viste basate su classe django con il modello-forma o formset in linea
-
12-10-2019 - |
Domanda
Ho i seguenti modelli:
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")
So che questo è possibile:
from django.forms.models import inlineformset_factory
inlineformset_factory(Bill, Item)
e quindi elaborare questo tramite visualizzazione standard.
Ora mi chiedevo, se c'è un modo per ottenere gli stessi (che significa: utilizzando una linea per l'aggiunta / modifica di elementi appartenenti a un disegno di legge) vista utilizzando class basate (non per l'ammi- l'interfaccia).
Soluzione
Punti chiave è:
-
FormSet
s generati all'internoforms.py
utilizzandoinlineformset_factory
:BookImageFormSet = inlineformset_factory(BookForm, BookImage, extra=2) BookPageFormSet = inlineformset_factory(BookForm, BookPage, extra=5)
-
restituito i
FormSet
s all'interno di una classeCreateView
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
-
form_valid
usato per salvare la forma e formset: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))
Altri suggerimenti
Ho appena aggiunto la mia versione dopo aver controllato alcuni di quei CBVS pre-fatti. In particolare mi serviva il controllo su multiple formsets -> one parent
in un'unica vista di ogni individuo con funzioni di risparmio.
In pratica ho farcito i dati formset associazione in una funzione get_named_formsets
quale è invocato il get_context_data
e form_valid
.
Ecco, io controllare se tutte formsets sono validi, e anche cercare un metodo che le sostituzioni una pianura vecchio formset.save()
su una base per formset per il risparmio personalizzato.
Il modello rende formsets tramite
{% with named_formsets.my_specific_formset as formset %}
{{ formset }}
{{ formset.management_form }}
{% endwith %}
Credo che sarò con questo sistema regolarmente.
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()
Si dovrebbe provare django-extra-vista . Cercare CreateWithInlinesView
e UpdateWithInlinesView
.
I rosso il codice sorgente generica del 1,3-beta-1:
Il codice non è assolutamente pronto per la modifica List o c'è qualche magia nera qui. Ma penso che possa essere implementata rapidamente.
Se si guarda alla django.view.generic.edit (che il supporto di modifica oggetto dettagliata) modulo come utilizzare il modulo django.view.generic.detail.
Credo che un modulo django.view.generic.list_edit può essere implementato utilizzando django.view.generic.list e una parte da django.view.generic.edit.
Ho fatto qualche modifica alla soluzione originale per far formset.is_valid () al lavoro:
if self.request.POST:
context['fs'] = MyInlineFS(self.request.POST, instance=self.object)
else:
context['fs'] = MyInlineFS(instance=self.object)
Il codice di risposta di Jordan non ha funzionato per me. Ho inviato la mia domanda proprio su questo, che credo ora ho risolto. Il primo argomento di inlineformset_factory deve essere prenotato, non forma di libro.
avevo bisogno di fare un ulteriore modifica al Jordan e get_context_data()
di vista di SpeQ in modo da avere formset.non_form_errors
esistere nel contesto del modello.
...
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