5

Lasst uns sagen, dass wir eine App namens Schrank haben und es hat einige Modelle:Django: Create mit Pre-besiedelten und nicht bearbeitet werden Felder durch Query-String angegeben

# closet.models.py 
class Outfit(models.Model): 
    shirt = models.ForeignKey(Shirt) 
    pants = models.ForeignKey(Trouser) 

class Shirt(models.Model): 
    desc = models.TextField() 

class Trouser(models.Model): 
    desc = models.TextField() 

class Footwear(models.Model): 
    desc = models.TextField 

Die Verwendung generischer Detailansicht ist es einfach die URL conf zu machen Einzelheiten zu jedem dieser:

#urls.py 
urlpatterns = patterns('', 
    url(r'^closet/outfit/(?P<pk>\d+)$',  DetailView(model=Outfit),  name='outfit_detail'), 
    url(r'^closet/shirt/(?P<pk>\d+)$',   DetailView(model=Shirt),  name='shirt_detail'), 
    url(r'^closet/trouser/(?P<pk>\d+)$',  DetailView(model=Trouser),  name='trouser_detail'), 
    url(r'^closet/footwear/(?P<pk>\d+)$',  DetailView(model=Footwear),  name='footwear_detail'), 
) 

Was ich als nächstes tun würde, ist die Ansichten definieren, die ein neues Objekt jeder Art schaffen. Ich möchte dies mit einer erweiterten Version von CreateView tun, die in der Lage sein wird, Daten auf vorab ausgefüllten Feldern zu handhaben.

Insbesondere möchte ich folgendes Verhalten:

  1. Wenn ich /closet/outfit/new besuche ich einen Standard ModelForm für das Outfit Modell mit alles leer und alles bearbeitbar erhalten möchten.
  2. Wenn ich /closet/outfit/new/?shirt=1 besuche, möchte ich alle Felder sehen, die ich in Fall 1) gesehen habe, aber ich möchte, dass das Hemdfeld mit dem T-Shirt mit pk = 1 ausgefüllt wird. Außerdem möchte ich, dass das Feld "Shirt" als nicht bearbeitbar angezeigt wird. Wenn das Formular eingereicht wird und als ungültig erachtet wird, möchte ich, wenn das Formular erneut angezeigt wird, dass das Feld "Shirt" weiterhin nicht bearbeitet werden kann.
  3. Wenn ich /closet/outfit/new/?shirt=1&trouser=2 besuche, möchte ich alle Felder sehen, die ich in Fall 1) gesehen habe, aber jetzt sollten sowohl die Hemd- als auch die Hosenfelder vorbearbeitet und uneditable sein. (Das heißt, nur das Feld footwear sollte bearbeitbar sein.)

Ist das im Allgemeinen möglich? I.e. Kann der Querystring die Struktur der angezeigten Form auf diese Weise verändern? Ich möchte dies DRYestmöglich erreichen. Mein Bauchgefühl sagt mir, dass dies mit klassenbasierten Ansichten machbar sein sollte und vielleicht model_form_factory beinhalten würde, aber ich kann die Logik nicht direkt in meinen Kopf bekommen. Insbesondere war ich nicht sicher, ob es möglich war, dass die klassenbasierte Ansicht auf die request.REQUEST (d. H. Die request.POST oder request.GET Parameter) zu der Zeit zugreifen kann, zu der die ModelForm konstruiert wird.

Vielleicht ist es nur möglich, wenn ich verschiedene querystring Schlüsselwörter für die gesperrten Felder verwenden. I.e. vielleicht muss die URL sein: /closet/outfit/new/?lock_shirt=1 und /closet/outfit/new?lock_shirt=1&lock_trouser=2. Wenn es so gemacht wird, würde der POST Handler sowohl eine Liste von gesperrten Feldern (für die Zwecke der Formularanzeige im Browser) als auch eine reguläre Liste aller Modellfelder für den Zweck der tatsächlichen Erstellung des Objekts übergeben.

Warum will ich dies: In der Vorlage für die footwear_detail würde ich einen Tag wie

<a href="{% url outfit_new %}?footwear={{object.pk}}>Click to create a new outfit with this footwear!</a> 

Im Allgemeinen machen zu können, will, wäre es sehr nützlich sein, um Links zu Formen machen deren "Struktur" (nicht nur Werte) sich abhängig von der übergebenen Querystring ändert.


Als Reaktion auf den großen Vorschlag von Berislav Lopac:

So voran ging ich und tat

class CreateViewWithPredefined(CreateView): 
    def get_initial(self): 
    return self.request.GET 

Dies bringt mich zu 90% von dem, was ich brauche. Aber lassen Sie mich die Situation ein bisschen mehr konkretisieren.Angenommen, ich füge dem Outfit-Modell zwei Felder hinzu: headgear = models.ManyToManyField('headgear') und awesomeness_rating = models.FloatField().

Zwei Probleme:

  1. Wenn ich besuchen /closet/outfit/new/?awesomeness_rating=10 dann meine Form mit [u'10'] vorge füllt-statt nur mit 10 füllen. Gibt es einen Filter, den ich in meiner Vorlage verwenden sollte, oder ein bisschen Verarbeitung, die ich meiner Ansicht hinzufügen kann, um die Formatierung geeigneter zu machen?
  2. Wenn ich ein paar Kopfbedeckungen vorschreiben möchte, welches ist das richtige Format, um das, was sich wie eine Python-Liste anfühlt, durch einen Abfrage-String zu übergeben? I.e. sollte ich tun /closet/outfit/new/?headgear=1,2,3? Wenn ja, wird Django dann richtig erkennen, dass ich die 3 Kopfbedeckungen mit diesen IDs vorwählen möchte?

Continuing daran arbeiten ...

class CreateViewWithPredefined(CreateView): 
    def get_initial(self): 
     initial = super(CreateView, self).get_initial() 
     for k, v in self.request.GET.iterlists(): 
      if len(v) > 1: 
       initial.update({ k : v }) 
      else: 
       initial.update({ k : v[0] }) 
     return initial 

Dies scheint mit einer Klappe schlagen zwei Vögel zu töten: numerische Daten von Unicode in numerische dazu gezwungen wird, und es flacht Listen, wenn möglich (wie beabsichtigt). Muss überprüft werden, ob dies bei mehrwertigen Feldern funktioniert.

Antwort

4

Es ist self.request, irgendwo in einem CBV. :-)

OK, lassen Sie mich diese Antwort umfassender machen. Im Grunde, was Sie wollen, ist die get_initial Methode, die von der FormMixin beigetragen wird. Überschreiben Sie es, um die Anfangswerte für Ihre Felder zu füllen.

+0

Dies ist ein guter erster Schritt. Ich habe zwei Fragen, wie das zu implementieren ist. Bitte beachten Sie die Änderungen am ursprünglichen Beitrag oben. Ich denke, für meine Zwecke werde ich diesen Weg gehen, da er den Kernpunkt erreicht. Aber in dem Maße, wie sich andere für das ursprüngliche Problem interessieren könnten: Hat jemand eine Lösung für die ursprüngliche Frage ... anstatt das Formular nur mit Anfangsdaten zu füllen, gibt es eine Möglichkeit, die vorgefüllten Felder tatsächlich anzuzeigen wie gesperrt? – 8one6

+0

Eine Möglichkeit besteht darin, dem Eingabeelement das 'readonly'-Attribut hinzuzufügen, möglicherweise in der' get_form'-Methode der Ansicht. Sie könnten die 'request.GET'-Felder verwenden (oder besser noch Ihr' get_initial' verwenden, um Doppelarbeit zu vermeiden) und das Widget jedes Felds ändern, das dort einen Wert hat. –

+0

Danke. Ich bin ziemlich neu und habe immer noch Probleme mit der Unicode-Formatierung. Ich verstehe, dass alle Einträge in einem QueryDict, die ich von "request.GET" bekomme, als Unicode-Strings formatiert werden. Gibt es eine allgemeine Möglichkeit, einen Unicode in seinen nativen Python-Datentyp zu konvertieren? Also, wenn ich '/ Schrank/Outfit/neu /? Awesomeness_level = 10' will ich sicherstellen, dass das Feld mit 10 anstelle von [u'10] vorformuliert ... – 8one6

Verwandte Themen