request.method and request.GET in Django - django

I am following a tutorial and I am unable to understand some lines in it:
from django.shortcuts import render, get_object_or_404
from django.http import HttpResponseRedirect
from . models import Page
from .forms import ContactForm
def index(request, pagename):
pagename = '/' + pagename
pg = get_object_or_404(Page, permalink=pagename)
context = {
'title': pg.title,
'content': pg.bodytext,
'last_updated': pg.update_date,
'page_list': Page.objects.all(),
}
# assert False
return render(request, 'pages/page.htm', context)
def contact(request):
submitted = False
if request.method == 'POST':
form = ContactForm(request.POST)
if form.is_valid():
cd = form.cleaned_data
#assert False
return HttpResponseRedirect('/contact?submitted=True')
else:
form = ContactForm()
if 'submitted' in request.GET:
submitted = True
return render(request,'pages/contact.htm',{'form': form, 'page_list': Page.objects.all(), 'sbmitted': submitted})
The above is pages/view.py file
{% extends "pages/page.htm" %}
{% block title %} Contact us {% endblock title %}
{% block content %}
<h1>Contact us</h1>
{% if submitted %}
<p class="success">
Your message was submitted successfully. Thankm you.
</p>
{% else %}
<form action="" method="post" novalidate>
<table>
{{ form.as_table }}
<tr>
<td>&NonBreakingSpace;</td>
<td><input type="submit" value="Submit"></td>
</tr>
</table>
{% csrf_token %}
</form>
{% endif %}
{% endblock content %}
The above is pages/contact.htm file
So, what is the meaning of
if requested.method == 'POST':
and why is there the following check?
if submitted in request.GET:
submitted=True

request.method gives which method is to submit the form so the first
thing checks if the form is submitted with the post method
request.GET returns a context(similar to dictionary in python) of all the variables passed by GET method
And there should be
if request.GET.get('submitted') == "True":
submitted = True
Instead of
if submitted in request.GET:
submitted=True
request.GET.get('submitted') gives value of submitted passed in url
And the thing to note is that both submitted in above code are different the former one is a key in context(similar to dictionary ) and the later one is a variable in views.py

you can send the data via GET or POST. With GET you send the data through the URL. e.g.
www.mydomain.com/Form?Key1=xxxxx&Key2=yyyyyyy
With POST the data is sent "hidden". For example, in a login form you don't want the password to be visible in the url. That's why in these forms is used as a method of sending POST.
if request.method == 'POST': that validates that the data you are sending is in POST format
2.
else:
form = ContactForm()
if 'submitted' in request.GET:
submitted = True
This means that if the sending method was not POST, but GET, look if within the information that was sent there is a submitted parameter and if so, set its value as True.

Related

Context Variable renders the previous value upon refresh

I have created a form that accepts a file upload and fetches some interesting data from the file upon POST.
However, upon refreshing the page, the form is back to its initial state but the data from the previous file remains. How do I fix it?
Here's my code:
forms.py
choices = (('all', 'all'),
('one', 'one'))
class TicketDetailForm(forms.Form):
file = forms.FileField()
type = forms.ChoiceField(choices=choices)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
views.py
def home(request):
detail = []
if request.method == 'POST':
form = TicketDetailForm(request.POST, request.FILES)
if form.is_valid():
if form.cleaned_data['type'] == 'all':
file = form.cleaned_data['file'].read()
detail.append([str(file, 'utf-8')])
# more workaround with the file
else:
form = TicketDetailForm()
return render(request, 'home.html', {'form': form,
'detail': detail})
home.html
{% extends 'base.html' %}
{% block content %}
<form method="post" enctype="multipart/form-data">
{% csrf_token %}
<p>{{form.as_p}}</p>
<input type="submit" value="Submit"/>
</form>
{% if detail %}
<div class="row">
<p>The detail is as follows:</p>
{% for d in detail %}
{{ d }}
{% endif %}
</div>
{% endif %}
{% endblock %}
This is because you re-post the form when you refresh the page, since your view just renders the template even if the form is valid. The proper behaviour for a server is to always redirect after successfully submitting a POST. In other words, inside if form.is_valid() you should end by return redirect('home').
Your views should always do the following:
For a GET request, render the template
For a POST request and invalid form, render the template (with the invalid form so the user can fix errors). Hitting refresh is ok here, it will just re-submit the invalid form and therefore won't cause issues.
For a POST request and valid form, redirect, so that the last request is a GET request and the user cannot re-submit when refreshing. This also avoids the valid form to be rendered again.

django view redirects to URL it shouldn't

I have the following view
def edit_booking(request, pk=None):
if not request.user.is_authenticated:
raise Http404
agent = Agent.objects.get(user=request.user)
booking = get_object_or_404(Booking, pk=pk)
form = BookingForm(request.POST or None, instance=booking)
if form.is_valid():
instance = form.save(commit=False)
instance.save()
return HttpResponseRedirect(instance.get_absolute_url())
elif form.errors:
messages.error(request,"There was a problem, please try again")
context = {
"form": form,
}
return render(request,'booking_form.html', context)
I use the following urls.py
urlpatterns = [
url(r'^booking/create', create_booking, name="create-booking"),
url(r'^booking/$', booking_list, name="booking-list"),
url(r'^booking/(?P<pk>\d+)/$', booking_detail, name="booking-detail"),
url(r'^booking/(?P<pk>\d+)/edit', edit_booking, name="edit-booking"),
]
For some reason when I try to submit the form after editing some booking (e.g. http://127.0.0.1:8000/booking/24/edit) I am automatically redirected to (http://127.0.0.1:8000/booking/24/).
As far as I can tell django is not processing any further code in the view. I tried to figure out with simple print("something") to see where in the code it ends up but it just goes to the url right away as soon as I submit from the template. For completeness sake this is the template:
{% extends 'base.html' %}
<div class="col-sm-6 col-sm-offset 3">
{% block content %}
<form method="POST" action=".">{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Save"/>
</form>
{% endblock %}
</div>
".", which you used as the action of the form, is interpreted by browsers as "the base of the current path directory". Since you have not used a trailing slash in your /edit URL, the browser submits the form to the nearest base, ie /booking/24.
You should always use a trailing slash:
url(r'^booking/create/$', create_booking, name="create-booking"),
url(r'^booking/$', booking_list, name="booking-list"),
url(r'^booking/(?P<pk>\d+)/$', booking_detail, name="booking-detail"),
url(r'^booking/(?P<pk>\d+)/edit/$', edit_booking, name="edit-booking"),
You need to check for the request method otherwise it will redirect on initial form rendering because django uses the same view for initial rendering and submitting the form.
if request.method == 'POST':
if form.is_valid():
instance = form.save(commit=False)
instance.save()
return HttpResponseRedirect(instance.get_absolute_url())
elif form.errors:
messages.error(request,"There was a problem, please try again")
else:
context = {
"form": form,
}
return render(request,'booking_form.html', context)

repeated modelform not validating in modelformset - django

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 %}

Two views in a Django page

I'm having problems displaying the input box of my page. On this same page I would like to have two views, one that accesses and retrieves data and the other a form. As it's an event sign-up page, the first view show the details of a specific event and the second is a view to remove a specific user from the event itself.
My views.py
def ShowSpecificEvent(request, eventslug):
if request.method == 'POST':
form = RemovalForm(request.POST)
if form.is_valid():
event = Event.objects.get(slug=eventslug)
context = {'event': event,}
updated_event = event.signed_up.remove(for_removal = form.cleaned_data['for_removal'],)
updated_event.save()
return render_to_response('base_specific_event.html', context, context_instance=RequestContext(request))
event = Event.objects.get(slug=eventslug)
context = {'event': event,}
return render_to_response('base_specific_event.html', context, context_instance=RequestContext(request))
def Remove(request, eventslug):
if request.method == 'POST':
form = RemovalForm(request.POST)
if form.is_valid():
event = Event.objects.get(slug=eventslug)
context = {'event': event,}
updated_event = event.signed_up.remove(for_removal = form.cleaned_data['for_removal'],)
updated_event.save()
return render_to_response('base_specific_event.html', context, context_instance=RequestContext(request))
return HttpResponseRedirect('base_remove_user.html')
My template
{% block content %}
event details...
{% if user.is_authenticated %}
{% if event.sign_up_is_live %}
<p> Sign me up!</p>
<form action='' method='post'>
{% csrf_token %}
{% if form.errors %}<p>Please correct the following fields:</p>{% endif %}
<div class='register_div'>
{% if form.for_removal.errors %} <p class='error'>{{ form.for_removal.errors }}</p>{% endif %}
<p><label for='for_removal'{% if form.for_removal.errors %}class='error'{% endif %}>User to be removed:</label></p>
<p>{{ form.for_removal }}</p>
</div>
<p><input type='submit'></p>
</form>
{% endif %}{% endif %}
{% endblock %}
I've read this which I think is the most relevant but the method prescribed doesn't really help.
I've also thought of splitting up the two pages, but I won't be able to retrieve the eventslug in my remove user page.
Thanks in advance :)
Update:
gutrt's answer was a great help and I've managed to get the input box to appear by changing ShowSpecificEvent to the following:
def ShowSpecificEvent(request, eventslug):
event = Event.objects.get(slug=eventslug)
form = RemovalForm(request.POST or None)
context = {'event': event, 'form': form,}
if request.method == 'POST':
if form.is_valid():
updated_event = event.signed_up.remove(request.POST.get('for_removal'))
updated_event.save()
return HttpResponseRedirect('base_user_removed.html')
else:
return render_to_response('base_specific_event.html', context, context_instance=RequestContext(request))
return render_to_response('base_specific_event.html', context, context_instance=RequestContext(request))
However, after submitting the form, I get a ValueError(invalid literal for int() with base 10: 'a_technicolor_skye') where a_technicolor_skye is the user I'm trying to remove. Does anyone have any ideas? Btw, event.signed_up is a many to many field and I've set it to null=True and blank=True.
You can pass all of the information into the context variable:
context = {'event': event, 'form': my_form}
Then both are available in your template. Note that this means you are going to end up using 1 view but computing all the information for the page in that view or its methods.

how to edit the user profile

Hi guys I am new to Django.
I wants that when I login to my account there is a edit button which shows me a form of some fields which I can edit.
I am confused how the data is saved to the same user profile.
So can anybody tell me how is that possible.Can show me it with one example
With my profile.html I can see my profile and on click on edit button I can edit my profile
{% extends 'base.html' %}
{% block content %}
<p>User_id: {{ drinker.user_id }}
<p>Name: {{ drinker.name }}</p>
<p>Birthday: {{ drinker.birthday }}</p>
<p>first_name: {{ user.first_name }}</p>
<p>Users: {{ user.username }}</p>
<p>Edit Profile
{% endblock %}
Edit function
def Edit(request):
if not request.user.is_authenticated():
return HttpResponseRedirect('/login/')
drinker = request.user.get_profile()
context = {'drinker':drinker}
return render_to_response('edit.html', context, context_instance=RequestContext(request))
**Edit.html**
{% extends "base.html" %}
{% block extrahead %}
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.8.0/jquery.min.js" type="text/javascript"></script>
<script src="//ajax.googleapis.com/ajax/libs/jqueryui/1.8.23/jquery-ui.min.js" type="text/javascript"></script>
<script>
$(function() {
$( "#birth" ).datepicker();
});
</script>
{% endblock %}
{% block content %}
<form action="/edit1/" method="post">
{% csrf_token %}
<div class="register_div">
<p><label for="name">Name:</label></p>
<p><input type="text" value="{{ drinker.name }}"></p>
</div>
<div class="register_div">
<p><label for="birthday">Birthday: {{ drinker.birthday }} </label></p>
<p>Choose new date of birth</p>
<p><input type="text" value="" id="birth"></p>
</div>
<p><input type="submit" value="submit" /></p>
</form>
{% endblock %}
On edit1 edit request function works
def EditRequest(request):
#if request.method == 'POST':
#form = UserProfileForm(request.POST, instance=user)
#if request.user.is_authenticated():
#return render_to_response('hgdhg')
if request.method == 'POST':
form = EditForm(request.POST)
if form.is_valid():
user=User.objects.create_user(usere_id=form.cleaned_data['user_id'])
#user.save()
drinker=user.get_profile()
drinker.name=form.cleaned_data['name']
drinker.birthday=form.cleaned_data['birthday']
drinker.save()
return HttpResponseRedirect('/profile/')
else:
return HttpResponseRedirect('/f/')
else:
return render_to_response('f')#,{'form':form} , context_instance=RequestContext(request))
this editrequest doesn't work ?
Here are the steps you need to execute to edit a user's profile:
Find out which user is logged in (read up on user authentication)
Check if the user has a profile or not; use the normal django query mechanism for that.
If the user has a profile; populate a ModelForm with the instance of the profile (see this page in the manual)
Display the form to the end user just like any other form.
When the user submits changes, do the normal form validation and save the object to the database.
Here is some code that does steps 1-4:
from django.shortcuts import render, redirect
from django.contrib.auth.decorators import login_required
from myapp.models import UserProfile
from myapp.forms import UserProfileForm
#login_required
def edit_profile(request):
try:
user_profile = UserProfile.objects.get(user=request.user)
except UserProfile.DoesNotExist:
# this user has no profile
return redirect('/error')
user_profile_form = UserProfileForm(instance=user_profile)
return render(request,'profile_edit.html',{'form':user_profile_form})
The UserProfileForm class:
from django import forms
from myapp.models import UserProfile
class UserProfileForm(forms.ModelForm):
class Meta:
model = UserProfile
pass the instance of user along your model form
user = User.objects.get(user_name = username)
form = Registrationform(instance=user)
and render this form to your template
Example i did before:
#login_required
def lexuseditform(request,userpk):
if Adult.objects.filter(user=request.user).exists():
adult = Adult.objects.get(user=request.user) # load existing Adult
else:
adult = Adult(user=request.user) # create new Adult
if request.method == 'POST': # If the form has been submitted...
form = AdultForm(request.POST,instance=adult) # A form bound to the POST data
if form.is_valid(): # All validation rules pass
form.save()
redirect_url = reverse('lexusedited',kwargs={'userpk': request.user.pk})
return HttpResponseRedirect(redirect_url) # Redirect after POST
else:
form = AdultForm(instance=adult) # An unbound form
return render(request,'lexus/lexuseditform.html', {'form': form})
#login_required
def lexusedited(request,userpk):
return render(request,'lexus/lexusedited.html')
Hope this helps...