Django: Adding inline formset rows without javascript - python

This post relates to this:
Add row to inlines dynamically in django admin
Is there a way to achive adding inline formsets WITHOUT using javascript? Obviously, there would be a page-refresh involved.
So, if the form had a button called 'add'...
I figured I could do it like this:
if request.method=='POST':
if 'add' in request.POST:
PrimaryFunctionFormSet = inlineformset_factory(Position,Function,extra=1)
prims = PrimaryFunctionFormSet(request.POST)
Which I thought would add 1 each time, then populate the form with the post data. However, it seems that the extra=1 does not add 1 to the post data.

Got it.
Sometimes it's the simplest solution. Just make a copy of the request.POST data and modify the TOTAL-FORMS.
for example..
if request.method=='POST':
PrimaryFunctionFormSet = inlineformset_factory(Position,Function)
if 'add' in request.POST:
cp = request.POST.copy()
cp['prim-TOTAL_FORMS'] = int(cp['prim-TOTAL_FORMS'])+ 1
prims = PrimaryFunctionFormSet(cp,prefix='prim')
Then just spit the form out as normal. Keeps your data, adds an inline editor.

Related

Deleting FlaskForm Fields depending on userinput in other forms

I have 3 forms with Checkboxes to configure the desired form (Final_Form). After the user chooses the desired fields (in form1, form2 and form3), i want to delet all fields that are not required in the final form and render the final form. The reason for that is, that i have 3 Subkategories with around 12 possible values, in each form (form1-form3) the user can choose one ore more subkategories. The subcategories are standardized and are used to describe a clinical incident. The users wished to have the subcategories (1-3; form1-form3) seperated and always with an example (right-side of the screen in an anther bootstrap col).
The finalform is than a combination of the the subcategories that matches best to describe the clinical incident. All fields in the Final_Form are TextAreaFields. The Input for the TextAreaFields is stored in a sqlite-db.
Here is how i tried it:
app.py:
if request.method == 'POST' and form1.form1Submit.data:
OnePointOne = form1.OnePointOne.data
if not OnePointOne:
del Final_Form.OnePointOne
return render_template('Form2.html', form2 = form2)
if request.method == 'POST' and form2.form2Submit.data:
TwoPointTwo = form2.TwoPointTwo.data
if not TwoPointTwo:
del Final_Form.TwoPointTwo
return render_template('Form3.html', form3 = form3)
if request.method == 'POST' and form3.form3Submit.data:
ThreePointThree = form3.ThreePointThree.data
if not ThreePointThree:
del Final_Form.ThreePointThree
return render_template('Final.html', Final_Form = Final_Form)
forms.py:
class form1(FlaskForm):
OnePointOne = BooleanField('Effect')
form1Submit = SubmitField('Submit Category')
class form2(FlaskForm):
TwoPointTwo = BooleanField('Measure')
form2Submit = SubmitField('Submit Category')
class form3(FlaskForm):
ThreePointThree = BooleanField('Result')
form3Submit = SubmitField('Submit Category')
class Final_Form(FlaskForm):
OnePointOne = TextAreaField('Example Effect')
TwoPointTwo = TextAreaField('Example Measure')
ThreePointThree = TextAreaField('Example Result')
Final_FormSubmit = SubmitField('Submit incident')
The problem is, that the formfields of the Final_Form objects dont get deleted (only inside the if statements). I am very thankful for every hint or explanation.
As you are showing three separate pages, there are three separate requests.
You Final_Form object cannot be simply kept between these requests.
I don't fully understand why you configure your third form this way, it would be helpful to explain your use-case for better advice.
Without more information, I'm thinking of some ways to do this:
You make it one page/request, where you go from form to form using AJAX.
You make it one page with all forms, controlling visualisation with JS + CSS
You save your desired value somewhere
probably you can keep it in cookie (session object)
or in database, if that makes sense in your context
Also, please include whole code of this function - it's not clear how you create those forms you use.

How to deal with errors in large formsets?

I'm just starting with formsets and I have trouble making a user friendly error system.
So the user sees a list view that shows him all instances of a model already written into a formset. This pages is meant to show him the data and edit it as well.
Before I was using a lot of individual forms with a save button for every form. But now I want to improve it to have a formset that provides a single save button for all of the forms.
But there comes my problem: Before I used to send the user via "action" to another url (e.g. .../update/ ) which processes the request and then sends him back to the list view he saw before. That's to avoid multiple submits when hitting F5.
But now if I do this and only a single form is wrong all the information the user had entered is lost.
So instead I stopped using the extra URL and made the processing part of the list view. Now I can use form.error on every form, but also the user resubmits when hitting F5.
Is there a way to have both?
Also: I have 1 extra form. But if the user changes it, and I feed the POST data into the formset, save it and then put it back to the page I lost the extra formset, because now the former extra is showing the newly entered instance and there is no true extra field left until the page is refreshed without sending post data.
Here is my View:
class BVServerListView(View):
def get(self, request):
eigene_server = Server.objects.filter(user=request.user)
EigeneServerFormset = modelformset_factory(Server, extra=1, form=ServerForm)
eigene_server_formset = EigeneServerFormset(queryset=eigene_server)
context = {'eigene_server': eigene_server_formset,}
return render(request, 'bildverteiler/server_list.html', context)
def post(self, request):
eigene_server = Server.objects.filter(user=request.user)
EigeneServerFormset = modelformset_factory(Server, extra=1, form=ServerForm)
eigene_server_formset = EigeneServerFormset(request.POST, request.FILES)
for form in eigene_server_formset.forms:
if form.data.get('delete', False):
server = Server.objects.get(user=request.user, name=form.data['name'])
server.delete()
else:
if form.has_changed() and form.is_valid():
server = form.save(commit=False)
server.user = request.user
server.save()
context = {'eigene_server': eigene_server_formset,}
return render(request, 'bildverteiler/server_list.html', context)
There is no difference between using a single form or a formset here. The answer is the same: post to the same view, but redirect after a successful save.
The other thing that you are doing wrong here is to validate and save individual forms one by one. Don't do that, because you could end up with a situation that the first forms are valid and get saved, but subsequent ones are invalid and therefore the formset needs to be redisplayed. Instead, validate the formset as a whole:
if eigene_server_formset.is_valid():
for form in eigene_server_formset.forms:
if form.cleaned_data.get('delete'):
... delete ...
else:
form.save()
return HttpResponseRedirect('somewhere_else')
return render...

How to pre-populate Django form with part of URL?

I'm completely new to programming (Django), and I'm trying to pre-populate a django_messages form with a snippet of the URL.
For example, for a compose form at www.mywebsite.com/compose_root/Chris88, I want the "Recipient" field to be pre-populated with "Chris88".
Is there any way to do this? In urls.py, I have:
url(r'^compose_root/(<recipient>[\w.#+-]+)/$', compose, name='messages_compose_to'),
I already tried plugging in recipient as an initial in the "Recipient" form field, but it didn't work, so it might be easier just to pre-populate with an excerpt of the URL.
Help is much appreciated.
Assuming you have a form that looks something like:
class New_form(Form.form):
... FormStuff
recipient = Some Field
Add a view that looks like:
def compose_root(request,recipient):
...# View Stuff
form = New_form(initial={"recipient": recipient})
return render_to_response('form-template.html', {'form':form})
And in your form-template
{{form}}

Keeping typed in form data in django

I have a form where i would like the data to be still present in the form fields if there is a form validation error. By default when i try to submit data in the form django clears all the fields. What is the best approach for doing this using django 1.6 ?
I thought i would just fetch data like so: request.POST['field'], send it to the template and then let the template run a conditional if statement by im getting an error from django telling me that the values isnt found in the multidict but it is found when i fill out the form field so that doesnt seem to work. I also tried to check if the value was present directly in the view but i ended up with a ridicoulus amount of if statements to be able to do this which is just an ugly hack.
Can someone suggest a good working solution on this ? Ive seem threads on SO on kind of the same problem but people just wrote that it should be the default to keep data but that doesnt seem to be the case for django 1.6.
I imagined your form class MyForm(). If the form is not valid send form = MyForm(request.POST) to template.
some view:
def myview(request):
if request.method=='POST':
form = MyForm(request.POST)
if form.is_valid():
form.save()
return render(request, 'success.html')
else:
form = MyForm()
return render(request, 'form.html',{'form':form})
<form action="." method="POST">
{{form}}
</form>

django ModelForm save() method issue

I have a model form:
class SnippetForm(ModelForm):
class Meta:
model = Snippet
exclude = ['author', 'slug']
and I want to be able to edit a particular instance by using this:
def edit_snippet(request, snippet_id):
#look up for that snippet
snippet = get_object_or_404(Snippet, pk=snippet_id)
if request.user.id != snippet.author.id:
return HttpResponseForbidden()
if request.method == 'POST':
form = SnippetForm(data=request.POST, instance=snippet)
if form.is_valid():
form.save()
return HttpResponseRedirect(snippet.get_absolute_url())
else:
form = SnippetForm(instance=snippet)
return render_to_response(SNIPPET_EDIT_TEMPLATE,
{'form':form, 'add':False, 'user':request.user},
RequestContext(request))
Notice that at the line
form = SnippetForm(data=request.POST, instance=snippet)
, I created a form that use the data supplied from the user, and bound it with the instance found using the primary key (received from the url). According to django documentation, when I call save() the existing instance should be updated with POSTED data. Instead, what I see is a new object is created and saved into the database. What went wrong? Thanks a lot.
[Edit] This is really embarrassed. The code indeed has nothing wrong with it. The only thing that messed up the whole thing was the action I put in the template (as I use a same template for add and edit a snippet)....Thanks a lot for your help, really appreciate that.
I don't see why it would happen. What version of django is it?
In any case, you can manually force update passing the corresponding argument.
form = SnippetForm(data=request.POST, instance=snippet, force_update=True)

Categories