How to create multiple form update(edit) view in Django - django

I need to create function based or class based view which can edit/update multiple forms in one page. How to create this?

You should be able to have more than one form appear on a template by passing two different form variables in the view. Something like this:
def formview(request):
if request.method == 'POST'
form1 = form.Form1()
form2 = form.Form2()
context = {'form1': form1, 'form2': form2}
Then in your template you simply need to handle each form within the form tags like so:
<form action="" method="post">
{% csrf_token %}
{{ form1.as_p }}
{{ form2.as_p }}
<input class="btn btn-primary" type="submit" value="Submit">
</form>

Related

Django - do not validate the second form

I have this code snippet in template.
<form method="POST" novalidate>
{% csrf_token %}
{{ form }}
{{ form2.as_p }}
<button type="submit" class="btn btn-secondary">Search</button>
</form>
And in forms.py there are two forms (not ModelForm, but only Form).
form searches data in first db and form2 search data in second db and displays the results. The second form has only one field and I'd like to have something like this in
a view.
if request.method == "POST":
if form.is_valid():
# extract data from the first db
if form2.is_valid()
# extract a few more data from the second db
The field in the second form is not required for the user to fill in. If the user fills it in the user gets only more data displayed.
I solved it partially with the novalidate in HTML. But what I'd like to have is the validation of the first form and the second form with its one form field can be empty.
Is there some django feature to achieve this result?
something like this?
<form method="POST">
{% csrf_token %}
{{ form.novalidate }}
{{ form2.as_p }}
<button type="submit" class="btn btn-secondary">Search</button>
</form>

add multiple forms to page on button click

I am working on developing a permitting app using django. This is my first django project so bear with me here...
we have a default utility permit that contains some basic info like property owner and address. Then from that you can attach a sewer, or water or row or any combination of related tables to the permit. Basically I am looking for a way to return a page with the default utility permit then have a series of links or buttons to add more forms to that page.
I made some model forms for each of the models and can display them individually on the page
forms.py
class UtilityPermitForm(forms.ModelForm):
class Meta:
model = UtilityPermit
fields = ['...']
class SewerPermitForm(forms.ModelForm):
class Meta:
model = SewerPermit
fields = ['...']
class WaterPermitForm(forms.ModelForm):
class Meta:
model = WaterPermit
fields = ['...']
I successfully added them to a list and could iterate through and get them to add
views.py
class BuildForms(View):
permits = []
utility_form = UtilityPermitForm
sewer_form = SewerPermitForm
water_form = WaterPermitForm
permits.append(utility_form)
permits.append(sewer_form)
permits.append(water_form)
template_name = 'engineering/UtilityPermitForm2.html'
def get(self, request, *args, **kwargs):
out_permits = []
for form in self.permits:
out_permits.append(form())
return render(request, self.template_name, {'form': out_permits})
def post(self, request, *args, **kwargs):
if request.GET.get('testButton'):
return HttpResponse("I guess")
form = self.utility_form(request.POST)
return render(request, self.template_name, {'form': form})
def add_permit(self, request, permit):
# need to get a thing to add a permit to the list
pass
.html
{% block content %}
<div>
<form class="site_form" action={% url 'engineering:utility_permit' %} method="post">
{% csrf_token %}
{% for item in form %}
{{ item }}
<hr>
{% endfor %}
<input type="submit" value="Submit">
</form>
</div>
{% endblock content %}
so again, my problem is I want to start with a one permit and then have links or buttons to add each form as needed. I'm a bit at a loss here and any help would be greatly appreciated.
EDIT:
so I have this base permit that comes up when a user navigates to it like so, and I want to have a user click the add sewer permit button or link or whatever
and then the corresponding permit will come up
you can create multiple same form in one page dynamically using formset
see Documentation
and maybe this tutorial is exactly what you are looking for.
EDITED
if I understand your question correctly, how about this:
first, it would be better to separate your form with dictionaries instead of list in your views.py
context = {
'utility_form': self.utility_form,
'sewer_form': self.sewer_form,
'water_form': self.water_form
}
return render(request, self.template_name, context)
then in your .html file,
if you want to add one form each time you click the button, my trick is:
show your base permit form first (said utility_form), button to add other form, and hide your other form first.
<div class="form-container">
<form class="site_form" action={% url 'engineering:utility_permit' %} method="post">
{% csrf_token %}
{{ utility_form }}
<div id="additional-forms"></div> <!-- notice this div -->
<hr>
<input type="submit" value="Submit">
</form>
</div>
<button class="add-sewer-form">Sewer Permit</button>
<div id="sewer-form-template" style="display: none;">
<div class="sewer-form-container">
{{ sewer_form }}
</div>
</div>
and then using jquery to add onclick listener, clone that hidden form, then insert it after base form (actually inside div with id additional-forms).
$('.add-sewer-form').click(function(){
let sewer_form = $('#sewer-form-template .sewer-form-container:first').clone(true);
$(sewer_form).appendTo($('#additional-forms'))
});
I haven't test it yet, but when you click the add button, it should be give result like this:
<div class="form-container">
<form class="site_form" action={% url 'engineering:utility_permit' %} method="post">
{% csrf_token %}
{{ utility_form }}
<div id="additional-forms">
<div class="sewer-form-container">
{{ sewer_form }}
</div>
</div>
<hr>
<input type="submit" value="Submit">
</form>
</div>
<button class="add-sewer-form">Sewer Permit</button>
<div id="sewer-form-template" style="display: none;">
<div class="sewer-form-container">
{{ sewer_form }}
</div>
</div>
Hope it can answer your question :)
First add the button
<button><button>
Then add onclick attribute to it which will help react on click
<button onclick='do'><button>
Then create script that contain the function to display the other form
<script>
function do() {
document.getElementById('form').innerHTML ='add your form here'
}
</script>
all together
<button onclick='do'><button>
<script>
function do() {
document.getElementById('form').innerHTML ='add your form here'
}
</script>

How to populate existing html form with django UpdateView?

I am trying to implement a simple UpdateView, but I want to use my own template. Using djangos auto_population is working, but not what I want, because I have lots of fields formatted differently.
<form method="post" action="#">
{% csrf_token %}
{{ form.as_p }}
<input type="submit">
</form>
But I want to use my own form template which looks like this:
edit_template.html
<form class="form-horizontal" role="form" method="POST" action="{% url 'update' pk=abc %}">
{% csrf_token %}
<input name='varX' id="varX" type="text" placeholder="" class="form-class">
<input name='varY' id="varY" type="text" placeholder="" class="form-class">
</form>
views.py
class ModelUpdate(UpdateView):
model = MyModel
fields = ['varX','varY']
Now I would like that form to be populated with my object data, but the form is empty.
UpdateView is also passing the data twice to the template: One as 'object' and one as 'mymodel'.
I also tried updating
get_context_data
by adding
context.update( model_to_dict(myModelData))
But that also does not change anything.
How can I populate my custom form using djangos class-based views?
Try this:
def get_initial(self):
initial = super().get_initial()
initial['my_form_field1'] = self.request.something
return initial
Have a look at django-widget-tweaks, you first need to check for any non field errors and then loopt through the fields one by one.
https://simpleisbetterthancomplex.com/article/2017/08/19/how-to-render-django-form-manually.html
This article should cover just that

How to change form layouts in Django 1.8

I have a form
Field Name: [Input Box]
I want
Field Name:
[Input Box]
How can I achieve this?
forms.py
class SearchForm(forms.Form):
search = forms.CharField()
views.py
form = SearchForm()
html_dtc = {'form':form}
return render_to_response('site/home.html', html_dtc)
home.html
<form method='POST' action=''> {% csrf_token %}
{{ form.as_p }}
<button type="submit" class="btn btn-success btn-sm">Update</button>
</form>
Thank you :)
You want a custom form rendering. You can read more about it here. For example, the following code would achieve what you're after.
<form method='POST' action=''> {% csrf_token %}
{% for field in form %}
<div class="fieldWrapper">
{{ field.errors }}
{{ field.label_tag }} <br/>
{{ field }}
</div>
{% endfor %}
<button type="submit" class="btn btn-success btn-sm">Update</button>
</form>
(field.errors are added, because when you are manually rendering the form, you have to take care of error rendering as well)
Try to overide form.as_p()
class SearchForm(forms.Form):
search = forms.CharField()
def as_p(self):
"Returns this form rendered as HTML <p>s."
return self._html_output(
normal_row='<p%(html_class_attr)s>%(label)s <br> %(field)s%(help_text)s</p>',
error_row='%s',
row_ender='</p>',
help_text_html=' <span class="helptext">%s</span>',
errors_on_separate_row=True)
If this is a one off thing you can render your form manually like described here in the documentation.
Otherwise there's the django-floppyforms which gives you great control over how forms and (default) widgets are rendered.
Just define a custom layout, make it the default, use floppyforms custom Form classes (they behave exactly the same) and you're good to go.
As far as I remember some of floppyforms's functionality will also be included in Django 1.9, so look out for that, too.
Use django_crispy_forms: http://django-crispy-forms.readthedocs.org/en/latest/
In the template include {% load crispy_forms_tags %} and for the form:
{% crispy form %}
In addition, you can change the layout of the form easily, by overriding the form_class in the init function of the form:
class ContactForm(forms.Form):
def __init__(self, *args, **kwargs):
super(ContactForm, self).__init__(*args, **kwargs)
self.helper = FormHelper()
self.helper.form_tag = False
self.helper.form_class = 'form-horizontal' # <-- leave out for vertical, or form-inline
self.helper.render_hidden_fields = True
self.helper.layout = Layout(
Div(InlineRadios('applying_for_whom'), css_class="col-xs-12"),
Div(InlineRadios('gender'), css_class='col-xs-12'),
Div('agreed_to_data_transmit', css_class="col-xs-12"),
As a bonus, if you are using bootstrap, set also set CRISPY_TEMPLATE_PACK = 'bootstrap3' so then everything is taken care of automatically for vertical bootstrap.
you can do
<form method='POST' action=''>
{% csrf_token %}
<label>Field Name:</label>
{{ form.search }}
<button type="submit" class="btn btn-success btn-sm">Update</button>
</form>
generally I don't recommend use the HTML code generated by Django, but instead I supply what is needed by the DJANGO form.
but some are required: like the ERRORs, like the CSRF token.
let me add some examples to clarify what I am talking
<form class="*" style="*">
<label /><input name="email" />
<label /><input name="password" />
<form>
basically what I am suggesting is, do not use template tags unless absolute necessary like CSRF.
in this way, you can completely separate the design from the backend logic. you can have front end work indecently on the UI. the interface is the form fields, you have to supply all fields to the backend. like in this case 'email' && 'password' is required at backend

loop over forms in formset and a list at same time + FileField required error :django

I have a formset which i initialize it in view. one of the form's fields is FileField. and I have to show user the name of his/her previous file name. Because i can't initialize FileField, i want to send file names in list. (I mean for example when you have a Charfield, you can initialize it in views and when you render to template, you will see an input filled with that data, but when you have file upload field you can't filled it in views and sends to template). i don't know how i can loop over forms in formset and list at the same time. And the other thing is when i initialize forms in formset and render to template (I mean for example write data['form-0-Team']='team1' but i can't write data['form-0-Team']='a.png' , so when i render to template, i see field named 'Team' is filled (value=team1) and field named 'File' is not filled and the error 'thid field is required' id shown. ) although it's the first time i'm visiting this page and my method isn't POST. (USUALLY form errors are shown when user clicks on submit and in views it checks if request.method == 'POST', then checks if form.is_valid, it return to template and shows errors, but in mine, it shows errors at the first time euser is visiting the page and before he/she posts data).
I wish i could say my problem. can you please guide me solve this? really thanks.
def myFunc(request):
flagFormSet = formset_factory(FlagFileBaseForm)
if request.method == 'POST':
formset = flagFormSet(request.POST, request.FILES)
if formset.is_valid():
# do s.th
else:
data = {
'form-TOTAL_FORMS': 5,
'form-INITIAL_FORMS': u'0',
'form-MAX_NUM_FORMS': u'',
# add initial form data to it
}
list=['a.png', 'b.png', 'c.png', 'd.png' , 'f.png']
formset = flagFormSet(data)
return render_to_response('myPage.html', RequestContext(request, { 'formset': formset, 'list':list}))
and my template:
<form method="post" action="" enctype="multipart/form-data">
{{ formset.management_form }}
{% for form in formset.forms %}
<div class="form">
<div class="form-row Team">
<div>
<label class="required" for="id_Team">Team:</label>
{{ form.Team }}
{{ form.Team.errors }}
</div>
</div>
<div class="form-row File">
<div>
<label class="required" for="id_File">File:</label>
{{ form.File }}
{{ form.File.errors }}
</div>
#here i want show the name of previous file
</div>
</div>
{% endfor %}
</form>
EDIT:
current result (while request is not post, it shows error)
desired result (form without error with file names)
In Django Templates, if you are trying to render a form that has a FileField. You must pass replace
<form method="post" action="">
with
<form method="POST" enctype="multipart/form-data">
https://docs.djangoproject.com/en/dev/ref/forms/api/#binding-uploaded-files-to-a-form
I'm afraid I don't really understand your question, so apologies if this doesn't help..
If your list is arbitary (as it looks from your question), then you could use django's built in forloop counter to construct your file names -
{% for form in formset %}
{{ form }}
<input type="text" name="file_name" value="{% forloop.counter %}.png">
{% endfor %}
Alternatively have a look at python's zip function. You could use it to build an object that includes both the names and the forms and pass that to your template.