Updating multiple checkboxes forms with Django - python

in my django website I'm trying to building a page in which there are multiple forms (In particular 3: the first is simply a checkbox, as the second one. The third one requires the entering of two text fields). I've already managed the presence of multiple forms and I've no problem when the user performs the first assignment. The problem is instead during the updating of the answers that the user gave the first time: there are no problems when adding new instances of the text fields of the third form, while instead if I've selected one checkbox of the first two forms and I want to change them unchecking them it seems like django doesn't save the new values. Any idea of why it's happening?
Here's the view associated:
def new_4e2(request, pk, var=None):
if Specifiche.objects.filter(ID_rich = pk).exists():
specs = Specifiche.objects.filter(ID_rich = pk)
choicesp =[]
lista =[]
for spec in specs:
choicesp+=[(spec.id, str(spec.rif))]
lista+=[spec.id]
att = MAIN.objects.get(id=pk)
unform = FormUn(instance=att)
data = {'ID_rich': pk}
form = UnicitaForm(initial=data)
form.fields['rifext'].choices = choicesp
if Unicita.objects.filter(rifext__in = lista).exists():
uns=Unicita.objects.filter(rifext__in = lista)
context={
'att': att,
'uns': uns,
'var':var,
'specs': specs
}
else:
context = {
'att': att,
'var':var,
'specs': specs,
}
form = UnicitaForm(initial = data)
form.fields['rifext'].choices = choicesp
similiform = SimiliForm(instance=att)
if request.method=='POST':
if 'Aggiungi' in request.POST:
form = UnicitaForm(request.POST, initial=data)
form.fields['rifext'].choices = choicesp
if form.is_valid():
form.save()
return redirect(f'/new_4e2/{pk}/{var}//')
if 'Simili' in request.POST:
similiform = SimiliForm(request.POST, instance=att)
if similiform.is_valid():
similiform.save()
return redirect(f'/new_4e2/{pk}/{var}//')
if 'Unicita' in request.POST:
unform = FormUn(request.POST, instance=att)
if unform.is_valid():
unform.save()
return redirect(f'/new_4e2/{pk}/{var}//')
context = context | {'form': form, 'unform':unform, 'similiform': similiform}
return render(request, 'new_4e2.html', context)
The two forms for which I have this problems are: 'unform' and 'similiform'
And here is my template.html
<form method="POST">
{% csrf_token %} 4.1 | {{unform}}
<input type="submit" name="Unicita">
</form>
{% if not att.Unicita %}
<div style="position:relative; left:50 px; height: 10 px; width:500 px;">
<form method="POST">
{% csrf_token %} {{similiform}}
<input type="submit" name="Simili">
</form>
<form action ="" method="POST">
{% csrf_token %}
<h4>Insert Unicita</h4>
{{form}}
<input type="submit" name="Aggiungi">
</form>
...

Related

[DJANGO]: How to pass a Django form field value to a template form action?

I have a Django form that asks for id number. Hence, when the user clicks on submit, that id number is passed as a parameter to the endpoint.
This URL path('verify/nin/', views.post_nin, name='post_nin') contains the form and asks for the id number while I am submitting the data to this URL to
path('nin/<str:nin>',
views.nin_verification_vw, name="nin_verification")
So I expect to be redirected to http://127.0.0.1:8000/api/nin/15374020766 but instead it is redirecting me to http://127.0.0.1:8000/api/nin/%3Cinput%20type=%22text%22%20name=%22nin%22%20required%20id=%22id_nin%22%3E?nin=15374020766&csrfmiddlewaretoken=u5UmwDW4KRUIvYWXAa64J8g1dTPoJ3yDqtoCuKjboIE2TNxI3tPbjPmCK6FztVwW
How do I avoid the unnecessary parameters?
Here is my forms.py:
class NINPostForm(forms.Form):
"""Form for a user to verify NIN"""
nin = forms.CharField(required=True, help_text='e.g. 123xxxxxxxx')
# check if the nin is a valid one
def clean_nin(self):
nin = self.cleaned_data['nin']
regex = re.compile("^[0-9]{11}$")
if not regex.match(nin):
raise forms.ValidationError("NIN is incorrect.")
return nin
Here is my views.py:
def post_nin(request):
submitted = False
if request.method == 'POST':
form = NINPostForm(request.POST)
if form.is_valid():
cd = form.cleaned_data['nin']
return HttpResponseRedirect('/verify/nin?submitted=True')
else:
form = NINPostForm()
context = {
'form': form,
# 'cd': cd,
}
return render(request, 'ninform.html', context)
And here is my HTML template:
<form action="{% url 'nin_verification' form.nin %}" method="POST">
<table>
{{ form.as_table }}
<tr>
<td><input type="submit" value="Submit"></td>
</tr>
</table>
{% csrf_token %}
</form>
first import redirect : from django.shortcuts import redirect
Change your view to :
<form action="{% url 'post_nin' %}" method="POST">
<table>
{{ form.as_table }}
<tr>
<td><input type="submit" value="Submit"></td>
</tr>
</table>
{% csrf_token %}
</form>
You were passing the whole field instead of a String by using form.nin in your form action you should use your post_nin view to parse the nin field so...
Change your view to :
def post_nin(request):
submitted = False # Don't understand this part
if request.method == 'POST':
form = NINPostForm(request.POST)
if form.is_valid():
nin = form.cleaned_data['nin']
return redirect('nin_verification', nin=nin)
else:
form = NINPostForm()
context = {
'form': form,
}
return render(request, 'ninform.html', context)
`

Django, How to add two form in one page?

I am new to django, my question is simple. How can I add two form in the same page? I tried many things as making a class in views or add a second urls path but didn't find how. Thanks you for helping
this is my code:
forms.py
class scrap_info(forms.Form):
url = forms.CharField(label="Urls")
website = forms.ChoiceField(label="Website", choices=ask_website)
class sms_info(forms.Form):
data = forms.ChoiceField(label="Data list", choices=ask_data)
number = forms.CharField(label="Sms number")
views.py
def scrap_app(request):
form1 = scrap_info(request.POST or None)
return render(request, "sms/scrap_app.html", {'form1': form1})
def sms_app(request):
form2 = sms_info(request.POST or None)
return render(request, "sms/sms_app.html", {"form2": form2})
scrap_app.html
<body>
<div>
<form method="POST">
{% csrf_token %}
{{ form|crispy }}
<button class="btn btn-outline-info" type="submit" value="Save">SCRAP</button>
</form>
</div>
</body>
urls.py
urlpatterns = [
path("/scrap_app", views.scrap_app, name="scrap_app"),
]
I have encountered this problem just recently and I solved it by adding a hidden field on every form and getting that hidden value to determine what form was submitted by using an if condition in views
Here's how I did it using CBV.
views.py
class ContactUsView(TemplateView):
template_name = 'yourtemplate.html'
def get(self, request, *args, **kwargs):
inquiry_form = InquiryForm(self.request.GET or None, prefix='inquiry_form')
complaint_form = ComplaintForm(self.request.GET or None, prefix='complaint_form')
context = self.get_context_data(**kwargs)
context['complaint_form'] = complaint_form
context['inquiry_form'] = inquiry_form
return self.render_to_response(context)
def post(self, request):
# instantiate all unique forms (using prefix) as unbound
inquiry_form = InquiryForm(prefix='inquiry_form')
complaint_form = ComplaintForm(prefix='complaint_form')
# determine which form is submitting (based on hidden input called 'action')
action = self.request.POST['action']
# bind to POST and process the correct form
if action == 'inquiry':
inquiry_form = InquiryForm(data=request.POST, prefix='inquiry_form')
if inquiry_form.is_valid():
# Your logic here
return self.render_to_response(
self.get_context_data(
inquiry_form=inquiry_form,
complaint_form=complaint_form,
)
)
messages.error(self.request,
'Inquiry form is invalid.')
elif action == 'complaint':
complaint_form = ComplaintForm(data=request.POST, prefix='complaint_form')
if complaint_form.is_valid():
# Your logic here
return self.render_to_response(
self.get_context_data(
inquiry_form=inquiry_form,
complaint_form=complaint_form,
)
)
messages.error(self.request,
'Complaint form is invalid.')
# prep context
context = {
'inquiry_form': inquiry_form,
'complaint_form': complaint_form,
}
return render(request, self.template_name, context)
yourtemplate.html
<!-- First Form -->
<form action="" method="post" role="form">
{% csrf_token %}
<input type='hidden' name='action' value='inquiry'>
{{ form1 }}
<button type="submit" title="Send Inquiry">Send Inquiry</button>
</form>
<!-- Second Form -->
<form action="" method="post" role="form">
{% csrf_token %}
<input type='hidden' name='action' value='complaint'>
{{ form2 }}
<button type="submit" title="Send Complaint">Send Complaint</button>
</form>
As you can see there's a hidden value in every form named 'action', that will be the one to determine which form was submitted.

form.as_hidden doesn't pass values to POST

My form has initial values in it. I use form.as_hidden to hide the values and pass those values through a POST request. However, the hidden values are not passing through. Is there a way through this?
views.py
def car_detail_view(request, id):
if request.method == "POST":
form = CarForm(request.POST)
print(form.is_valid())
if form.is_valid():
car_save = form.instance
get_car = Car.objects.get(number_plate=car_save.number_plate)
get_car.available = False
get_car.save()
return redirect('/')
else:
print(form.errors)
else:
car = Car.objects.get(id=id)
form = CarForm(initial={'brand':car.brand, 'number_plate':car.number_plate, 'price':car.price,
'available':car.available})
args = {
'car':car,
'form':form
}
return render(request, 'map/confirmation.html', args)
confirmation.html
<h1>Confirmation of Booking</h1>
{% block content %}
<p>Brand: {{ car.brand }}</p>
<p>Number Plate: {{ car.number_plate }}</p>
<p>Price: {{ car.price }}</p>
<p> Are you sure you want to book? <p>
<form class="" method="post">
{% csrf_token %}
{{ form.as_hidden }}
<input type="submit" value="Book {{ car.brand }}">
</form>
{% endblock %}
Error
<ul class="errorlist"><li>brand<ul class="errorlist"><li>This field is required.</li></ul></li><li>number_plate<ul class="errorlist"><li>This field is required.</li></ul></li><li>price<ul class="errorlist"><li>This field is required.</li></ul></li></ul>
Django doesn't have a form.as_hidden method. Therefore {{ form.as_hidden }} will render as the empty string '' in your template.
You can use the as_hidden method for individual form fields.
{{ form.number_plate.as_hidden }}
If you use values from hidden fields, you might need to add code to prevent the user altering the field values (e.g. with their browser's developer tools). However, in your case you don't need to get the values from the form, you can fetch them from the database.
def car_detail_view(request, id):
if request.method == "POST":
car = Car.objects.get(id=id)
car.available = False
car.save()
return redirect('/')
else:
car = Car.objects.get(id=id)
args = {
'car':car,
}
return render(request, 'map/confirmation.html', args)
Once you've got this working, you might want to think about what happens if two users try to book the same car at once.

Passing value and ID from Request.POST

I am trying to have a website with multiple input type ="text" fields which as a default have values from database in them.
Goal is to have X input types where X=number of entries in database and one extra input type box to add a new entry.
The problem is that if user edits a textfield and hits submit, Request.POST['event'] returns only the new value, not the id of the box that has been edited,
This is my current code:
<form method="post">
{% csrf_token %}
{% for choice in event %}
<form method ='POST'> {% csrf_token%}
<input type="text" name = "event" id="event{{ forloop.counter }}" value="{{choice.txt}}"><br>
<input type = 'submit' value = 'Zapisz'/>
</form>
{% endfor %}
<form method ='POST'> {% csrf_token%}
{{form.as_p}}<br>
<input type = 'submit' value = 'Zapisz'/>
</form>
and views.py:
def rpg_create(request):
try:
event = get_list_or_404(Event)
except:
event = ""
if request.method == 'POST':
try:
Adjusted_event = request.POST['event']
print (Adjusted_event)
except:
pass
form = RpgForm(request.POST or None)
if form.is_valid():
print(form)
form.save()
context = {
'form': form,
'event': event
}
return redirect('/rpgmaker', context)
else:
form = RpgForm()
context = {
'form': form,
'event': event
}
return render(request,"rpgmaker/rpg.html",context)

Validate Django forms for user specified dynamically generated fields

How do I perform a Django form validation for an unknown number of fields specified by the user? In my case, form allows a user to create a music album with any number of tracks and associate it to an artist. The view asks for how many tracks there are and then generates a form with that many input fields.
Form:
class NumberOfTracks(forms.Form):
track_no = forms.IntegerField()
class CustomAlbumAdmin(forms.Form):
artist = forms.CharField(max_length=150)
album = forms.CharField(max_length=150)
track_no = forms.IntegerField()
track = forms.CharField(max_length=150)
View:
def album_admin(request):
if request.GET.get('track_no'):
number_of_tracks = request.GET.get('track_no')
artists = Artist.objects.all()
return render(request, 'customadmin/album_admin1.html', {
'number_of_tracks': number_of_tracks,
'tracks': range(1, int(number_of_tracks) + 1),
'artists': artists,
})
elif request.method == 'POST':
form = CustomAlbumAdmin(request.POST)
print form
artist = request.POST['artist']
album = request.POST['album']
all_tracks = request.POST.getlist('track')
create_album = CreateAlbum(artist=artist, album=album, tracks=all_tracks)
create_album.save_album()
create_album.save_tracks()
form = NumberOfTracks()
return render(request, 'customadmin/no_tracks1.html', {
'form': form,
})
else:
form = NumberOfTracks()
return render(request, 'customadmin/no_tracks1.html', {
'form': form,
})
(Just so it's clear, I used if form.is_valid() and form.cleaned_data but to get this to work thus far, I've had to bypass that in favor of getting the raw POST data)
Part of what's confusing me is that I've customized my form template to add a number input fields with name="track" depending on user input (EX: create an album with 13 tracks). When I go into my view to print form = CustomAlbumAdmin(request.POST) it gives a very simple table based on my form: one artist, one album, one track, and one track_no so validating against this will of course return False unless I have an album with just one track.
Here's the template:
{% extends 'base.html' %}
{% block content %}
<form action="/customadmin/album1/" method="POST">{% csrf_token %}
<select name="artist">
{% for entry in artists %}
<option value="{{ entry.name }}">{{ entry.name }}</option>
{% endfor %}
</select>
{{ form.non_field_errors }}
<div class="fieldWrapper">
{{ form.album.errors }}
<label for="id_album">Album:</label>
<input id="id_album" maxlength="150" name="album" type="text" />
</div>
<div class="fieldWrapper">
{{ form.track.errors }}
<input type="hidden" name="number_of_tracks" value="{{ number_of_tracks }}">
{% for e in tracks %}
<label for="id_track">Track No. {{ forloop.counter }}</label>
<input id="id_track_{{ forloop.counter }}" maxlength="150" name="track" type="text" /></br>
{% endfor %}
</div>
<p><input type="submit" value="Save album" /></p>
</form>
{% endblock %}
The one way I was thinking of approaching this was to create a custom clean_track method that takes a list of all the tracks entered as I've done in the view with all_tracks = request.POST.getlist('track') but not sure how to do that.
A related question I have is if I can customize validation based on POST data. The first way I approached this was to generate incremented inputs with name="track_1", name="track_2", etc.,. and then trying to validate based on that. However, I wouldn't be able to use request.POST.getlist('track') in that case.
It might be a better approach to use formsets instead.
class AlbumForm(forms.Form):
artist = forms.CharField(max_length=150)
name = forms.CharField(max_length=150)
class TrackForm(forms.Form):
track_no = forms.IntegerField()
name = forms.CharField(max_length=150)
# In view
from django.forms.formsets import formset_factory
TrackFormSet = formset_factory(TrackForm)
if request.method == 'POST':
track_formset = TrackFormSet(request.POST)
album_form = AlbumForm(request.POST)
if track_formset.is_valid() and album_form.is_valid():
save_album(album_form, track_formset)
else:
track_formset = TrackFormSet()
album_form = AlbumForm()
And in save_album you can just iterate through track_formset.ordered_forms to get each form in the formset:
for form in track_formset.ordered_forms:
data = form.cleaned_data
# Do what you want with the data
This can be even more powerful if you use model formsets because you can set a foreign key in the track model that points to the album model, and Django can save them automatically for you.

Categories