django klassenbasierte Ansichten mit Inline-Modell-Form oder formset
-
12-10-2019 - |
Frage
Ich habe die folgenden Modelle:
class Bill(models.Model):
date = models.DateTimeField(_("Date of bill"),null=True,blank=True)
class Item(models.Model):
name = models.CharField(_("Name"),max_length=100)
price = models.FloatField(_("Price"))
quantity = models.IntegerField(_("Quantity"))
bill = models.ForeignKey("Bill",verbose_name=_("Bill"),
related_name="billitem")
Ich weiß, dass dies möglich ist:
from django.forms.models import inlineformset_factory
inlineformset_factory(Bill, Item)
und diese dann über Standardansicht bearbeiten.
Nun ich habe mich gefragt, ob es eine Möglichkeit ist, die gleichen (was bedeutet: mit einem Inline zum Hinzufügen / Bearbeiten von Elementen, die zu einer Rechnung) zu erreichen, mit Klasse basierten Ansichten (nicht für den Admin- Schnittstelle).
Lösung
Das Wichtigste ist:
-
erzeugt
FormSet
s innerhalbforms.py
mitinlineformset_factory
:BookImageFormSet = inlineformset_factory(BookForm, BookImage, extra=2) BookPageFormSet = inlineformset_factory(BookForm, BookPage, extra=5)
-
ergab
FormSet
s innerhalb einerCreateView
Klasse inviews.py
:def get_context_data(self, **kwargs): context = super(BookCreateView, self).get_context_data(**kwargs) if self.request.POST: context['bookimage_form'] = BookImageFormSet(self.request.POST) context['bookpage_form'] = BookPageFormSet(self.request.POST) else: context['bookimage_form'] = BookImageFormSet() context['bookpage_form'] = BookPageFormSet() return context
-
Gebrauchte
form_valid
die Form und formset zu speichern:def form_valid(self, form): context = self.get_context_data() bookimage_form = context['bookimage_formset'] bookpage_form = context['bookpage_formset'] if bookimage_form.is_valid() and bookpage_form.is_valid(): self.object = form.save() bookimage_form.instance = self.object bookimage_form.save() bookpage_form.instance = self.object bookpage_form.save() return HttpResponseRedirect('thanks/') else: return self.render_to_response(self.get_context_data(form=form))
Andere Tipps
ich meine eigene Version nur hinzugefügt, nachdem einige dieser vorgefertigten CBVS Check-out. Ich speziell die Kontrolle über multiple formsets -> one parent
in einer einzigen Ansicht mit jeweils individuellen benötigten Funktionen speichern.
Ich stopfte im Grunde die FormSet Daten in eine get_named_formsets
Funktion Bindung, die durch get_context_data
und form_valid
genannt wird.
Es, überprüfe ich, ob alle Formularsätze gültig sind, und suche auch nach einem Verfahren, das hebt eine einfache alte formset.save()
auf einem pro formset Basis für individuelle Einsparung.
Die Vorlage macht Formularsätze über
{% with named_formsets.my_specific_formset as formset %}
{{ formset }}
{{ formset.management_form }}
{% endwith %}
Ich denke, ich werde dieses System regelmäßig werden.
class MyView(UpdateView): # FormView, CreateView, etc
def get_context_data(self, **kwargs):
ctx = super(MyView, self).get_context_data(**kwargs)
ctx['named_formsets'] = self.get_named_formsets()
return ctx
def get_named_formsets(self):
return {
'followup': FollowUpFormSet(self.request.POST or None, prefix='followup'),
'action': ActionFormSet(self.request.POST or None, prefix='action'),
}
def form_valid(self, form):
named_formsets = self.get_named_formsets()
if not all((x.is_valid() for x in named_formsets.values())):
return self.render_to_response(self.get_context_data(form=form))
self.object = form.save()
# for every formset, attempt to find a specific formset save function
# otherwise, just save.
for name, formset in named_formsets.items():
formset_save_func = getattr(self, 'formset_{0}_valid'.format(name), None)
if formset_save_func is not None:
formset_save_func(formset)
else:
formset.save()
return http.HttpResponseRedirect('')
def formset_followup_valid(self, formset):
"""
Hook for custom formset saving.. useful if you have multiple formsets
"""
followups = formset.save(commit=False) # self.save_formset(formset, contact)
for followup in followups:
followup.who = self.request.user
followup.contact = self.object
followup.save()
Sie sollten versuchen, django-extra-Ansichten . Suchen Sie nach CreateWithInlinesView
und UpdateWithInlinesView
.
I rot die generische Quellcode des 1,3-beta-1:
Der Code ist absolut nicht bereit für Listenbearbeitung oder gibt es einige schwarze Magie hier. Aber ich glaube, dass sie schnell umgesetzt werden kann.
Wenn Sie an der django.view.generic.edit aussehen (diese Unterstützung detaillierte Objektbearbeitung) Modul, wie es das django.view.generic.detail Modul verwenden.
ich denke, dass ein django.view.generic.list_edit Modul django.view.generic.list und einen Teil von django.view.generic.edit umgesetzt werden kann.
Ich habe einige Änderungen zur ursprünglichen Lösung zu lassen formset.is_valid () zu arbeiten:
if self.request.POST:
context['fs'] = MyInlineFS(self.request.POST, instance=self.object)
else:
context['fs'] = MyInlineFS(instance=self.object)
Der Code in Jordaniens Antwort nicht für mich arbeiten. Ich stellte über diese href="https://stackoverflow.com/questions/11198638/django-inline-formset-error/11199031">, die ich glaube, ich habe jetzt gelöst. Das erste Argument für inlineformset_factory sollte Buch sein, nicht Buchform.
Ich brauchte eine weitere Modifikation Jordaniens und speq Ansicht der get_context_data()
zu haben, um formset.non_form_errors
exist in der Vorlage Kontext zu machen.
...
if self.request.POST:
context['fs'] = MyInlineFS(self.request.POST, instance=self.object)
context['fs'].full_clean() # <-- new
else:
context['fs'] = MyInlineFS(instance=self.object)
return context