2017-05-15 8 views
0

Ich erweitere Django (v1.9) integrierte Benutzermodell mit Player-Klasse, um einige zusätzliche Eigenschaften hinzuzufügen.Erweitern Django Benutzermodell - Populationsfehler

class Player(models.Model): 
    TIMEZONES=() 
    user = models.OneToOneField(User, on_delete=models.CASCADE) 
    ... (player-specific properties here) 
    time_zone = models.CharField(max_length=255, choices=PRETTY_TIMEZONE_CHOICES, blank=True, null=True,) 

Wenn Benutzer von Django Admin-Panel zu schaffen, ich brauche nicht immer Spieler zu schaffen, so dass manchmal nur Benutzer erstellt werden. Daher stimmen die Player- und Benutzer-IDs nicht genau überein. Es stellte sich heraus, dass dies zu einem Problem führt, wenn ModelForms von Modellen, die verknüpft sind Spieler, wie diese bevölkern:

class City(models.Model): 
    player = models.ForeignKey(Player, on_delete=models.CASCADE) 
    name = models.CharField(max_length = 100) 
    x_coord = models.SmallIntegerField() 
    y_coord = models.SmallIntegerField() 
    region = models.CharField(max_length = 100) 
    def __unicode__(self): 
     return str(self.player) + "-" + str(self.name) 
    class Meta: 
     db_table = 'cities' 

class CityForm(ModelForm): 
    class Meta: 
     model = City 
     fields = (
      'name', 
      'player', 
      'x_coord', 
      'y_coord', 
      'region') 

Diese Modelform verwendet wird, wenn die Schaffung einer neuen Stadt. Wenn die Benutzer-ID und die Spieler-ID übereinstimmen, gibt es kein Problem, die Spieler-ID wird in das Formular eingetragen und die Stadt wird erfolgreich erstellt. Wenn die Benutzer-ID und die Player-ID unterschiedlich sind, wird die Player-ID im Formular nicht ausgefüllt, das Formular wird nicht validiert und die Erstellung der Städte schlägt fehl.

Ich habe kein Problem bekommt Spielernummer von request.user, und ich konnte die Spieler-ID, bevor die Validierung nach dem Aufstehen POST-Daten reparieren. Ich habe auch einen Post-Speicher-Hook hinzugefügt, so dass Player immer erstellt wird, so dass die IDs immer übereinstimmen. Aber es scheint, dass Formular mit Spieler-ID an erster Stelle gefüllt werden sollte, da Benutzerdaten zugänglich sind und es eine Eins-zu-eins-Beziehung ist.

Was fehlt mir hier?

Antwort

0

Was Ihnen fehlt, ist, dass, wenn Sie eine Modelform instanziiert eine neue Zeile zu erstellen, die zu einem gewissen bestehenden Objekt verwandt ist, hat Django keine Möglichkeit, die ID des zugehörigen Objekts zu wissen. Du musst es irgendwie erzählen.

Eine Möglichkeit, das zu tun ist, wenn Sie das Formular in Reaktion auf eine GET werden angezeigt wird, verwenden Sie das initial Argument der Form Konstruktor:

myform = MyModelFormClass(None, initial={ 'myfkfield': myrelatedobject.pk }) 

Nun ist die Form-Klasse weiß, was Wert-fill Pre Wenn das Formular gerendert wird und wenn das Formular gepostet wird, wird dieses Feld mit ihm gepostet.

Die andere Möglichkeit wäre es, wegzulassen, die die Beziehung Feld aus dem Formular überhaupt zu tun, ist es dann später füllen, bevor Sie das commit Argument der Form speichern Methode speichern, unter Verwendung von:

myform = MyModelFormClass(request.POST) 
# this causes form values to be filled into the instance without actually 
# writing to the database yet. 
myinstance = myform.save(commit=False) 
myinstance.myfkfield = myrelatedobject 
# now really write to database 
myinstance.save() 

Hinweis dass dies für einen Einsatz wäre. Für Updates müssen Sie das vorhandene Objekt zu Ihrem Modelform Konstruktor liefern, wie folgt aus:

myinstance = MyModel.objects.get(pk=self.kwargs.pk) 
myform = MyModelFormClass(request.POST, instance=myinstance) 

Ohne Beispiel Modelform nicht weiß, welche Zeile in der Datenbank ist zu aktualisieren. Du würdest denken, dass dies alles im HTML vorhanden ist, also sollte es nicht notwendig sein .. aber so funktioniert Django nicht. Sie müssen das Objekt aus der Datenbank abrufen und zusammen mit den Daten request.POST an den ModelForm-Konstruktor übergeben. Wenn Sie dann myform.save() aufrufen, wird das Formular validiert, seine Daten mit dem vorhandenen Objekt zusammengeführt und das Objekt gespeichert. Die Verwendung von commit=False führt dazu, dass der letzte dieser drei Schritte zurückgestellt wird, sodass Sie Änderungen oder Überprüfungen an der aktualisierten Instanz vornehmen können, bevor sie tatsächlich gespeichert werden.

+0

ich irgendwelche Annahmen über IDs nicht machen war, ganz im Gegenteil, ich war es für selbstverständlich, dass die Spieler-ID würde in der Modelform korrekt ausgefüllt werden. Das Problem besteht nicht in mehreren Stadt-IDs, sondern in folgendem: Wenn der Benutzer eine neue Stadt erstellt, wird die Spieler-ID des Nutzers nicht in das Stadterstellungsformular eingetragen. – seadeer

+0

Ahh ich sehe, Sie haben versucht, das Problem zu umgehen, werde ich meine Antwort –

+0

Ok, so habe ich meine Antwort geändert, hoffentlich ist dies hilfreich. Wenn du es immer noch nicht verstehst, kann ich versuchen es zu klären. –

Verwandte Themen