I am reading Django docs and don’t quite understand the comment below about formsets.
Why do I need to be aware to use the management form inside the management template in this example ?
Using a formset in views and templates
Using a formset inside a view is as easy as using a regular Form class. The only thing you will want to be aware of is making sure to use the management form inside the template. Let’s look at a sample view:
from django.forms import formset_factory
from django.shortcuts import render
from myapp.forms import ArticleForm
def manage_articles(request):
ArticleFormSet = formset_factory(ArticleForm)
if request.method == 'POST':
formset = ArticleFormSet(request.POST, request.FILES)
if formset.is_valid():
# do something with the formset.cleaned_data
pass
else:
formset = ArticleFormSet()
return render(request, 'manage_articles.html', {'formset': formset})
# manage_articles.html
<form method="post">
{{ formset.management_form }}
<table>
{% for form in formset %}
{{ form }}
{% endfor %}
</table>
</form>
ManagementForm form is used by the formset to manage the collection of forms contained in the formset.
It is used to keep track of how many form instances are being displayed.
for more detail information see here
Related
I have a model form
class Parent(forms.ModelForm):
someTest = forms.CharField(max_length=20)
I have a child form:
class Child(Parent):
someTestChild = forms.CharField(max_length=20)
I want a listview for the child form, this is my url.py
path('Testing/',
views.Child.as_view(),name="child"),
but I get an error saying that this class has no .as_view possibility.
Is it possible to create an list and detailview on the child form.
You are calling as_view() on the forms.ModelForm class which is not possible. You can only call that on a Class-Based View. Also, do you even have a model created that you can use for the form and view?
Consult the following docs for an example ListView (and also check the docs about models if you don't have any yet): https://docs.djangoproject.com/en/3.1/ref/class-based-views/generic-display/
Note the difference between a view and a form in general:
from django.views.generic.detail import DetailView
from articles.models import Article
class ArticleDetailView(DetailView):
model = Article
I believe what you want to do is show a model that you have inherited from in your forms.ModelForms. In that case you could just create the model you want to show in your models.py. Then in your forms.py add:
from .models import YourModel
class FormName(forms.ModelForm):
class Meta:
model = YourModel
fields = '__all__'
after that you can use the form you have created in your html by connecting it via your views.py:
from .forms import FormName
def form_page(request):
my_form = FormName()
if request.method == 'POST':
my_form = FormName(request.POST)
if my_form.is_valid():
my_form.save(commit=True)
else:
print('Error Form could not be read')
return render(request, 'path_to/my.html', {'my_form': my_form})
now you can insert the form in your html file by using:
<form method="POST">
{{ my_form.as_p }}
{% csrf_token %}
<input type="submit" value="Submit!">
</form>
The .as_p at the end will make your form look nicer on the webpage.
Be sure to include the csrf_token otherwise it will not work.
Also keep in mind if you want to upload and include images into your model there are a few extra lines of code necessary to make it work.
Now that you have the form in your html to show the models created with the form you will need to first connect the model to your view:
def index(request):
model_items = MyModel.objects.all()
context = {
'model_items': model_items
}
return render(request, "home/index.html", context=context)
then include them in the html where you want to show them. You can easily use for loops to integrate them into your code. For example:
<table>
{% for item in model_items %}
<tr>
<td>
{{ item.property_nr_one }}
</td>
<td>
{{ item.property_nr_two }}
</td>
</tr>
{% endfor %}
</table>
I am getting the following Bootstrap exception
'Parameter "form" should contain a valid Django Form.'
when running the following code from this tutorial:
{% load bootstrap4 %}
<form action="/url/to/submit/" method="post" class="form">
{% csrf_token %}
{% bootstrap_form form %}
{% buttons %}
<button type="submit" class="btn btn-primary">Submit</button>
{% endbuttons %}
</form>
Is the second'form' in 'bootstrap_form form' supposed to reference/point to something? Is it a variable? What is a valid django form? I checked several posts and answers on this issue, but haven't been able to make sense of this error.
EDIT View code:
from django.shortcuts import render
def hello_world(request):
return render(request, 'hello_world.html', {})
I got the same problem and it takes me nearly whole day to figure out.
The Quickstart part of django-bootstrap4 is not very starter-friendly.
{% bootstrap_form form %}
The form is a parameter, which should be transfered from views.py. In your situation, form should be added to return render(request, 'hello_world.html', {})
create a file called forms.py and put following code in it.
(forms.py should be put in the same folder of views.py)
from django import forms
class NameForm(forms.Form):
your_name = forms.CharField(max_length=100)
modify views.py and add the following code:
# ...
from .forms import NameForm
# ...
def hello_world(request):
form = NameForm()
return render(request, 'hello_world.html', {'form': form})
# ...
Currently I am starting to develop a django project which need to provide a HTML page for other students to upload their experiment results which are excel files (maybe CSV), and save them to databases. But I don't know what should I do with the model.py file for each student have diffenent assignments which means the first row of different experiments are not the same. Can anyone help me?
Django 2.1.7
try this
in template
<form method="post" enctype="multipart/form-data">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">Upload</button>
</form>
in forms.py
from django import forms
from .models import YourModel
class YourModelForm(forms.ModelForm):
class Meta:
model = YourModel
fields = ('myfile', )
in views.py
def file_upload(request):
if request.method == 'POST':
form = YourModelForm(request.POST, request.FILES)
if form.is_valid():
form.save()
return redirect('home')
else:
form = DocumentForm()
return render(request, 'template', {
'form': form
})
for more details refer this
hope it helps
I am creating an app that allows anonymous input of data, and have condensed my difficulties down to a simple Author example.
My problem is that each time I input a new author, the number of forms rendered after Submit is increased by N+1 author. (ie the first time used, there is 1 form, then 2, then 3). I only want one blank form to be displayed, and then will later use other apps to retrieve the data.
It seems there could be two ways to solve the problem. 1) Get formset.management_form to return the last form (eg slicing: '{% for form in formset[-1] %}', which does not work. 2) To have view.py only send one new form instead of the formset in render_to_response() - how to do this?
---models.py---
from django.db import models
from django.forms import ModelForm
class Author(models.Model):
first_name = models.CharField(max_length=50)
class AuthorForm(ModelForm):
class Meta:
model = Author
---/models.py---
---views.py---
django.http import HttpResponseRedirect
from django.shortcuts import render_to_response
from django.template import RequestContext
from django.forms.models import modelformset_factory
from author.models import Author , AuthorForm
def manage_authors(request):
AuthorFormSet = modelformset_factory(Author)
if request.method == 'POST':
formset = AuthorFormSet(request.POST)
if formset.is_valid():
formset.save()
else:
formset = AuthorFormSet()
return render_to_response("manage_authors.html",{"formset": formset,})
---/views.py---
---manage_authors.html---
<!DOCTYPE html>
<html lang="en"
<body>
<form action="" method="post">
<table>
{{ formset.management_form }}
{% for form in formset %}
{{ form }}
{% endfor %}
</table>
<button type="submit">Submit</button>
</form>
</body>
</html>
---/manage_authors.html---
---urls.py---
from django.conf.urls import patterns, include, url
from author.views import manage_authors
urlpatterns = patterns('',
url(r"^author/$", manage_authors),
)
---/urls.py---
UPDATE:
Thanks for the suggestions to use modelform. The django docs had only shown template interactions with modelformset. Using:
---views.py---
def manage_authors(request):
form = AuthorForm(request.POST)
if request.method == 'POST':
if form.is_valid():
form.save()
else:
form = AuthorForm()
return render_to_response("manage_authors.html",{"form": form,})
---/views.py
and only using the the tag {{ form }} in manage_authors.html, does what I need.
Try using max_num and extra fields while creating model formset as
AuthorFormSet = modelformset_factory(Author, max_num=1, extra=1)
This will try to show at most 1 form, if there isn't any existing.
However, you may want to think if you really have to use modelformset as #Daniel Roseman suggested.
I have a ModelForm that users can submit to save information to a database. I want to extend it with a ModelFormset so that the user can view and submit the multiple of the same model forms with different information at the same time. However, my POST data isn't binding to the ModelFormset, so the ModelFormset fails as invalid upon is_valid(). I see there is data associated with request.POST.copy(), it just
views.py
def create(request):
if request.method == 'POST':
post_data = request.POST.copy()
print "POST DATA"
print post_data
for i in post_data:
print i
formSet = WorkOrder_Form(post_data)
print "FORMSET"
print formSet
if formSet.is_valid():
formSet.save()
else:
print 'INVALID'
return HttpResponseRedirect('/Shelling/')
else:
formSet = formset_factory(WorkOrder_Form, extra=1)
return render_to_response('create.html',{'WorkOrder_Form':formSet}, context_instance=RequestContext(request))
template: (create.html)
{% load url from future %}
Return to Index </li>
<br>
<br>
<form action="{% url 'create' %}" method="post"> {% csrf_token %}
{% for WorkOrder in WorkOrder_Form %}
{{ WorkOrder.as_ul }}
<br>
{% endfor %}
You are using model forms, so you should use modelformset_factory instead of formset_factory. You can create the formset class outside of the create view. Then, you need to instantiate the formset in the GET and POST branches of your view.
Putting it together, you have the following (untested, so there might be some typos!)
WorkOrderFormSet = formset_factory(WorkOrder_Form, extra=1)
def create(request):
if request.method == 'POST':
post_data = request.POST.copy()
formset = WorkOrderFormSet(data=post_data, queryset=WorkOrder.objects.none())
if formset.is_valid():
formset.save()
else:
print 'INVALID'
return HttpResponseRedirect('/Shelling/')
else:
formset = WorkOrderFormSet(queryset=WorkOrder.objects.none())
return render_to_response('create.html',{'formset':formset}, context_instance=RequestContext(request))
And in the template:
{% for form in formset %}
{{ form.as_ul }}
{% endfor %}