I'm confused with how django adds elements to a list. consider the following:
def add(request):
if request.method == "POST":
form = NewTaskForm(request.POST)
if form.is_valid():
task = form.cleaned_data["task"]
request.session['tasks'].append(task)
# request.session['tasks'] += [task]
return HttpResponseRedirect(reverse("tasks:index"))
else:
return render(request, "tasks/add.html",{
"form": form
})
return render(request, "tasks/add.html",{
"form": NewTaskForm()
})
if we add a print statement after request.session['tasks'].append(task) we get a list:
['check email']
we also get the same list if we comment the append line and use the correct way with +=
However, on the redirect to task/index the first way shows an empty list and the second way shows the list that's expected. Why? Whats going on?
Django only saves the session data and sends to client if it has been assigned or deleted. Like in your second example:
request.session['tasks'] += [task]
If you are updating the information inside your session data, it will not recognize the change and won't update it, like when you append some data to the list that is assigned to the 'tasks' key. In this case you need to explicitly tell Django that you modified the session data using:
request.session.modified = True
Related
Currently, I have a view that essentially closes a lead, meaning that it simply copies the information from one table (leads) to another (deals), now what I really would like to do is that after clicking close, the user is redirected to another page where the user can update some entries (sales forecast), I have a view that updates the lead, so I thought that I can do something like below:
#login_required
def close_lead(request):
id = request.GET.get('project_id', '')
keys = Leads.objects.select_related().get(project_id=id)
form_dict = {'project_id': keys.project_id,
'agent': keys.agent,
'client': keys.point_of_contact,
'company': keys.company,
'service': keys.services,
'licenses': keys.expected_licenses,
'country_d': keys.country
}
deal_form = NewDealForm(request.POST or None,initial=form_dict)
if request.method == 'POST':
if deal_form.is_valid():
deal_form.save()
obj = Leads.objects.get(project_id=id)
obj.status = "Closed"
obj.save(update_fields=['status'])
## Changing the Forecast Table Entry
forecast = LeadEntry.objects.filter(lead_id=id)
for i in forecast:
m = i
m.stage = "Deal"
m.save(update_fields=['stage'])
messages.success(request, 'You have successfully updated the status from open to Close')
update_forecast(request,id)
else:
messages.error(request, 'Error updating your Form')
return render(request,
"account/close_lead.html",
{'form': deal_form})
This view provides the formset that I want to update after closing the lead
#login_required
def update_forecast(request,lead_id):
# Gets the lead queryset
lead = get_object_or_404(Leads,pk=lead_id)
#Create an inline formset using Leads the parent model and LeadEntry the child model
FormSet = inlineformset_factory(Leads,LeadEntry,form=LeadUpdateForm,extra=0)
if request.method == "POST":
formset = FormSet(request.POST,instance=lead)
if formset.is_valid():
formset.save()
return redirect('forecast_lead_update',lead_id=lead.project_id)
else:
formset = FormSet(instance=lead)
context = {
'formset':formset
}
return render(request,"account/leadentry_update.html",context)
As you can see I’m calling this function update_forecast(request,id) after validating the data in the form, and I would have expected to be somehow redirected to the HTML page specified on that function, however, after clicking submit, the form from the first view is validated but then nothing happens, so I'm the function doesn't render the HTML page
My question how can I leverage existing functions in my views?, obviously, I will imagine that following the DRY principles you can do that in Django, so what am I doing wrong ?, how can I call an existing function within another function in views?
A view returns a response object. In your current code, you're calling a second view but not doing anything with its response. If you just wanted to display static content (not a form that might lead to an action that cares about the current URL) you could return the response object from the second view - return update_forecast(request, id).
But since your second view is displaying a form, you care about what the action for the view from the second form is. The typical Django idiom is to have forms submit to the current page's URL - that wouldn't work if you just call it and return its response object. You could customize the action in the second view, say adding an optional parameter to the view, but the usual idiom for form processing is to redirect to the view you want to show on success. Just as you do in the update_forecast view. Something like this:
messages.success(request, 'You have successfully updated the status from open to Close')
return redirect('update_forecast', lead_id=id)
I need to loop through all field objects of a model in Django. Once I look through I need to detect if in any of the entries of data this specific field(type) is equal to "Date1". If it is I need it to send a variable(val) that is a string equal to "True" to the Django templates. I have everything set and it seems simple and it seems like it should work. On its own, the val can send a value to the template when it is not in an if statement and the for loop also properly works. Even when "Date1" exists as a value in the type field of an entry in the model "Field_Repo1" the val isn't sent and the if statement is never iterated through(I know this by using prints). No matter what the if statement is never run through. Code Below. Thanks in advance.
context = {}
context['Field_Repo1'] = Field_Repo1.objects.filter(user=response.user)
for type1 in Field_Repo1.objects.values_list('type'):
if type1 == "Date1":
val = "True"
context['val'] = val
print(val)
print(AHHHHHHHHHHHH)
if response.method == 'POST':
form = Field_Repo1_Form(response.POST, response.FILES)
if form.is_valid():
instance = form.save(commit=False)
instance.user = response.user
instance.save()
response.user.Field_Repo1.add(instance)
return redirect('repo1')
else:
form = Field_Repo1_Form()
context['form'] = form
return render(response, 'sheets/add_fields/repo1_add_field.html', context)
The values_list() function returns a queryset of tuples. The statement in your for loop if type1 == "Date1": is trying to compare equality between "Date1" and a tuple, which will never be true. The tuples in the query set all are of length 1 since you only passed a single field to the values_list() function, so you should be able to do if type1[0] == "Date1": for your comparison.
There's lots of documentation about Django and the reverse() method. I can't seem to locate my exact problem. Suppose I have two urlconfs like this:
url(r'ParentLists/$', main_page, name = "main_page"),
url(r'ParentLists/(?P<grade_level>.+)/$', foo, name = "foo")
and the two corresponding views like this:
def main_page(request):
if request.method == 'POST':
grade_level = request.POST['grade_picked']
return HttpResponseRedirect(reverse('foo', args = (grade_level,)))
else:
return render(request, 'index.html', context = {'grade_list' : grade_list})
def foo(request, grade_level):
grade_level = request.POST['grade_picked']
parent_list = # get stuff from database
emails = # get stuff from database
return render(request, 'list.html', context = {'grade_list' : grade_list, 'parent_list' : parent_list})
Here, list.html just extends my base template index.html, which contains a drop down box with grade levels. When the user goes to /ParentLists, the main_page view renders index.html with the drop down box as it should.
When the user picks a grade level from the drop down box (say 5th Grade), the template does a form submit, and main_page once again executes - but this time the POST branch runs and the HttpResponseRedirect takes the user to /ParentLists/05. This simply results in an HTML table pertaining to grade 5 being displayed below the drop down box.
The problem is, when the user now selects say 10th Grade, the table updates to show the grade 10 content, but the URL displayed is still /ParentLists/05. I want it to be /ParentLists/10.
Clearly, after the first selection, the main_page view never executes again. Only foo does...and so the HttpResponseRedirect never gets called. How should I reorganize this to get what I'm looking for? Thanks in advance!
As you correctly mentioned you will never redirect to foo() from foo().
So the simple way to fix this is just add similar code as in main_page() view:
def foo(request, grade_level):
if request.method == 'POST':
grade_level = request.POST['grade_picked']
return HttpResponseRedirect(reverse('foo', args = (grade_level,)))
else:
parent_list = # get stuff from database
emails = # get stuff from database
return render(request, 'list.html', context = {'grade_list' : grade_list, 'parent_list' : parent_list})
Please note that I remove grade_level = request.POST['grade_picked'] because as Nagkumar Arkalgud correctly said it is excessively.
Also instead of combination of HttpResponseRedirect and reverse you can use shortcut redirect which probably little easy to code:
from django.shortcuts redirect
...
return redirect('foo', grade_level=grade_level)
I would suggest you to use kwargs instead of args.
The right way to use the view is:
your_url = reverse("<view_name>", kwargs={"<key>": "<value>"})
Ex:
return HttpResponseRedirect(reverse('foo', kwargs={"grade_level": grade_level}))
Also, you are sending "grade_level" to your view foo using the URL and not a POST value. I would remove the line:
grade_level = request.POST['grade_picked']
as you will override the grade_level sent to the method from the url.
i created a form to save a post into db for my blog project. I've designed index page. now i am tryin to create a form to create new posts. before that i was using ' manage.py shell'
here is my view :
def addpost(request):
form = addForm()
if request.method=="POST":
titleform = request.POST['title']
bodyform = request.POST['body']
checkform = request.POST['isdraft']
if form.is_valid():
n = Post(title = titleform, body = bodyform, isdraft=checkform)
n.save()
return HttpResponseRedirect('/admin/')
else:
pass
return render(request,'userside/add.html',{'form':form,})
my model.py:
class Post(models.Model):
title = models.CharField(max_length = 100)
body = models.TextField()
slug = AutoSlugField(populate_from='title',unique=True)
posted = models.DateField(auto_now_add=True)
isdraft = models.BooleanField()
def __unicode__(self):
return self.title
#permalink
def get_absolute_url(self):
return ('view_blog_post',None, {'postslug':self.slug})
class addForm(forms.Form):
title = forms.CharField(max_length=100)
body = forms.CharField(widget=forms.Textarea)
isdraft = forms.BooleanField()
if i submit form as 'isdraft' field is False(unchecked) ; it gives error like:
MultiValueDictKeyError at /admin/addpost/
"Key 'isdraft' not found in "
and if i submit the form as 'isdraft' field is True(checked) ; it gives nothing. just refreshing form. no adding data into db.
i am doing sth wrong..
thank you
edit : Dmitry Beransky's answer worked for checkbox error. but it still doesnt add any data into db. just refreshes the form.
The whole point of using a form is that it takes care of validation and cleaning, that is converting values to the proper data types. That's why you should be accessing form.cleaned_data rather than reques.POST, and you should be doing it inside the if form.is_valid() check.
Edit
I've just noticed that you're never passing request.POST to the form. So form.is_valid() will never be true.
Please go back and read the documentation about using a form in a view.
If a checkbox is not checked in your HTML form, it's name/value is not going to be included in the data that the browser sends to your server. Which meanst that the request.POST dictionary is not going to contain an entry for 'isdraft' which in turn will cause a key error when you try to read the isdraft value. A solution is to change the way you read the value from the posted data to:
checkform = request.POST.get('isdraft', False)
rather than throw an error if isdraft isn't found in the dictionary, this will set checkform to False (the default value in case of a missing key)
Maybe your form does not validate at all. Have you checked if your code even reaches those lines after the if form.is_valid() statement ? If they do, what you've done there is right and should create the db row for your new entry, though you could have used
Post.objects.create(....) , and that would have taken away the need for calling the method save().
Some points though:
instead of checking for request.POST , check for request.method == 'POST' , cause there might be a post which has an empty POST dict ( in case no arguments have been submitted ), in that case request.POST fails to provide the right check .
see the docs for more info : request.POST
instead of using request.POST['var_name'] , use request.POST.get('var_name', 'default_value') , cause doing this like request.POST['var_name'] might result in some exceptions ( in case for example the argument is not provided , like what happened for your checkform variable )
Try accessing those variables through form.cleaned_data
and finally , you don't need the else statement in the end , just use the indentation :)
I have a page that can be viewed by list or grid view through jQuery, but I want the URL to display what view it is -- especially when user paginate so that they don't have to reclick what they want to view -- so something like this: /test/?grid_view or /test/?list_view.
I've been trying to use request.GET.get, but it doesn't seem to be working. Here is what I have so far:
def test (request):
grid_view = request.GET.get('grid_view')
list_view = request.GET.get('list_view')
if grid_view:
return render_to_response('grid_view.html', {}, context_instance=RequestContext(request))
elif list_view:
return render_to_response('list_view.html', {}, context_instance=RequestContext(request))
else:
return render_to_response('default_view.html', {}, context_instance=RequestContext(request))
Then in my main template I'd point the different views to list view, etc. There is probably a better way to do it so any suggestions are appreciated too.
An empty string is evaluated to False and, that is what your GET request Query String parameters will contain.
You could modify your code to:
if 'grid_view' in request.GET or 'grid_view/' in request.GET:
pass
elif 'list_view' in request.GET or 'list_view/' in request.GET:
pass
Or:
if request.GET.has_key('grid_view') or request.GET.has_key('grid_view/'):
# ...
That's not a GET parameter. Use request.META['QUERY_STRING'] to get the query string.