I want to create an update form. When a user enters this page the form should be filled with information so that the user can edit what they want to fix. I try to use instance in views but didn't work. The fields are still empty. How can I do it?
views.py
def setup_settings(request):
user = request.user
data = get_object_or_404(DashboardData, user=user)
# print(data) --> DashboardData object (45)
form = SetupForm(request.POST or None, instance=data)
if request.method == 'POST':
if form.is_valid():
form.save()
else:
form = SetupForm()
context = {
'form': form,
}
return render(request, 'update_setup.html', context)
Basically, in your else block, you have overwritten form with the empty object SetupForm(). When the user will visit the page, it will hit a GET request and your else block will make your form empty, try again after removing it.
Related
I'm trying to get form data using a POST request and save the form data to my database which was created using a django model, which is InfoModel. I'm getting the data from the POST request, but I don't know how to save all of it at once so that it all saves to the same row in the db. The way I'm doing it now, each object from the form saves to a different row of the database which is obviously not useful at all. I expect the answer is simple, but I haven't seen this in the docs.
views.py:
def home(request):
if request.method == 'POST':
# if POST request, validate the data
form = InfoForm(request.POST)
if form.is_valid():
# if the form is valid, collect the data, submit to db, and thank the user
valid = True
form_data = request.POST
f = InfoModel(fname=form_data['fname'])
f.save()
l = InfoModel(lname=form_data['lname'])
l.save()
e = InfoModel(email=form_data['email'])
e.save()
p = InfoModel(phone=form_data['phone'])
p.save()
return render(request, 'form_db/home.html', {'form': form, 'valid': valid})
else:
# if the form is invalid, populate the form with the entered data and show error message
valid = False
form = InfoForm(request.POST)
return render(request, 'form_db/home.html', {'form': form, 'valid': valid})
else:
# if GET request, return blank form as normal
form = InfoForm()
return render(request, 'form_db/home.html', {'form': form})
You can simply, give all fields' names of your InfoModel at once in the following way:
if form.is_valid():
valid=True
fName=form.cleaned_data['fname']
lname=form.cleaned_data['lname']
email=form.cleaned_data['email']
phone=form.cleaned_data['phone']
instance=InfoModel(fname=fName,lname=lname,email=email,phone=phone)
instance.save()
return render(request,"form_db/home.html",{'form': form,'valid':valid})
Note: Models in django doesn't require model to be the suffix, so it will be better if you only give model name Info rather than InfoModel.
Every time you call f = InfoModel() you are instantiating a new instance, and then saving it using f.save(), which is why you are getting so many rows. All this is unnecessary since a form has it's own save() method, which will save all the fields at once into ONE row.
The best way to handle forms is to use the classic Post/Redirect/Get method where if the form data comes in as Post, then you process it and redirect, usually back to the same view, but it can be another view as well. If it is a Get, then you render the blank form.
def home(request):
if request.method == 'POST':
form = InfoForm(request.POST or None)
if form.is_valid():
form.save()
return redirect('home')
return render(request, 'form_db/home.html', {'form':form})
Note the form = InfoForm(request.POST or None), which is handy since it will create a blank form with the None if it is not a Post request, but if it is will fill the form with the data request.POST if it's a Post request.
This is my views function,
def studentcreate(request):
reg = StudentForm()
string = "Give Information"
if request.method == "POST":
reg = StudentForm(request.POST)
string = "Not Currect Information"
if reg.is_valid():
reg.save()
return render('http://localhost:8000/accounts/login/')
context = {
'form':reg,
'string': string,
}
return render(request, 'student.html', context)
Here first we store form in reg variable then also we write reg = StudentForm(request.POST) why?
acutally why we write this?
I can't tell you why you are writing this. Maybe only you know. It does not make much sense. I would recommend reading the Django documentation on this at https://docs.djangoproject.com/en/4.0/topics/forms/#the-view
from django.http import HttpResponseRedirect
from django.shortcuts import render
from .forms import NameForm
def get_name(request):
# if this is a POST request we need to process the form data
if request.method == 'POST':
# create a form instance and populate it with data from the request:
form = NameForm(request.POST)
# check whether it's valid:
if form.is_valid():
# process the data in form.cleaned_data as required
# ...
# redirect to a new URL:
return HttpResponseRedirect('/thanks/')
# if a GET (or any other method) we'll create a blank form
else:
form = NameForm()
return render(request, 'name.html', {'form': form})
You read from data if the request is a POST. Otherwise, return an empty form.
You could think of the "request.POST" as a parameter passed onto the form in the view. This tells the view that the form mentioned has POST data from the form in name.html. Otherwise it is just an empty form.
I have a view, which expects a POST request. The post request should contain data submitted through a Django form.
The Django form looks something like this:
class SubmitForm(forms.Form):
title = forms.CharField(max_length=100)
comment = forms.CharField(max_length=255)
I know I have access to the submitted data with request.POST["title"] and request.POST["comment"]. So I can theoretically check if they're set and valid manually.
But is there a way to use .is_valid() (Link to Django documentation), to validate the submitted form?
One possibility would be to create a form in the view, fill it with the submitted data and then check it for validity.
data = {'title': request.POST["title"],
'comment': request.POST["comment"]}
f = SubmitForm(data)
f.is_valid()
# True/False
Is there a direct way to use is_valid() on a submitted Django form?
You can write view as below:
def verify_view(request):
if request.method == "POST":
form = SubmitForm(request.POST)
if form.is_valid():
# code here if form is valid
else:
form = SubmitForm() # returns empty form to be fill if not post request
return render(request, 'template_form.html', {'form': form})
if request.method == 'POST':
form = PostForm(request.POST or None)
if form.is_valid():
// do your save work
You can pass request.POST as Form argument directly:
form = PostForm(request.POST or None)
if form.is_valid():
....
I have a form, "results", where one of the fields, "subjectID", is many-to-many because there's more than one result for each subject. I want one of the submit buttons to let me save what I've entered, then redirect to the same form, now unbound except that the many-to-many "subjectID" field stays the same so I can enter more results for that subject.
Edit: I should have made it clear that I wanted the instance that I had selected in the subjectID field to stay the same. I posted the code below that actually seems to be working for me
from models.py
class ResultsForm(forms.Modelform):
class Meta:
model = models.Results
fields = ['subjectID', # this is the field want
# to populate the form with when I "save and add another"
'slideNum', # IntegerField
'resultType' ] # ForeignKey
from views.py
def addResults(request):
if request.method == 'POST'
form = ResultsForm(request.POST)
if form.is_valid():
form.save()
if 'Save_and_add_another' in request.POST:
subjectID = form.fields['subjectID']
prepop = {'subjectID' : subjectID}
form = ResultsForm(initial=prepop)
return render(request, 'slideAdmin/addResults.html', {'form': form})
elif 'Save_and_return' in request.POST:
return HttpResponseRedirect('/home/')
else:
form = ResultsForm()
return render(request, 'slideAdmin/addResults.html', {'form': form})
Right now when I click on "save and add another" from my addResults form, I get this error:
TypeError at /slidebox/addResults
'ModelMultipleChoiceField' object is not iterable
which happens when rendering {{ form.as_p }} in the template.
Edit: Changes I made to views.py
if 'Save_and_add_another' in request.POST:
subjectID = form.cleaned_data.get('subjectID')
form = ResultsForm(initial={'subjectID': subjectID})
return render(request, 'slideAdmin/addResults.html', {'form': form})
As far as I can tell, this change works. Thanks again
You should always use form.cleaned_data.get('subjectID') versus pulling the field directly from the post data. You need to pass in a list of the pk's for the M2M field.
Your view can also use a touch of cleanup:
from django.core.urlresolvers import reverse
def addResults(request):
form = ResultsForm(request.POST or None)
if request.method == 'POST' and form.is_valid():
form.save()
if 'Save_and_add_another' in request.POST:
subjectID = form.cleaned_data.get('subjectID', [])
if subjectID:
subjectID = subjectIDs.split(',')
form = ResultsForm(initial={'subjectID': subjectID})
elif 'Save_and_return' in request.POST:
return HttpResponseRedirect(reverse('home')) # don't hard code
return render(request, 'slideAdmin/addResults.html', {'form': form})
I'm not sure if you will be able to keep the form unbound when initialized.
Your form.fields is an ordered dict of django.forms.fields objects. You just want the ids, and not all the other info that comes across it.
Get the data straight from the POST dictionary.
subjectID = request.POST.get('subjectID', '')
If this is a true many to many model. You need to make sure the data is setup correctly for the initialization.
# We have to special-case M2Ms as a list of comma-separated PKs.
if isinstance(f, models.ManyToManyField):
initial[k] = initial[k].split(",")
Here is the initialization method from the django source code for Admin (or as I call it my super detailed and complicated Django cheat sheet, I am pedantic)
def get_changeform_initial_data(self, request):
"""
Get the initial form data.
Unless overridden, this populates from the GET params.
"""
initial = dict(request.GET.items())
for k in initial:
try:
f = self.model._meta.get_field(k)
except FieldDoesNotExist:
continue
# We have to special-case M2Ms as a list of comma-separated PKs.
if isinstance(f, models.ManyToManyField):
initial[k] = initial[k].split(",")
return initial
Some PEP8 nonsense as well
classes are camel case ex: class MyAwesomeClass(object):
everything else is lower with underscores. ex: awesome_id = awesome1245
Good Luck!!
Let's say someone submits a form.
It doesn't pass is_valid(), and I return them back to the template.
How do I display the form fields again, without having the person retype their stuff?
I prefer not to use the { initial: } option.
You could implement your view like so:
def showForm(request):
if request.method == "POST":
form = MyForm(request.POST)
if form.is_valid():
# do stuff on success, like redirection
else:
form = MyForm()
return render_to_response(...,
{"form" : form})
# then in the template, use {{ form.as_table }}, for example