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.
Related
So I created a model form but it's not showing in the page but it's registered on the django admin site.views.py[forms.py
(https://i.stack.imgur.com/Z3qud.png)models.py
the error I keep getting
I tried creating the models using django shell
views.py
from django.shortcuts import render, redirect
from django.contrib import messages
from .forms import AttendeeForm
# Create your views here.
def attendees_reg(request):
form = AttendeeForm()
if request.method == 'POST':
form = AttendeeForm(request.POST)
if form.is_valid():
form.save()
messages.success(request, 'Data Has been Saved')
return redirect('/attendees')
return render(request, "templates/attendees_reg.html", {'form':form})
forms.py
from django.forms import ModelForm
from .models import Attendee
class AttendeeForm(ModelForm):
class Meta:
model = Attendee
fields = "all"
template
</h1> <hr>
{% for message in messages %}
<p>{{message}}</p>
{% endfor %}
<form action="" method="POST">
{% csrf_token %}
{{ form.as_p }}
<input type="submit">
</form>
You need to be correct "__all__" instead of "all"
class AttendeeForm(ModelForm):
class Meta:
model = Attendee
fields = "__all__"
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 beginner of Django. When i submit in the html page, is_valid funtion in my views.py always returns false. users.html is my template. I obviously filled things correctly but it still returns false.
Any help would be welcome.
this is my models.py file
from django.db import models
# Create your models here.
class User(models.Model):
first_name = models.CharField(max_length=264, )
last_name = models.CharField(max_length=264, )
email = models.EmailField(max_length=255,)
def __str__(self):
return self.first_name + self.last_name
this is my forms.py file
from django import forms
from first_app.models import User
from django.forms import ModelForm
class User_form(ModelForm):
class Meta:
model = User
fields = ['first_name','last_name','email']
this is my views.py file
from django.shortcuts import render
from django.http import HttpResponse
from . import forms
from first_app.models import User
# Create your views here.
def index(request):
return render(request,'index.html')
def user_form_view(request):
form = forms.User_form()
if request.method == 'POST':
if form.is_valid():
form = forms.User_form(request.post)
form.save()
return index(request)
else:
print(form)
return user_show(request)
return render(request,'first_app/users.html',{'form':form})
and this is my users.html
<!DOCTYPE html>
{% load static %}
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8">
<title>Users</title>
</head>
<body>
<h1>Hello! please type in your information</h1>
<div class="container">
<form class="" method="POST">
{{form.as_p}}
{% csrf_token %}
<input type="submit" class="btn btn-primary" value="submit">
</form>
</div>
</body>
</html>
In order for a form to be valid, it needs to be "bounded" (you can check this with .is_bounded [Django-doc]). Bounded means that you passed data to it, for example with request.POST (or request.GET, or another dictionary-like container):
def user_form_view(request):
if request.method == 'POST':
form = forms.User_form(request.POST)
if form.is_valid():
form.save()
return index(request)
else:
print(form)
return user_show(request)
else:
form = forms.User_form()
return render(request,'first_app/users.html',{'form':form})
Note: the names of classes are typically written in PerlCase, not snake_case, so you probably should rename User_form to UserForm.
I am getting the following error on running my django code. I am an absolute beginner and I was following a tutorial to create a crud app.
On typing the information in my html form I get the following error
ValueError: Cannot assign django.contrib.auth.models.AnonymousUser object at 0x00000288775D3EF0: "Note.user" must be a "User" instance
from form.instance.user = request.user in my views.py
views.py
from django.shortcuts import render
from django.shortcuts import render, redirect
from .models import Note
# Create your views here.
from .forms import NoteModelForm
# CRUD - create update retrieve and delete
def createView(request):
form = NoteModelForm(request.POST or None, request.FILES or None)
if form.is_valid():
form.instance.user = request.user
form.save()
return redirect('/')
context = {
'form': form
}
return render(request, "create.html", context)
forms.py
from django import forms
from .models import Note
class NoteModelForm(forms.ModelForm):
class Meta:
model = Note
fields = ['title','url','image']
create.html
<!DOCTYPE html>
<html>
<head>
<title>CRUD APP</title>
</head>
<body>
<form method="POST" enctype="multipart/form-data">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" name="submit">
</form>
</body>
</html>
If the user is not logged in, request.user gives AnonymousUser, which can't be assigned to the form instance.
To avoid this situation, you may add a condition before accessing the view. For this, you may use login_required decorator, as shown below
from django.contrib.auth.decorators import login_required
#login_required
def createView(request):
....
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