2009-06-01 14 views
1

Update 3 (zuerst lesen):Django: ein generisches (content_type) Feldes mit einem realen Objekt Einstellung setzt es auf None

Ja, dies wurde durch das Objekt „Profil“ verursacht nicht gespeichert wurde. Für diejenigen, die die gleichen Symptome haben, lautet die Moral "Wenn ein ForeignKey-Feld auf" None "gesetzt wird, wenn Sie ihm ein reales Objekt zuweisen, liegt das wahrscheinlich daran, dass diese anderen Objekte nicht gespeichert wurden."

Auch wenn Sie 100% sicher sind, dass es gespeichert wurde, klicken Sie hier ;-)


Hallo,

Ich verwende content_type/generic Fremdschlüssel in einer Klasse in Django.

Die Linie eine Instanz der Klasse zu erstellen, ist in etwa so:

tag = SecurityTag(name='name',agent=an_agent,resource=a_resource,interface=an_interface) 

Wo beiden Mittel und Ressourcen sind content_type Felder aus.

Meistens funktioniert das so, wie ich es erwarte und erschafft das passende Objekt. Aber ich habe einen speziellen Fall, in dem ich diese Zeile anrufe, um einen SecurityTag zu erstellen, aber der Wert des Agentenfelds scheint am Ende wie Kein zu enden.

Jetzt, in diesem speziellen Fall, teste ich in der vorhergehenden Zeile, dass der Wert von an_agent ein vorhandenes, gespeichertes Django.model-Objekt eines Agententyps enthält. Und es tut es.

Der resultierende SecurityTag-Datensatz wird jedoch mit None für dieses Feld ausgegeben.

Ich bin davon ziemlich verblüfft. Ich vermute, dass irgendwo in der Leitung etwas fehlschlägt, wenn der ORM versucht, die ID des Objekts in an_agent zu extrahieren, aber es wird weder eine Fehlermeldung noch eine Exception ausgelöst. Ich habe überprüft, dass das Objekt an_agent gespeichert ist und einen Wert in seinem ID-Feld hat.

Wer hat so etwas gesehen? Oder haben Sie irgendwelche Ideen?

====

Update: 10 Tage später genau das gleiche Bug mich in einen neuen Kontext wieder zu beißen ist gekommen:

einige Code Hier ist die die „Sicherheitsetikett“ Objekt beschreibt, das ist im Grunde eine Abbildung zwischen

a) einer Art von permission-Rolle (bekannt als "Agent" in unserem System), das eine generische content_type ist,

b) eine Ressource, die auch eine generische content_type ist, (und Im aktuellen Problem wird ein Pin vergeben ax "Profil"),

und c) eine "Schnittstelle" (was im Grunde eine Art von Zugriff ist ... z. „Sichtbarer“ oder „Editierbare“, die nur eine Zeichenfolge ist)

class SecurityTag(models.Model) : 
    name = models.CharField(max_length='50') 
    agent_content_type = models.ForeignKey(ContentType,related_name='security_tag_agent') 
    agent_object_id = models.PositiveIntegerField() 
    agent = generic.GenericForeignKey('agent_content_type', 'agent_object_id') 

    interface = models.CharField(max_length='50') 

    resource_content_type = models.ForeignKey(ContentType,related_name='security_tag_resource') 
    resource_object_id = models.PositiveIntegerField() 
    resource = generic.GenericForeignKey('resource_content_type', 'resource_object_id') 

Zu einem bestimmten Zeitpunkt später, ich dies tun:

print "before %s, %s" % (self.resource,self.agent) 
t = SecurityTag(name=self.tag_name,agent=self.agent,resource=self.resource,interface=self.interface_id) 
print "after %s, %s, %s, %s" % (t.resource,t.resource_content_type,type(t.resource),t.resource_object_id) 

Das Ergebnis davon ist, dass vor, die „Ressource“ Variable bedeutet Referenz ein Profil, aber nach ...

before phil, TgGroup object 
after None, profile, <type 'NoneType'>, None 

Mit anderen Worten, während der Wert von t.resource_content_type auf „Profil“ gesetzt wurde, ist alles andere Keine. In meiner vorherigen Begegnung mit diesem Problem habe ich es "gelöst", indem ich das Ding, das ich dem generischen Typ zuweisen wollte, neu lade. Ich fange an mich zu fragen, ob dies eine Art von ORM-Cache-Problem ist ... ist die Variable "self.resource" mit einem netten Proxy-Objekt statt der realen Sache?

Eine Möglichkeit ist, dass das Profil nicht gespeichert wurde. Dieser Code wird jedoch als Ergebnis eines after_save-Signals für das Profil aufgerufen. (Es setzt Standardberechtigungen), könnte es also sein, dass die Profilspeicherung nicht festgeschrieben wurde oder so?

Update 2: unter folgenden Matthew Vorschlag, fügte ich

print self.resource._get_pk_value() and self.resource.id 

das Profil der Luft gejagt hat sagen _get_pk_value nicht hat()

+0

Dies ist eindeutig ein Fehler, nicht beabsichtigtes Verhalten, und um ehrlich zu sein, es ist viel eher ein Fehler in Ihrem Code als in Django (obwohl letzteres sicherlich möglich ist). Daher denke ich, dass nützliche Antworten schwer zu bekommen sind, wenn Sie nicht den gesamten relevanten Code veröffentlichen (oder mit einem Pastebin-Dump verknüpfen) können. –

+0

Können Sie die Datei "self.resource._get_pk_value()" und "self.resource.id" zur Druckanweisung "before" hinzufügen und die Frage mit den Ergebnissen bearbeiten? Wenn der erste zurückkehrt, kann ich aus irgendeinem Grund nicht verstehen, warum dies geschieht. –

+0

Brilliant! Matthew, du hattest Recht. Das zeigte, dass das Objekt nicht wirklich gespeichert wurde. Was mich wiederum auf einen Fehler hinwies. Wenn Sie eine Antwort geben, werde ich Ihnen den Bonus gewähren. – interstar

Antwort

4

So habe ich bemerkt, wie man den Django-Code passiert: Wenn Sie eine neue Instanz eines Modellobjekts über einen Konstruktor erstellen, wird eine Vor-Initialisierungsfunktion (via Signale) für generische Objektreferenzen aufgerufen.

Anstatt das übergebene Objekt direkt zu speichern, werden der Typ und der Primärschlüssel gespeichert.

Wenn Ihr Objekt persistent ist und eine ID hat, funktioniert das gut, denn wenn Sie das Feld zu einem späteren Zeitpunkt abrufen, ruft es es aus der Datenbank ab.

Wenn Ihr Objekt jedoch keine ID hat, gibt der Abrufcode nichts zurück und der Getter gibt None zurück!

Sie können den Code in django.contrib.contenttypes.generic.GenericForeignKey, in den instance_pre_init und Funktionen sehen.

1

Das ist wirklich nicht meine Frage beantworten oder meine Neugier befriedigen aber es scheint zu funktionieren, wenn ich das Objekt an_agent sofort aus der Datenbank herausziehe, bevor ich versuche, es im SecurityTag-Konstruktor zu verwenden.

Zuvor übergab ich eine Kopie, die zuvor mit get_or_create erstellt wurde. Ist diese alte Instanz irgendwie veraltet oder nicht mehr aktuell?

+0

Hast du sichergestellt, dass die alte Instanz gespeichert wurde, um ihre Freunde zu füllen und sie herumzureichen? –

Verwandte Themen