django form populate multiple identical field form in one submit - django

I don't want to use django form class as they will not give me much flexibility.
I have a form where will random number field in easy request. i am trying to populate the multiple value of forms that appears.
this is my models.py
class Profile(models.Model):
name = models.CharField(max_length=100)
photo = models.FileField()
and this my form.html
<form method="POST" action="{% url 'form' %}">
{% csrf_token %}
{% for i in range %}
<input type="text" id="name" name="name"><br>
<input type="file" id="photo" name="photo"><br><br>
{% endfor %}
<input type="submit" value="Submit">
</form>
You may notice I am rendering field with for loop.
that is means, there will be as much field as possible can be appear based on user request.
So I want to populate these models.
my view looks like
def form_view(request):
if request.method == 'POST':
# Need to puplate the form
return render(request, 'form.html', {'range': range(40)})
Can anyone please help me how can i achieve this? i am just struggling to achieve this.

you can use modelformset_factory for this. this way,
in your views.py
from .models import Profile
from django.forms import modelformset_factory
def form_view(request):
form_range = 40 # set the range here
ProfileFormSet = modelformset_factory(Profile, fields=("name", "photo"), extra=form_range, max_num=form_range)
formset = ProfileFormSet(request.POST or None)
if request.method == "POST":
if formset.is_valid():
formset.save()
return render(request, "form.html", {"profile_formset": formset})
and in your form html
<form method="POST" action="{% url 'form' %}">
{% csrf_token %}
{{ profile_formset.as_p }}
<input type="submit" value="Submit">
</form>

Related

Generating forms based on user choices in Django

I am working on a Django project whose purpose is to allow the user to fill in some forms. In some of these forms, the user must make a choice between several options and, based on the choice made, a particular form must be generated. At the end of all these forms, the data entered must be used to write a pdf file.
As for the functionality related to generating the pdf, what I'm interested in for the purposes of the question is the use of data entered in one view in another view using them as context.
Here's what I tried to do.
First of all I created some forms in forms.py:
class ChoiceForm(forms.Form):
CHOICES = [
('1', 'Choice-One'),
('2', 'Choice Two'),
]
choice = forms.ChoiceField(choices=CHOICES)
class ChoiceOneForm(forms.Form):
name_one = forms.CharField(max_length=200)
class ChoiceTwoForm(forms.Form):
name_two = forms.CharField(max_length=200)
Then I created this view in views.py:
def contact(request):
if request.method == 'POST':
num_people = int(request.POST.get('num_people'))
people_formset = [forms.ChoiceForm() for i in range(num_people)]
return render(request, 'home.html', {'people_formset': people_formset})
else:
return render(request, 'home.html')
def generate_pdf(request):
context = {}
return render(request, 'pdf.html', context)
And finally I have this HTML file called 'home.html':
<h1>Contact</h1>
<form method="post">
{% csrf_token %}
People number: <input type="number" name="num_people" required>
<input type="submit" value="Submit">
</form>
{% if people_formset %}
{% for form in people_formset %}
<form>
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Submit">
</form>
{% endfor %}
{% endif %}
what I've been able to achieve so far is to generate as many 'choice' fields as the value of the number entered in the 'num_people' field.
What I'm missing is:
1. Being able to create, for each 'choiche' field in the formset, a ChoiceOneForm or ChoicheTwoForm form based on the choice made in the 'choice' field;
2. Being able to use all this data in the 'generate_pdf' view (for now what interests me is being able to include this data in the context of this view).

Why don't my entries get saved in the database in Django?

The post requests from the frontend do not get saved in the database, without any error shown. However, when I manually add entries from the admin panel, it shows on the frontend.
My index.html(form part):
<form class="main__input--form" method="POST">
{% csrf_token %}
<p class="main__input--text">
<textarea name="content" id="content" class="main__input--content" cols="35" rows="8" aria-label="Entry content" placeholder="Enter text here..."></textarea>
</p>
<button class="main__input--submit" type="submit">Vent</button>
</form>
My extension of index which loops through the database entries:
{% for obj in all_vents %}
<div>
<h1>{{obj.vent}}</h1>
</div>
<br />
{% endfor %}
My models.py:
class Vents(models.Model):
vent = models.CharField(max_length=10000)
def __str__(self):
return self.vent
My forms.py:
from django import forms
from .models import Vents
class VentForm(forms.ModelForm):
class Meta:
model = Vents
fields = ['vent']
My views.py:
from django.shortcuts import render, redirect
from .forms import VentForm
from .models import Vents
def ventout(request):
if request.method == "POST":
form = VentForm(request.POST or None)
if form.is_valid():
form.save()
return redirect("ventout")
else:
all_vents = Vents.objects.all()
return render(request, "ventout.html", {"all_vents": all_vents})
Views:
def ventout(request):
all_vents = Vents.objects.all()
if request.method == "POST":
form = VentForm(request.POST or None)
if form.is_valid():
form.save()
return redirect("ventout")
else:
form = VentForm()
context = {"all_vents": all_vents, "form":form}
return render(request, "ventout.html", context)
Template:
<form class="main__input--form" method="POST">
{% csrf_token %}
{{ form.as_p }}
<button type="submit" class="main__input--submit">Vent</button>
</form>
you could install/use "crispy_forms_tags" to make the form look better,
https://django-crispy-forms.readthedocs.io/en/latest/index.html
if you want to go further you could install/use "widget_tweaks"
https://pypi.org/project/django-widget-tweaks/
Your index.html from part should have {{ form }} form tag, as I guess.
Try Using following code
<form class="main__input--form" method="POST">
{% csrf_token %}
{{ form }}
<p class="main__input--text">
<textarea name="content" id="content" class="main__input--content"
cols="35" rows="8" aria-label="Entry content" placeholder="Enter text here...">
</textarea>
</p>
<button class="main__input--submit" type="submit" value="Submit">Vent</button>
</form>

How do i add <input type="button"> as a formfield in django

I want to have an input field as a button in my template. Just like this.I am manually rendering form fields in my template.So, how do i create a field like that in my form.
Formfield in forms.py
class DetailForm(forms.Form):
owner=forms.CharField(widget=forms.TextInput(attrs={'class':'form-control'}))
views.py
def getDetail(request):
form=DetailForm()
return render(request,'materials/addpage.html',{'form':form})
and template,
<div class="form-group">
{{form.owner}}
</div>
A minimal example of using buttons as input in Django looks like this:
Template:
<form method="POST">
{% csrf_token %}
<input type="submit" name="btn" value="yes">
<input type="submit" name="btn" value="no">
</form>
{{ val }}
Form:
class Fooform(forms.Form):
btn = forms.CharField()
View:
def test_view(request):
if request.method == 'POST':
form = Fooform(request.POST)
if form.is_valid():
val = form.cleaned_data.get("btn")
else:
form = Fooform()
return render(request, 'template.html', locals())
Libraries like crispy-forms have button widgets.

Django - How do form template tags work?

This is a simple question, but I can't find the answer. The django docs show the following example for calling a form in template just using {{ form }}:
<form action="/your-name/" method="post">
{% csrf_token %}
{{ form }}
<input type="submit" value="Submit" />
</form>
This doesn't fully explain how the {{ form }} tag in the template works if I'm not missing something.
I have my some snippets of my code here which show the problem I'm having with my form tag which currently returns blank:
forms.py
class addtaskForm(forms.ModelForm):
task_name = forms.CharField(label='task_name')
priority = forms.ChoiceField(choices=PRIORITY_CHOICES)
views.py
def add_task(request):
if request.method == "POST":
return HttpResponse("works!")
urls.py
url(r'^add_task/$', 'todo.views.add_task', name='add_task')
tasks.html
<form id="add_task" action="/add_task/" method="post">
{% csrf_token %}
{{ add_task_form }}
<input type="submit" value="submit">
</form>
The {{add_task_form}} is just a guess.
{{ form }} is not a template tag, it is a context variable. By default Form instances are rendered using the Form.as_table() method. So you have to pass such variable to the template in the render() call:
from django.shortcuts import render
def add_task(request):
if request.method == "POST":
form = addtaskForm(request.POST)
if form.is_valid():
# do something useful and redirect
else:
form = addtaskForm()
return render(request, 'tasks.html', {'add_task_form': form})
I suggest you to carefully read the full explanation of the forms in the Working with forms chapter of the django documentation.

Updating form in Django. How to design?

I'm a django newbie.
I have this model:
class Item(models.Model):
name = models.CharField(max_length=255)
quantity = models.IntegerField()
How to create view to update quantity of my all Item?
views:
def item_list(request):
item = Product.objects.all()[:6]
return render_to_response('item.html',{'item':item},context_instance=RequestContext(request))
form:
from django import forms
class QuantityForm(forms.Form):
quan = forms.IntegerField()
template:
{% for i in item %}
{{ i.name }}
{{ i.quantity }}
{% endfor %}
I'm trying to do something like this(after clicking "update" value quantity in my model should be actualize):
Please any help. Thanks
First you need a view, which retrieves item id and quantity value, updates relative Item instance and redirects you back to the page. Here is an example:
from django.views.decorators.http import require_http_methods
from django.shortcuts import redirect, get_object_or_404
#require_http_methods(["POST"])
def update_item(request)
id = request.POST.get('id', None) #retrieve id
quantity = request.POST.get('q', None) #retrieve quantity
item = get_object_or_404(Item, id=id) #if no item found raise page not found
if quantity:
#updating item quantity
item.quantity = quantity
item.save()
return redirect('my-item-list-view-name')
Also you need to create urlpattern for the view in your urls.py. For example:
...
url(r'^update-item/$', 'update_item', name='update_item'),
...
Then you can make a forms for each item on a template:
{% for i in item %}
<form action="{% url 'update_item' %}" method="post">
{% csrf_token %}
{{ i.name }}
<input name="id" type="hidden" value="{{ i.id }}" />
<input name="q" type="text" value="{{ i.quantity }}" />
<input type="submit" value="update" />
</form>
{% endfor %}
I'm trying to offer a solution as simple as possible. You should know that django provides a lot of cool stuff, that can help your to solve your problem much efficiently, such as forms, modelforms, formsets...
You can either create a ModelForm for your item and then use Formsets or if you can use jquery to submit a ajax request to a django view that updates the item for the selected model
$('<yourbuttonclass').onClick(function(e){
e.preventdefault()
$.post(urlToPost, dataFromTextField&csrfmiddlewaretken={{csrf_token}})
.success('Successfully Updated')
....
In your view:
#Get the item id from urlconf
#ajax_request
def update_view(request, item_id)
#Update your item
return {'Success': 'Updated to blah'}
I like to use the ajax_request decorator from here for sending ajax response. You can also send a HTTPResponse('Successfully updated')
If you want to creating a Restful resource would be a great way too and then you get an interface to create, update, read and delete from a single pattern. Read up on Django Tastypie
in views.py :
if request.method=='POST':
if 'txt1' in request.POST:
if request.POST['txt1']!='':
obj=Item.objects.get(pk=request.POST['item1'])
obj.quantity=request.POST['txt1']
obj.save()
if 'txt2' in request.POST:
if request.POST['txt2']!='':
obj=Item.objects.get(pk=request.POST['item2'])
obj.quantity=request.POST['txt2']
obj.save()
if 'txt3' in request.POST:
if request.POST['txt3']!='':
obj=Item.objects.get(pk=request.POST['item3'])
obj.quantity=request.POST['txt3']
obj.save()
#continue this code for all 6 items
update:
of course U can put this in a loop:
for i in range(1,6):
if 'txt'+str(i) in request.POST:
if request.POST['txt'+str(i)]!='':
obj=Item.objects.get(pk=request.POST['item'+str(i)]
obj.quantity=request.POST['txt'+str(i)]
obj.save()
in template:
<form method='POST' action=''>
{% for i in item %}
{{ i.name }}:<input type='text' id='txt{{forloop.counter}}' value='{{ i.quantity }}' /><input type='hidden' id='item{{forloop.counter}}' value='{{item.pk}}' /><input type='submit' value='increase' id='sbm{{forloop.counter}}' />
{% endfor %}
</form>
update: forloop.counter is the current for counter,1,2,3...