Does request.session["name"] in Django creates a new list? - python

What does it mean when we write request.session["tasks"] and assign it to something in django views? Like in the script below in the index function request.session["tasks"] = [ ],does that mean an empty list named tasks has been created for that particular session? and if so, where exactly all these session details are stored in django? and also what does cleaned_data["task"] in the add function is exactly doing in this script? I tried looking in the documentation but couldn't find any satisfactory information about this, so I'm sorry if this sounds a little stupid but I'm new to django and sometimes the syntax really confuses me,Any help is appreciated!
from django.shortcuts import render
from django import forms
from django.http import HttpResponseRedirect
from django.urls import reverse
# Create your views here.
class NewTaskForm(forms.Form):
task = forms.CharField(label = "New Task",min_length=8,max_length=16)
priority = forms.IntegerField(label="Priority",min_value=1,max_value=5)
def index(request):
if "tasks" not in request.session:
request.session["tasks"] = []
return render(request,"index.html",
{
"tasks":request.session["tasks"]
})
def add(request):
if request.method == "POST":
vari = NewTaskForm(request.POST)
if vari.is_valid():
task = vari.cleaned_data["task"]
request.session["tasks"] += [task]
return HttpResponseRedirect(reverse("index"))
else:
return render(request,"other.html",
{
"form":vari
})
return render(request,"other.html",{
"form" : NewTaskForm()
})

Yes, It means an empty list named tasks has been created for that particular session. and django stores the session data in 'django_session' table.
cleaned_data is used for validating the data.
# This line is used to pass the validated data from the form input.
task = vari.cleaned_data["task"]

Related

Populate Python object with Django Form

I am trying to use a Django form to populate a Python object (not a Django model).
I have the feeling I can only either:
build a simple form and populate manually
use a Django model as proxy
The extra difficulty is the form send a GET request
The class
class Search:
def __init__(self):
self.min_area = 0
self.max_area = 999
The form
from django import forms
class MainSearchForm(forms.Form):
min_area = forms.IntegerField(label="Minimum", required=False)
max_area = forms.IntegerField(label="Maximum", required=False)
The view
from django.http import HttpResponse
from django.template import loader
from front.forms.search.main import MainSearchForm
from front.gears.search import Search
def main(request):
search = Search()
form = MainSearchForm(request.GET, {})
# manual populating i want to avoid
if form.has_changed() and form.is_valid():
search.min_area = form.cleaned_data['min_area']
search.max_area = form.cleaned_data['max_area']
tpl = loader.get_template('front/search/main.html')
ctx = {
'form': form,
'search': search
}
return HttpResponse(tpl.render(ctx, request))
For now, I am populating manually in the view but I am quite sure there is a better way to do it.
Am I missing a part of the documentation ?
You can use setattr:
for key in form.cleaned_data:
setattr(search, key, form.cleaned_data[key])

Django Haystack Custom Search Form

I've got a basic django-haystack SearchForm working OK, but now I'm trying to create a custom search form that includes a couple of extra fields to filter on.
I've followed the Haystack documentation on creating custom forms and views, but when I try to view the form I can only get the error:
ValueError at /search/calibration/
The view assetregister.views.calibration_search didn't return an HttpResponse object. It returned None instead.
Shouldn't basing this on SearchForm take care of returning a HttpResponse object?
forms.py
from django import forms
from haystack.forms import SearchForm
class CalibrationSearch(SearchForm):
calibration_due_before = forms.DateField(required=False)
calibration_due_after = forms.DateField(required=False)
def search(self):
#First we need to store SearchQuerySet recieved after / from any other processing that's going on
sqs = super(CalibrationSearch, self).search()
if not self.is_valid():
return self.no_query_found()
#check to see if any date filters used, if so apply filter
if self.cleaned_data['calibration_due_before']:
sqs = sqs.filter(calibration_date_next__lte=self.cleaned_data['calibration_due_before'])
if self.cleaned_data['calibration_due_after']:
sqs = sqs.filter(calibration_date_next__gte=self.cleaned_data['calibration_due_after'])
return sqs
views.py
from .forms import CalibrationSearch
from haystack.generic_views import SearchView
from haystack.query import SearchQuerySet
def calibration_search(SearchView):
template_name = 'search/search.html'
form_class = CalibrationSearch
queryset = SearchQuerySet().filter(requires_calibration=True)
def get_queryset(self):
queryset = super(calibration_search, self).get_queryset()
return queryset
urls.py
from django.conf.urls import include, url
from . import views
urlpatterns = [
....
url(r'^search/calibration/', views.calibration_search, name='calibration_search'),
....
]
Haystack's SearchView is a class based view, you have to call .as_view() class method when adding a urls entry.
url(r'^search/calibration/', views.calibration_search.as_view(), name='calibration_search'),
This helped me.
"removing the "page" prefix on the search.html template did the trick, and was a good temporary solution. However, it became a problem when it was time to paginate the results. So after looking around, the solution was to use the "page_obj" prefix instead of "page" and everything works as expected. It seems the issue is that the haystack-tutorial assumes the page object is called "page", while certain versions of django its called "page_obj"? I'm sure there is a better answer - I'm just reporting my limited findings."
See this: Django-Haystack returns no results in search form

Passing form data from my view to thank you page

Is there a way I can pass data from a form submission over to the 'thank you' page. The reason i'd like to do this is because I have a form on the website, where the user will select multiple fields which all contains different PDF's.
So once the user has submitted the form the idea is to re-direct them to a thankyou page, where they can view the list of pdf/files they have selected on the form.
I hope this is enough info to go on. Here are my views / models.
def document_request(request, *args):
# template = kwargs['name'] + ".html"
if request.method == 'POST':
form = forms.ReportEnquiryForm(request.POST)
print(request.POST)
if form.is_valid():
docrequest = form.save()
return HttpResponseRedirect(reverse('thank_you', kwargs={'id': docrequest.id}))
else:
form = forms.ReportEnquiryForm()
return render_to_response('test.html',{'form':form})
def thank_you(request):
docrequest = DocumentRequest.objects.get(pk=id)
return render_to_response('thankyou.html',
{'docrequest' : docrequest },
context_instance=RequestContext(request))
My initial idea was to pass the data to a new view called thank_you. But not this is possible.
class DocumentUpload(models.Model):
name = models.CharField(max_length="200")
document_upload = models.FileField(upload_to="uploads/documents")
def __unicode__(self):
return "%s" % self.name
class DocumentRequest(models.Model):
name = models.CharField(max_length="200")
company = models.CharField(max_length="200")
job_title = models.CharField(max_length="200")
email = models.EmailField(max_length="200")
report = models.ManyToManyField(DocumentUpload)
def __unicode__(self):
return "%s" % self.name
form.py
class ReportEnquiryForm(forms.ModelForm):
class Meta:
model = models.DocumentRequest
fields = ('name', 'company', 'job_title', 'email', 'report')
If you need anymore info, please ask :)
You've saved the user's submission in a DocumentRequest object. So you can pass the ID of that object in the URL when you redirect, and in the thank_you view you can get the DocumentRequest and render the list.
Edit The idea is to make the thank_you page like any other view that accepts a parameter from the URL:
url(r'thanks/(?P<id>\d+)/$, 'thank_you', name='thank_you')
and so the POST part of the form view becomes:
if form.is_valid():
docrequest = form.save()
return HttpResponseRedirect(reverse('thank_you', kwargs={'id': docrequest.id}))
and thank_you is:
def thank_you(request, id):
docrequest = DocumentRequest.objects.get(pk=id)
return render_to_response('thankyou.html',
{'docrequest' : docrequest },
context_instance=RequestContext(request))
Second edit
As others have suggested, this makes it possible for anyone to see the request. So a better solution is to put it in the session:
docrequest = form.save()
request.session['docrequest_id'] = docrequest.id
and in thank_you:
def thank_you(request):
if not 'docrequest_id' in request.session:
return HttpResponseForbidden
docrequest = DocumentRequest.objects.get(request.session['docrequest_id'])
You can do as Daniel Roseman said but in this case the thank you pages can be accessed by anyone with the Ids.
Some ways to pass data between views are the following(the list is not mine.):
GET request - First request hits view1->send data to browser -> browser redirects to view2
POST request - (as you suggested) Same flow as above but is suitable when more data is involved
Using django session variables - This is the simplest to implement
Using client-side cookies - Can be used but there is limitations of how much data can be stored.
Maybe using some shared memory at web server level- Tricky but can be done.
Write data into a file & then the next view can read from that file.
If you can have a stand-alone server, then that server can REST API's to invoke views.
Again if a stand-alone server is possible maybe even message queues would work.
Maybe a cache like memcached can act as mediator. But then if one is going this route, its better to use Django sessions as it hides a whole lot of implementation details.
Lastly, as an extension to point 6, instead of files store data in some persistent storage mechanism like mysql.
The simplest way is to use sessions. Just add the id to the session and redirect to the thank you view, you read the id value and query the db with that id.

POST in django. How does a user update?

I'm brand new to django and fairly new to programming in general. I've done the django tutorial and searched the web for an answer to this question, but to no avail, so now I'm here. I am confused how post works with django. All of the tutorials I've looked at how have a return function in views that displays the webpage. I get that. But then how does a user update data if the page is being rendered from that return statement? After the return there can't be any more updates because the function stops, right? What am I missing here? Any help would be greatly appreciated, I'm getting fairly desperate here.
One pattern for Django views (by no means the only pattern) is to check the request method (GET or POST) at the beginning of the view. If it is POST, then handle the incoming data (before the view returns), and then return either a rendered template, or a redirect.
def view_function(request):
if request.method == 'POST':
if data_is_valid(request.POST):
save_data(request.POST)
return HttpResponseRedirect('/somewhere/good')
else:
return render('template', {'errors': what_went_wrong}
else:
return render('template')
The user updates data in the logic of the view function. That is to say, if the user wishes to update something, you place the update logic in the view function before the return. For example, you would do this:
def update(request):
item = <some model>.objects.get(<something>)
<more code>
return <something>
Usually an edit view function contains two parts -- one for updating data, and the other for displaying the update form. For example,
def user_edit(request):
if request.method == 'POST': # is this a save action?
# save the user data
user_id = request.POST.get('user_id')
username = request.POST.get('username')
description = request.POST.get('description')
user = User.objects.get(id=user_id)
user.username = username
user.description = description
user.save()
return HttpResponseRedirect('/user/') # redirect to index
else:
# show the edit form
user_id = request.GET.get('user_id')
user = User.object.get(id=user_id)
return render_to_response('/user/edit.html', { 'user': user })
There are many different choices for the if request.method == 'POST' line. You can also use if request.POST.get('user_id') to check if specified field is set, to determine if this is a save action.

Django form is throwing error: "takes exactly 1 argument (0 given)"

I'm working on a basic event form created from a model, but I keep getting the following error message:
TypeError at /addlaundry/
addlaundry() takes exactly 1 argument (0 given)
I think it's because I'm not passing the argument through on views, but I can't find documented anywhere how to do this right, at least not written in a way I understand.
Here is my urls.py:
urlpatterns = patterns('',
url('^addlaundry/$', 'beacon.laundry.views.addlaundry'),
}
And the views itself:
# Create your views here.
from schedule.views import EventForm
def addlaundry(request):
if request.method == 'POST':
form = EventForm(request.POST)
if form.is_valid():
return HttpResponseRedirect('/thanks/') #redirect after succesfully adding new delivery
else:
form = addlaundry()
return render_to_response('newlaundry.html', {
'form': form,
})
Do I indeed have my views wrongly structured, or am I missing something else? If there's documentation I need to read up on, I want to I just haven't found it but feel like I'm missing something basic.
Thanks,
Michael
The problem is here:
form = addlaundry()
You're calling your view function addlaundry which takes 1 required argument (request), but you're not passing it any arguments.
Of course, that's not the right way to construct a form, anyway. You'll want to take a look at the examples given in the Django forms documentation to see how to create and use forms in Django.
Your view is called addlaundry, and it calls (presumably) something else called addlaundry. Rename one of them, or use the other addlaundry from inside its namespace.
This is your problem:
form = addlaundry()
That's attempting to call the view itself! That's not what you want. You need to define a form class and call (instantiate) it here.
views.py :
from schedule.forms import EventForm
def addlaundry(request):
if request.method == 'POST':
form = EventForm(request.POST)
if form.is_valid():
return HttpResponseRedirect('/thanks/')
else:
form = EventForm()
return render_to_response('newlaundry.html', {
'form': form,
})
That means :
using a forms.py file to define your forms
initializing your form in a non post context (regular first page load), that will be passed to your template
Also, in urls.py your view should not be a string.
else:
form = addlaundry()
Just as the exception says: The view function needs 1 argument, but you didn't supply any.

Categories

Resources