How to save couple forms of same model?
Here is example, I have one model with a lot of fields, so I decided to create a couple forms with different model fields of that model instead of creating one big form because site requires custom styling for each part of data, so it easer to group input fields with same style to one form.
def add_pet(request):
form1 = PetMainInfoForm()
form2 = PetFoodForm()
form3 = PetDescriptionForm()
if request.method == 'POST':
form1 = PetMainInfoForm(request.POST)
form2 = PetFoodForm(request.POST)
form3 = PetDescriptionForm(request.POST)
if form1.is_valid() and form2.is_valid() and form3.is_valid():
form1.save()
form2.save()
form3.save()
return HttpResponse('ok ok ok')
return render(request, 'add_pet.html', {'form1': form1,
'form2': form2,'form3': form3})
Did you try using prefix for each form? Prefix should be unique for each form. This way, when you post back you know which form has posted. It helped me post multiple forms from same template. I hope it helps you too.
form1 = PetMainInfoForm(request.POST, prefix='PetMainInfoForm')
Related
So I'm trying to make a calculator of sorts where the user enters some data and then they are presented with a view that gives them the results they need (printer-friendly format so they can print it).
What I've done so far:
Created a model and a form which they work as intended.
**class CalcModel**(models.Model):
income = models.DecimalField...
civil_status = models.CharField...
have_children = models.CharField..
**class CalcForm**(ModelForm):
class Meta:
**model = Calculate**
fields = ['income', 'civil...]
The view that processes the form and redirects to another view if submitted data is valid:
data_d = {}
def createcalculation(request):
form = CalcForm()
if request.method == 'POST':
form = CalcForm(request.POST)
if form.is_valid():
**data_d['cleaned_data'] = form.cleaned_data**
form.save()
return redirect('res-view')
context = {'c_form': form}
return render(request, 'calc/calc.html', context)
I think there should be a way to pass the model instance data to the view where the user is redirected but I can't figure it out. So, help is highly appreciated. Right now, I'm 'manually' passing a dictionary containing the data from the form but it doesn't work:
def res_ca(request):
context = data_d
return render(request, 'calc/res_ca.html', context)
I can't seem to figure out how to pass the data for the current session to the res_ca view.
The urls if that helps:
path('calc', createcalculation, name='calculate'),
path('res/', res_ca, name='res-view'),
As suggested by #vinkomlacic, I found a way to include the id of the model instance by switching to the render method instead of redirect and it worked like a charm.
if form.is_valid():
messages.success(request, f'Successful!')
item = form.save()
m_data = Calculate.objects.get(id=item.id)
context = {'c_data': form.cleaned_data, 'm_data': m_data}
return render(request, 'calc/res_ca.html', context)
This way, the form is saved, I can pass that instance of the model to the next view and it also allows me to add additional context to the template directly from model methods.
I have a date model and a Order model. The date model is connected to Order model by a foreignkey, I'm trying to update the date model feilds in Order model with a form. I want the form to autofill the fields with saved data in admin database. I tried a lot to find the solution but I couldn't find it.
In your view.
You need to edit the function
views.py
def orderDetailView(request, pk):
order = Order.objects.get(pk=pk)
date_instance = order.date
form = DateForm(request.POST, request.FILES, instance=date_instance)
if form.is_valid()
form.save()
.....
....
context = {
'order': order, 'form': form
}
return render(request, "date_list.html", context)
Basically, what I'd like to do is take a formset that has been bounded to request.POST, add a blank form to it, and return the new formset.
class MyView(View):
def post(self, request):
MyFormSet = formset_factory(MyForm)
posted_formset = MyFormSet(request.POST)
# Append a blank form to posted_formset here
return render(request, 'mytemplate.html', {'formset': posted_formset})
Is there any clean way to do this in Django 1.6? Right now I've got a workaround that involves creating a new formset with initial set to the data bound in posted_formset, but it's kind of clunky, and I feel like there should be an easier way to do this.
This might be a possible duplicate of this question: Django: How to add an extra form to a formset after it has been constructed?
Otherwise have a look at the extra parameter for the factory function. You get more information about formsets in the Django Documentation
So it seems like there's no clean way to do this, as after a formset is bound to a QueryDict, the extra parameter passed to formset_factory becomes irrelevant. Here's how I'm doing it in my view right now:
class MyView(View):
def post(self, request):
MyFormSet = formset_factory(MyForm)
posted_formset = MyFormSet(request.POST)
initial = []
for form in posted_formset:
data = {}
for field in form.fields:
data[field] = form[field].value()
initial.append(data)
formset = AuthorFormSet(initial=initial)
return render(request, 'mytemplate.html', {'formset': formset})
Basically, I bind a formset to request.POST, then iterate through it and grab the field values and put them into an array of dicts, initial, which I pass in when I make a new formset (see docs) that will have an extra blank form at the end because it's not bound.
This should work with any form and formset. Hope it helps someone.
I have a formset with three forms that the user inputs. Next to this, I have another form with one field that I want to validate against the fields inputted in the formset. Views.py looks something like:
FormSet = formset_factory(Form1, formset=BaseFormSet, extra=3)
if request.method == 'POST':
formset = FormSet(request.POST, request.FILES, prefix='first_form')
form2 = Form2(request.POST)
if formset.is_valid() and form2.is_valid():
# do something with the data
pass
else:
formset = FormSet(prefix='first_form')
target_shoe_form = TargetShoeForm()
return render(request, 'my_template.html', {
'formset': formset,
'form2': form2,
})
Is there a way to validate Form2 against the values in my Formset? As currently above they only validate internally, not against each other. Or, is it necessary to either nest the singleton form inside the formset, or nest the formset in the singleton form somehow? Thanks!
Update on validation:
Form1 has two fields, and rendered three times as part of a formset. Form2 has one field. When the user submits, I want to check that Form2's field is distinct from any of the values submitted in Form1
I have a many-to-many relationship between two classes (Lesson and Student), with an intermediary class (Evaluation).
I am trying to set up a form which will allow me to add a lesson with students and the related evaluation data. I can get all of the fields I want to display correctly, however I also need to set an initial value behind the scenes (the current user), as it does not make sense to have it in the form.
I have tried following the docs but I think I have a syntax error in the way I am passing the data to the formset.
The error I receive is as follows:
__init__() got an unexpected keyword argument 'initial'
My actual view (with my attempt at adding the initial data removed) looks like this:
def addlesson(request):
LessonFormset = inlineformset_factory(Lesson, Evaluation, exclude=('user',), max_num=5)
if request.method == 'POST':
lesson = Lesson(user=request.user)
form = LessonForm(request.POST, instance=lesson, user = request.user)
formset = LessonFormset(request.POST, instance = lesson)
if form.is_valid() and formset.is_valid():
form.save()
formset.save()
return HttpResponseRedirect("/")
else:
form = LessonForm(user = request.user)
formset = LessonFormset()
return render_to_response("addlesson.html", {
'form': form,
'formset' : formset,
}, context_instance=RequestContext(request))
Could anyone show me to correct syntax to use to set the current user in the formset?
This is what I had before but it was giving me the error at the start of my post:
initial={'user': request.user},
Any advice appreciated
Thanks
It's not clear to me why you are using a formset when it looks like you only want to add one row. A regular form would have been how I would do it if there was only one row. But, here's how I set the default value in a formset.
I exclude the field, just like you already have in your code. Then:
if form.is_valid() and formset.is_valid():
form.save()
models = formset.save(commit=False)
for i in models:
i.user = request.user
i.save()
return HttpResponseRedirect("/")
I tried Umang's answer and it didn't work good for when you want to change a value with a specific index. When you save the formset it will change the values that was changed.
But if you change models = formset.save(commit=False) to models = formset
and then you also need to change i.user = request.user to i.instance.user = request.user
if form.is_valid() and formset.is_valid():
form.save()
# changed to formset instead of formset.save(commit=False)
models = formset
for model in models:
# changed to i.instance.user instead of i.user, except renamed i to model.
model.instance.user = request.user
model.save()
# save the formset
formset.save()
return HttpResponseRedirect("/")
Now when you want to change an index it will include all the forms, not only the ones that was changed when you save.
Example:
views.py
if form.is_valid() and formset.is_valid():
form.save()
models = formset
index = 0
# This will only change the first form in the formset.
models[index].instance.user = request.user
models.save()
formset.save()
return HttpResponseRedirect("/")