2016-08-09 4 views
2

Ich habe ein Modell für meine Legacy-Datenbank erstellt von manage.py inspectdb, die auf die Datenbank namens "edlserver" in Einstellungen, eine von vielen Datenbanken für das Projekt verwendet. Ich kann das Datenbanklayout nicht ändern.Django vergisst. Using Datenbank zum Auflösen von Fremdschlüssel

Es hat die folgenden Klassen (unter anderem irrelevanten):

One für Logging-Einträge.

class Logs(models.Model): 
    time = models.DateTimeField() 
    job = models.ForeignKey(Jobs, models.DO_NOTHING, db_column='id_job') 
    msg = models.TextField() 

    class Meta: 
    managed = False 
    db_table = 'logs' 

Ein weiterer für Jobs (dass die Job Feldverweise)

class Jobs(models.Model): 
    job_type = models.ForeignKey(JobTypes, models.DO_NOTHING, db_column='id_job_type') 
    time_start = models.DateTimeField() 
    time_end = models.DateTimeField(blank=True, null=True) 
    pid = models.IntegerField(blank=True, null=True) 
    title = models.CharField(max_length=255) 

    class Meta: 
    managed = False 
    db_table = 'jobs' 

und ein anderer für JobTypes.

class JobTypes(models.Model): 
    name = models.CharField(max_length=255) 
    max_processes = models.IntegerField() 

    class Meta: 
    managed = False 
    db_table = 'job_types' 

Der Blick für django-Rest-Rahmen wie dieser Es verwendet den Filter

class EDLLogList(generics.ListAPIView): 
    serializer_class = EDLLogsSerializer 
    filter_backends = (filters.DjangoFilterBackend,) 
    filter_class = EDLLogsFilter  

    def get_queryset(self): 
    if not 'job_name' in self.request.GET: 
     raise ParameterRequired('job_name') 
    else: 
     return Logs.objects.all().using('edlserver') 

aussieht:

class EDLLogsFilter(filters.FilterSet): 
    time_start = django_filters.DateTimeFilter(name="time", lookup_type='gte') 
    time_end = django_filters.DateTimeFilter(name="time", lookup_type='lte') 
    job_name = django_filters.MethodFilter()  

    class Meta: 
    model = Logs 
    fields =() 

    def filter_job_name(self, queryset, job_name): 
    try: 
     q = queryset.filter(job__job_type__name=job_name)[:10000] 
    except: 
     raise InternalError() 

    if len(q) < 1 and 
     len(JobTypes.objects.all().using('edlserver').filter(name=job_name)) < 1: 
     raise InvalidParameter(job_name, 'job_name') 
    else: 
     return q 

und den Serializer: Problem

class EDLLogsSerializer(serializers.HyperlinkedModelSerializer): 
    time = serializers.DateTimeField() 
    job_name = serializers.SerializerMethodField() 
    message = serializers.SerializerMethodField() 

    class Meta: 
    model = Logs 
    fields = ('job_name','time', 'message') 

    def get_job_name(self, obj): 
    return obj['id_job__id_job_type__name'] 

    def get_message(self, obj): 
    return obj.msg 

ist Ich bekomme eine TypeError: 'Logs' object is not subscriptable i n get_job_name() im Serializer, kommt aus dem psycopg2-Modul - die Datenbank ist jedoch eine MySQL-Datenbank. Die Tatsache, dass die erste Abfrage während des Debugging ein Abfrage-Set mit len> 0 hat, zeigt, dass das Modell in Ordnung ist, und django verwendet das MySQL-Backend zum Abrufen der Daten. Bei der Auflösung des Fremdschlüssels geht etwas schief und die (ich glaube) Standarddatenbank wird verwendet, nämlich PostGreSQL.

Ist das ein Fehler?

Wenn nicht, was kann ich tun? Ich dachte über einen Router nach, der ein Meta-Feld auflösen würde. Das würde viele Änderungen an anderen Modellen bedeuten, also möchte ich das nicht tun. Irgendwelche Ideen?

EDIT: Einstellungen für Datenbanken

'default': { 
    'ENGINE': 'django.db.backends.postgresql_psycopg2', 
    'NAME': 'pic', 
    'USER' : 'pic-5437', 
    'PASSWORD' : '',  
    'HOST' : 'host1.url.com', 
    'PORT' : '5432'  
}, 
'...' : { 
    ... 
}, 
'edlserver': { 
    'ENGINE': 'django.db.backends.mysql', 
    'HOST': 'host2.url.com', 
    'NAME': 'edl', 
    'USER': 'edl_ro', 
    'PASSWORD': '', 
} 
+0

bitte aktualisieren Sie Ihre Frage mit dem Datenbanken Abschnitt Ihrer settings.py und bitte die unnötigen Modelle auslassen – e4c5

+0

Die Modelle werden alle benötigt, da sie die Fremdschlüsselbeziehungen zeigen. Ich habe in den Datenbanken bearbeitet. –

Antwort

2

Fremdschlüssel fügen dem Modell, das selbst eine Modellinstanz ist, ein Attribut hinzu.Um die komplette Beziehung von Logs zu JobType zu folgen, einfach Attribute Lookups verwenden:

def get_job_name(self, obj): 
    return obj.job.job_type.name 

Dies würde der normale Anwendungsfall sein. Wenn mehrere Datenbanken verwendet werden und django verwendet die falsche Datenbank, während die Fremdschlüssel zu lösen, kann es manuell durchgeführt werden:

return JobTypes.objects.all().using('edlserver').filter(id= 
    Jobs.objects.all().using('edlserver').filter(id= 
    obj.job_id)[0].job_type_id)[0].name 

Eine andere Möglichkeit wäre, ein Meta-Feld im Modell einzuführen, wie folgt aus:

import django.db.models.options as options 
options.DEFAULT_NAMES = options.DEFAULT_NAMES + ('in_db',) 

class MyModel(models.Model): 
    class Meta: 
    in_db = 'edlserver' 

Dann wird eine Datenbank-Router benötigt:

class DatabaseMetaRouter(object): 
def db_for_read(self, model, **hints): 
    """ 
    Route to the given in_db database in Meta 
    """ 
    if hasattr(model._meta, 'in_db'): 
     return model._meta.in_db 
    else: 
     return 'default' 

def db_for_write(self, model, **hints): 
    """ 
    Route to the given in_db database in Meta 
    """ 
    if hasattr(model._meta, 'in_db'): 
     return model._meta.in_db 
    else: 
     return 'default' 

def allow_relation(self, obj1, obj2, **hints): 
    """ 
    Always allow 
    """ 
    return True 

def allow_migrate(self, db, app_label, model_name=None, **hints): 
    """ 
    Always allow 
    """ 
    return True 
+0

Okay. Das erzeugt immer noch genau den gleichen Fehler: 'psycopg2.ProgrammingError: relation" jobs "existiert nicht LINE 1: ... bs". "Time_end", "jobs." "Pid", "jobs". "Title" FROM "jobs" WHE ... '. Wenn ich jedoch die Beziehung manuell mit' .using ('edlserver') befolge, bekomme ich den richtigen Wert. "Also schlussfolgern wir, dass es wirklich django ist, nicht zu wissen, welche Datenbank zu verwenden ist -Wenn ich es manuell mache? –

1

Das Problem ist, dass hier obj eine Instanz von Logs

def get_job_name(self, obj): 
    return obj['id_job__id_job_type__name'] 

Django Modelle aussehen wie Wörterbücher, riechen wie Wörterbücher, aber sie sind nicht Wörterbücher. Die korrekte Verwendung ist:

return obj.job.job_type.name 

Ich empfehle Ihnen, eine django Shell öffnen, ein einzelnes statt Logs laden und die Hilfe() Befehl und experimentieren Sie mit den Pfaden verwenden.

Für das zweite Problem wurde die falsche Datenbank für die Abfragen verwendet. Sie müssen entweder database router definieren oder in Ihren Abfragen using() hinzufügen.

+0

Ich habe es gerade ausprobiert. 'AttributeError: Das Objekt 'Logs' hat kein Attribut 'id_job__id_job_type__name'' ist das Ergebnis. Ich habe auch 'return obj.job.job_type.name' versucht, was zu einem' psycopg2.ProgrammingError: relation "jobs" nicht existiert LINE 1: ... bs "." Time_end "," jobs. " pid "," jobs "." title "FROM" jobs "WHE ...". Ich habe die Punktnotation an einer anderen Stelle im Projekt, wo sie für das Auth-Modell (das in der Standarddatenbank ist) funktioniert. –

+0

Ich habe gewählt +1. Aber ich bin auch unten gewählt. Entschuldigung. Ich bin wirklich froh, dass Sie versuchen zu helfen. –

+0

@ e4c5 Nehmen Sie nicht an. Ich downvoted, weil Ihre Antwort falsch ist und das OP auf die falsche Fährte setzt. Die folgenden Beziehungen für Modellinstanzen verwenden einfachen Attributzugriff, nur Abfrageabfragen verwenden die doppelte Unterstreichungssyntax. – knbk

Verwandte Themen