Still new to python and django, though learning ;-)
I have a view that is intended to display a form with contact information. After succesfully processing the form and saving/creating the object, I want to display the same view again (to add another contact) but with a message added saying the previous contact information was successfully saved.
From Django return redirect() with parameters I learned that the way to redirect to a view with a passed parameter is to simply call the view again and display the response.
My view starts as follows:
def addabentry(request, entrytype, messages=[]):
""" Presents form to create a company listing, then enters company into database"""
After postback and successfully saving the data, I call the view again as follows:
messages = ["%s %s has been added." % (entrytype, entry.name)]
response = addabentry(request, entrytype=entrytype, messages=messages)
return HttpResponse(response)
However, the form on the second go-round seems to be bound with the previous data, presumably because the POST parameter is still in the request object I pass to the view.
Is there a way to unbind the form for the second time around? Or, as is more likely, is there a better way of doing what I want? Do I need to use request.sessions as mentioned in the referenced SO question?
Thanks for your help!
W.
You need messages framework.
i think you may be making things a lot more complicated than they need to.
from the basic form example in the docs
def contact(request):
message = ''
if request.method == 'POST': # If the form has been submitted...
form = ContactForm(request.POST) # A form bound to the POST data
if form.is_valid(): # All validation rules pass
# Process the data in form.cleaned_data
# ...
# instead of redirecting here, create a new blank form, and add a message
form = ContactForm()
message = "contact successfully created"
else:
form = ContactForm() # An unbound form
return render_to_response('contact.html', {
'form': form,
'message': message,
})
Related
I am trying to create a simple one item product store, in which customers would go to a product page and choose the quantity they would like to purchase in a form. After completing the form, I would then like for it to redirect to the checkout page and render the quantity they chose. Is there a simple way to do this? At the moment, I am posting the form data to the product page url and then redirecting the user to the checkout page, however I am unsure how to access that data.
def proxy_detail(request, proxy_slug):
if request.method == 'POST':
form = forms.AddProxyAmountForm(request.POST)
if form.is_valid():
cd = form.cleaned_data
number_of_proxies = int(cd['number_of_proxies'])
return redirect('payment:checkout')
else:
add_proxy_form = forms.AddProxyAmountForm()
proxy_product = get_object_or_404(models.ProxyProduct, slug = proxy_slug)
return render(request, 'shop/product/proxy_detail.html', {'proxy_product' : proxy_product, 'add_proxy_form' : add_proxy_form })
Its not an exact answer but I am new here so I can't really comment :p
Anyways, I think in your view, what you can do is, get the data in a variable and pass it as a context to render another page.
def viewname(request):
if request.method == "POST":
#your logic to save here
context = {variableOfInterest : request.POST.valueOfInterest} #considering you are getting it from the form
return render(request, "redirected.html", context)
I'm trying to learn Django and have come up with a situation I can't figure out. I have the following code:
def contact_add(request):
if request.method == 'POST':
form = ContactManageForm(request.POST)
if form.is_valid():
if form.has_changed(): # <-- ALWAYS RETURNS TRUE!
form.clean()
...
elif 'id' in request.GET: # Request to show an existing contact
new_contact_dynamic = contacts.models.PersonDynamic.objects.get(person_static = request.GET['id'],
current_record_fg = True)
form = ContactManageForm(new_contact_dynamic.__dict__, initial=new_contact_dynamic.__dict__)
else: # This must be to add a new contact
form = ContactAddForm()
return render(request, 'contact_manage.html', {'form': form})
So, if I'm sent an ID number, I read a record and display it on the screen. My template gives the user a 'submit changes' button. My problem, as noted above, is that Django always shows that the form has changed, even if the user hasn't changed any data on the screen (i.e. he just hit the submit changes button without changing anything).
So, am I doing something obviously wrong in my code that's creating this situation? Am I misinterpreting how the form.has_changed() method works?
It's my assumption that when I use the initial=parameter after a GET request, Django is storing that data somewhere and knows the context when the user then hits the 'submit data' button, is this wrong?
Yes you need to initialize your Form with initial data.
In your view the GET and POST requests have no common context. You may want to use sessions for that.
But in this case, it is not necessary. You can retrieve the instance on each request:
def contact_add(request):
if 'id' in request.GET:
new_contact_dynamic = contacts.models.PersonDynamic.objects.get(
person_static = request.GET['id'],
current_record_fg = True
)
if request.method == 'POST':
form = ContactManageForm(request.POST, initial=new_contact_dynamic.__dict__)
...
else: # Show an existing contact
form = ContactManageForm(initial=new_contact_dynamic.__dict__)
else:
form = ContactAddForm()
return render(request, 'contact_manage.html', {'form': form})
In the Django documentation on Forms, it explains how to pass data to a new form you are creating.
For example
data = {'subject': 'hello',
'message': 'Hi there',
'sender': 'foo#example.com',
'cc_myself': True}
f = ContactForm(data)
But why would you ever want to do this? Isn't the whole point of creating a form to solicit new data? If you are putting in the data, why not just enter it directly into the model?
It's not the idea, the idea is to describe the Form API, generally we instantiate the format without passing data to render an empty form in the GET request, and with user's data after user submit the given form. You will write some code like that:
if request.method == "GET":
form = ContactForm()
elif request.method == "POST":
form = ContactForm(request.POST)
Because, as that same documentation says, the primary purpose of a form is for validation. So you pass the data to be validated, and the form determines the errors.
I'm starting to learn django and started watching tutorials on how to create forms and i've seen a lot of places where the form is created like this.
def create(request):
if request.POST:
form = ArticleForm(request.POST)
if form.is_valid:
form.save()
else:
form = ArticleForm()
args = {}
args.update(csrf(request))
args['form'] = form
return render_to_response('create_article.html', args)
Now, assuming that I created a model called Article and then created an ArticleForm from that model, what exactly is going on here (in the code I provided above)? I understand the if form.is_valid: form.save() part, and according to what I read, request should always be the first parameter, but can someone explain what request as a parameter does and what the first two lines of the function are doing? And what exactly is going on in the else statement and after the else statement (the args part)?
EDIT: Also, suppose the Article model has a field called name = models.CharField(max_length=20), is there a way for me to get / access what the user entered for that particular section of the form? Suppose I want to get the name and see if the name already exists in my database, would there be a way for me to do that?
request.POST among other things (like the CSRF token value) contains all the data the user has entered in the form.
if request.POST
checks if the user actually validated the form, otherwise there is no POST data in the request.
form = ArticleForm(request.POST)
looks strange at first but when the user validates the form, the same page is loaded but the POST data is processed in the django form for data validation (like checking if a required field was left blank, etc…) in order to display errors in the form.
If there is no error (form.is_valid()) then the view program continues.
I hope you are familiar with HTTP methods like GET and POST.
request object represents a single request by any user agent. So it can be a request that's sent from browser from you when you browse a particular page or from a crawler from a search engine. Read more about request here
request.POST is an attribute of this request object, it's a QueryDict (much similar to a normal Python dict). It contains the HTTP POST parameters that are sent to your view.
In short in your example:
def create(request):
if request.POST: # check if the request is POST request and it contains any parameter
form = ArticleForm(request.POST) # then pass all those parameters to the form
if form.is_valid: # process the form to check if it's valid
form.save() # save the data if it's valid
else:
form = ArticleForm() # if not valid data, initialize an new / empty form
args = {} # create a dict to pass to the template
args.update(csrf(request)) # add the CSRF token
args['form'] = form # add the 'form' above to the 'args' dict
return render_to_response('create_article.html', args) # pass that dict to template
Not so sure why you have this example, normally I would do the last part like this:
def create(request):
.... your code ....
else:
form = ArticleForm()
return render(request, 'create_article.html', { form: form })
Hope it helps.
There are some mistakes in the code and it seems it's copy-pasted from a SO question. I would recommend going through the excellent Django documentation, especially the Django tutorial.
Your example should rather look like this example from the Django docs.
Here are some comments:
def create(request):
if request.POST:
form = ArticleForm(request.POST)
if form.is_valid:
form.save()
# after successful POST
# we want to redirect to a different page here
else:
form = ArticleForm()
args = {}
# you really don't need the following necessarily
# just use `{% csrf_token %}` inside the form in your template
args.update(csrf(request))
args['form'] = form
# using just `render` like in the example linked to above is more modern
return render_to_response('create_article.html', args)
Hy there,
i just read here that posted data can't be sent by a redirect,
and then found that people are generally not happy with using redirects. And my question is why?
My situation
I have a Django app which starts by rendering a page which gives the choice of using Registered or Anonymous usage.
def start(request):
request.session.flush()
return render_to_response('start.html')
If Registered usage is chosen a simple form is rendered to insert the registration data, and it loops to itself until form is valid after which 'auth/' takes place.
def registration(request):
if request.method == "POST":
form = RegistrationForm(request.POST)
if form.is_valid():
return HttpResponseRedirect('auth/')
else:
return render_to_response('registration.html',
{'form':form})
form = RegistrationForm()
return render_to_response('registration.html',
{'form':form})
If anonymous usage is chosen, the registration page is skipped, and is redirected to 'auth/', the same Django view function like in upper code:
return HttpResponseRedirect('auth/')
What i was hoping to achieve with auth is for it to just set the sessions, write the data to a database and then redirect the next page which is identical to Registered and Anonymous users (only the sessions would differ).
def auth(request):
ipdb.set_trace()
if request.method == "POST":
request.session['user_type'] = 'REG'
request.session['email'] = request.POST['email']
request.session['first_name'] = request.POST['first_name']
RegisteredUser.objects.create(first_name = request.POST['first_name'],
email = request.POST['email'],
company = request.POST['company'])
else:
request.session['user_type'] = 'ANONIM'
return HttpResponseRedirect('next_page')
Of course, when the debugger starts, request.method always returns GET.
My reasons
There is a lots of talking about separating the view from the logic, and i don't find it very readable or loosely coupled when i have a Django view function (if I drop the 'auth/', 'next_page' would have to take it's functionality) which has to
Check for request.post
If there if the reason for it is form validation of the current page, or if it's from the previous page, in which case write that data to a base
Do additional checks to set the sessions for registered or anonymous user
which I would have to do since using separated functions just for logic that redirects instead of rendering doesn't seem as the generally accepted way.
Can someone please shed some light on things?
UPDATE WITH SOLUTION
Thanks to the answers i figured out the pattern on how to do this. The code for registration is now:
def registration(request):
if request.method == "POST":
form = RegistrationForm(request.POST)
if form.is_valid():
request.session['user_type'] = 'REG'
request.session['email'] = request.POST['email']
request.session['first_name'] = request.POST['first_name']
RegisteredUser.objects.create(first_name = request.POST['first_name'],
email = request.POST['email'],
company = request.POST['company'])
return HttpResponseRedirect('param_select/')
else:
return render_to_response('registration.html',
{'form':form},
context_instance = RequestContext(request))
form = RegistrationForm()
return render_to_response('registration.html',
{'form':form},
context_instance = RequestContext(request))
From now on, I'm using the "Loop into yourself with POST data, and then perform the logic" method.
To demystify the name, thats what the new registration(request) does.
First it renders the form to input the data
Than it is recalled once the data is submitted because of link to itself
form action="" method="post"
This is repeated until correct form data isn't submitted after which the logic is called (in this case, writing to a base and setting the sessions).
It ends with a httpRedirect to a different page leaving the registration completely handled by registration(request).
By default you can assume that user is anonymous and set request.session['user_type'] = 'ANONIM' in your start() view.
Whatever you are doing in auth() you can do it in registration() along with request.session['user_type'] = 'REG'. With this you can use the validated form to create RegisteredUser and flag errors as well if required.
And once POST processing is valid and complete it can redirect to your next_page.
If anonymous user is chosen, start will redirect to next_page rather than auth/