2012-04-10 7 views
1

Lassen Sie uns sagen, ich habe diese Modelle:Django 1.4: ein Feld in einem Fremdschlüssel Objekt (null = True) Erhalten, erhalten keine oder Feldwert

class A(models.Model): 
    name = models.CharField(max_length=32) 
    b = models.ForeignKey("B", null=True) 
    def __unicode__(self): 
     return self.name 

class B(models.Model): 
    name = models.CharField(max_length=32) 
    def __unicode__(self): 
     return self.name 

Und diese Ansicht:

def DisplayIt(request): 
    html = "" 
    for a in A.objects.all(): 
     html += "<input type='text' value='" + a.b.name + "' />" 

Dies funktioniert gut, solange jedes A einen Verweis auf ein B in Feld b hat. Aber ich habe null = True auf dem Referenzfeld b. Wenn b None ist, wird eine Ausnahme ausgelöst, dass NoneType keinen Funktionsnamen hat, was vollständig erwartet wird.

Natürlich, ich kann dies tun:

def DisplayIt(request): 
    somestring = "" 
    for a in A.objects.all(): 
     if a.b is not None: 
      somestring += a.b.name 

ABER, ich will nicht, dies zu tun, wenn ich nicht haben. Also, gibt es eine Möglichkeit, b.name oder None zu erhalten, wenn b None ist, OHNE eine if a.b is not None: in jede Schleife zu setzen? Mein Beispiel aus der realen Welt ist viel komplexer, und ich erstelle ein temporäres Objekt zur Anzeige aus tatsächlichen Datenbankfeldern ... es genügt zu sagen, dass ich nicht alle diese if-Anweisungen hätte und nicht sicher war, ob es da ist war eine andere eingebaute Funktion, um dorthin zu gelangen. Ich könnte auch eine Klassenmethode erstellen, um jedes dieser fremden Felder zu erhalten, wenn sie existieren, oder leer, wenn sie das nicht tun, aber ich bin mir nicht sicher, ob das auch der beste Weg ist.

+0

Ich erwähnte dies in meiner Antwort, aber hören Sie auf, HTML in der Ansicht durch Verketten von Zeichenfolgen zu erstellen, und verwenden Sie die Vorlagenfunktion. –

Antwort

3

Lassen Sie die Datenbank das für Sie erledigen.

Verwenden Sie ein cross-relation filter alle A mit einem b mit name zu erhalten, die not null ist:

def DisplayIt(request): 
    somestring = "" 
    for a in A.objects.filter(b__name__isnull=False): 
     somestring += a.b.name 

dieses so zu tun, dass Dummy-Werte enthalten sind, wenn a.b None ist, verwenden Sie die folgenden Schritte aus:

def DisplayIt(request): 
    somestring = "" 
    for a in A.objects.filter(b__name__isnull=False): 
     somestring += a.b.name 
    for a in A.objects.filter(b__name__isnull=True): 
     somestring += "dummy value for missing b.name" 



Auch, als eine Randnotiz, machen Sie keine String-Verkettung auf diese Weise - es ist horribly inefficient, da Python-Strings nicht veränderbar sind. Hier finden Sie viel besser:

def DisplayIt(request): 
    stringparts = [] 
    for a in A.objects.filter(b__name__isnull=False): 
     stringparts.append(a.b.name) 
    for a in A.objects.filter(b__name__isnull=True): 
     stringparts.append("dummy value for missing b.name") 
    ''.join(stringparts) 



Zweite Seite Hinweis: Der obige Code wird eine Abfrage durchführen bei jeder Iteration der for-Schleife holen a.b. Das kann suuuuper langsam sein. Erwägen Sie die Verwendung von select_related, um alles auf einmal zu erfassen. Seien Sie vorsichtig, das kann auch langsam sein, wenn Ihre Indizes nicht korrekt eingerichtet sind. Nachdem ich dies aktiviert hatte, schnüffelte ich die Abfragen und spend some quality time with your query planner, um sicherzustellen, dass Sie keine unangenehmen nicht indizierten Suchvorgänge durchführen.

Revised Code:

def DisplayIt(request): 
    stringparts = [] 
    for a in A.objects.filter(b__name__isnull=False).select_related(): 
     stringparts.append(a.b.name) 
    for a in A.objects.filter(b__name__isnull=True).select_related(): 
     stringparts.append("dummy value for missing b.name") 
    ''.join(stringparts) 
+0

Danke für die Notiz über die Zeichenketten concats, ich habe tatsächlich eine riesige Menge von concats auf diese Weise, um eine HTML-Seite zu erstellen, also werde ich sehen, ob ich das ändern kann, um es effizienter zu machen. Was das isnull betrifft, muss ich es tatsächlich zurückgeben, None oder "" für a.b.name, auch wenn a.b None ist. Weißt du, wie das geht? – Furbeenator

+0

In der Datenbank sagen Sie, dass Sie eine Abfrage wünschen, die, wenn Entität A vom Typ A, die einen nullbaren Fremdschlüssel b enthält, zum Entitätstyp B gehört, wenn ab NULL ist und Sie dann als Teil von ersetzen möchten Abfrage, ab mit einem "leeren" Schein einer Entität vom Typ B? Entschuldigung - das ist ein schrecklich verwirrender Satz ... –

+0

Wenn das, was ich gerade gesagt habe, wahr ist, dann nein, es gibt keine Möglichkeit, das zu tun, außer jedes A in der for-Schleife zu überprüfen. Wenn Sie jedoch die Einfügung so ändern können, dass Sie, wenn b für ein gegebenes A fehlt, auf a.b auf ein Dummy/leeres B zeigen, dann können Sie loslegen. Ich glaube, Sie könnten dies einfach tun, indem Sie den Standardwert von A für b ändern, aber es würde eine Migration erfordern. –

3

Ihr Kommentar Gebäude aus, die sagt, dass Sie die Instanzen von A wollen, die keine B. haben können oder können Sie hacken kann, zu arbeiten, die in der Regel ist eine schreckliche Idee. Verwenden Sie den langatmigen Python-Weg, den Sie vermeiden möchten. Aber hier ist die schlecht Art und Weise zu tun, was Sie wollen:

a.__dict__.get('b',{'name':None}).name 

Dies nutzt die Tatsache, dass alle Attribute in einem dict Objekt auf der tatsächlichen Instanz des Objekts gespeichert werden.Sie verwenden einen Standard-Wörterbuch-Accessor get(), um b oder ein Wörterbuch zurückzugeben, das ein Attribut enthält, das Sie interessiert. Dies ist eine schreckliche Idee, aber da ist es.

Auch Django/Python ist nicht Old School PHP. Ich kann nicht glauben, wie oft ich dies in den letzten Wochen auf stackoverflow gesehen habe, aber ... STRINGS NICHT KONZENTRIEREN, UM HTML ZU PRODUZIEREN !! Dafür ist die Templating-Sprache zuständig. Benutze es. Hör auf, was du gerade machst. STOPPEN SIE ES STOP ES STOPPEN SIE ES. Verwenden Sie Vorlagen, versuchen Sie nicht, HTML in Ihren Ansichten zu schreiben. Es ist eine nachweisbare FALSCHE Sache, also hör auf. Hör einfach auf.

+0

LOL, in Ordnung, ich werde es durch Vorlagen tun. Danke für die Vorschläge und clevere Methode, die Methode .get() des Dictionays zu verwenden, um None als Standard zu erhalten. Ich werde das nicht benutzen, aber es ist gut, es zu sehen. Der Grund, warum ich html in meine Sicht stellte, ist, dass ich es einfach von jQuery ajax aus aufrufen und die Seite mit dem HTML-Code füllen kann, der in meiner Sicht erzeugt wurde. Was ist eine bessere Vorlage? Würden Sie vorschlagen, eine Ansicht zu erstellen, die eine Vorlage für jeden Ajax-getriebenen Abschnitt übergibt und die an mein xmlHttpRequest-Objekt zurückgegeben und an den Onpage-Abschnitt gesendet wird? – Furbeenator

+0

Absolut. Sie können Ihre Ansichten verwenden, um Teilvorlagen für Ihr JavaScript zurückzugeben oder eine vollständige HTML-Seite für Ihr JavaScript zurückzugeben. In jedem Fall. Die Templating-Sprache dient zum Erstellen von Strings, die für jede Anforderung zurückgegeben werden. –

+0

+ 1'd für die Warnung, keine Vorlagen zu verwenden ... Ich habe so darüber nachgedacht, wie ich das ORM dazu bringen kann, sich in das zu verwandeln, was er will, dass ich das total vermisst habe! –

Verwandte Themen