2016-12-07 4 views
1

Ich versuche, ein Objekt zu generieren, das Werte in einer Standardeinheit gespeichert, aber in verschiedenen Einheiten basierend auf den Einstellungen für das Projekt angezeigt werden kann. Unten ist ein Beispiel, wo ich die Temperatur eines Raumes speichern kann. Ich möchte, dass der Datenbankwert zur Vereinfachung der Berechnungen in Kelvin ist, möchte aber, dass die Benutzer F oder C anzeigen oder eingeben können, wie es das Projekt erfordert.Django ändern Modelldaten vor dem Rendern ModelForm

Das Modell kann die Werte aus einem Formular übernehmen und beim Speichern in Kelvin konvertieren. Ich weiß, dass dies in der Form gemacht werden kann, aber ich habe es hier für andere Dateneingabemethoden. Eine gestreifte abgespeckte Version des Modells ist wie folgt:

class Room(models.Model): 
    name    = models.CharField(max_length=255)    
    temperature   = models.FloatField(default=293.15) 

    def save(self, *args, **kwargs): 
     self.temperature = convert.temperature(self.temperature, 
      from_unit=self.plant.temperature_scale) 
     super(Room, self).save(*args, **kwargs) 

ich eine Modelform in Create und UpdateView verwenden erstellt. Ich brauchte das ModelForm, um das queryset für andere Felder zu begrenzen (das funktioniert gut). Hier konnte ich das Temperaturfeld auf die gewünschten Einheiten für ein neues Objekt in Create konvertieren, aber ich kann nicht scheinen, den Weg zu finden dies für einen bestehenden Datensatz

class RoomForm(ModelForm): 
    def __init__(self, plant, *args, **kwargs): 
     super (RoomForm,self).__init__(*args,**kwargs) 

     self.fields['temperature'].initial = convert.temperature(
      value=self.fields['temperature'].initial, 
      from_unit='K', 
      to_unit=self.fields['unit'].queryset[0].plant.temperature_scale) 

     self.instance.temperature = convert.temperature(
      value=self.instance.temperature, 
      from_unit='K', 
      to_unit=self.fields['unit'].queryset[0].plant.temperature_scale) 

    class Meta: 
     model = Room 
     fields = ['name', 'temperature'] 

Für eine gute Maßnahme ziehen aus, hier sind die Ansichten, die diese Form aufrufen.

class NewRoom(CreateView): 
    model = Room 
    form_class = RoomForm 

    def get_form_kwargs(self, **kwargs): 
     form_kwargs = super(NewRoom, self).get_form_kwargs(**kwargs) 
     form_kwargs["plant"] = Plant.objects.get(slug=self.kwargs['plant']) 
     return form_kwargs  

class EditRoom(UpdateView): 
    model = Room 
    form_class = RoomForm 
    template_name_suffix = "_update_form" 

    def get_form_kwargs(self, **kwargs): 
     form_kwargs = super(EditRoom, self).get_form_kwargs(**kwargs) 
     form_kwargs["plant"] = Plant.objects.filter(slug=self.kwargs['plant']) 
     return form_kwargs 

In den Vorlagen (nicht Formulare) verwende ich dies, um die Temperatur korrekt anzuzeigen.

{{ room.temperature|convert_temperature:room.plant.temperature_scale }} 

Ich nehme an, ich brauche das Teil zu ergänzen, wo die Modelform die Daten aus dem Datenbank-Datensatz importiert, aber ich konnte nicht erkennen, wo diese im Code django.forms Quelle passiert.

Ich habe versucht, diese manuell in der Shell-Aufruf

>>> from rooms.models import * 
>>> from rooms.forms import * 
>>> room = Room.objects.first() 
>>> form = RoomForm(room.plant, instance=room) 
>>> form.instance.temperature 
20.0 
>>> form.as_p() 

und das gerenderte Form wird mit dem falschen Wert für die Temperatur wie folgt

<p> 
    <label for="id_name">Name: 
    </label> 
    <input id="id_name" maxlength="255" name="name" type="text" value="Testing" 
     required /> 
</p>\n 
<p> 
    <label for="id_temperature">Temperature: 
    </label> 
    <input id="id_temperature" name="temperature" 
     step="any" type="number" value="293.15" required /> 
</p>\n 

Ich verwende 1.10.3 Django-Version, wenn es möglich, das ist ein Fehler.

+0

Hallo Brian, hast du convert.temperature selbst geschrieben, oder gibt es ein fertiges Paket, das ich vermisse? Ich möchte mich an Konventionen halten, gibt es irgendwelche :) – gabn88

+0

Ich schrieb mein eigenes Convert-Modul. Ich habe eine Reihe von Verweisen auf Pint gesehen, aber ich fand die Syntax verwirrend. –

Antwort

0

Während Lucasnadalutti mich an der richtigen Stelle lassen, hat es nicht geschafft, den Trick zu tun. Überschreibe die Instanz, die an die ModelForm.__init__ übergeben wurde, und rufe sie nach der Änderung erneut auf.

class RoomForm(ModelForm): 

    def __init__(self, plant, *args, **kwargs): 
     super(RoomForm, self).__init__(*args,**kwargs) 

     self.instance.temperature = convert.temperature(
      value=self.instance.temperature, 
      from_unit='K', to_unit=self.fields['unit'].queryset[0].plant.temperature_scale) 

     # Override instance passed to __init__ and call super again 
     kwargs['instance'] = self.instance 
     super(RoomForm, self).__init__(*args, **kwargs) 

    class Meta: 
     model = Room 
     fields = ['name', 'temperature'] 
1

Um Daten in Ihrem vorhandenen Datensatz vor dem Rendern zu ändern, tun Sie es einfach in self.instance nach dem Aufruf der Eltern __init__.

def __init__(self, plant, *args, **kwargs): 
    super(RoomForm,self).__init__(*args,**kwargs) 
    self.instance.temperature = # ... 
+0

hat meine aktuellen 'self.fields ['temperature'] auskommentiert. Initial =' und 'self.instance.temperature = 'am Ende von' __init__' hinzugefügt und es scheint nicht so zu sein. (Da beide Versionen drin sind, hält mich, wo ich war) –

+0

Ist 'self.instance' Ihnen das richtige Objekt? – lucasnadalutti

+0

Das Einfügen einer Debugging-Anweisung in meinen Code, um den Wert im Terminal auszudrucken, zeigt die richtige Antwort, aber es zeigt sich nicht wie gewünscht auf der Seite (auch nach dem Neustart des Servers). Durch das Hinzufügen von 'print (self.instance)' wird der Name des Raums im Terminal gedruckt. –