Django - Passing parameters from template to view not working - python

I'm trying to get my hands dirty with django and I started trying to make my own project. I'm currently having trouble passing parameters from my template to my views without using POST requests.
heres my code in the template
#in main.html
<div>
{{ event_results }}
{{ friends }}
</div>
{% for user in results %}
<div class="userblock">
<p class="user">{{ user.username }}</p>
<a href="/events/addFriend/{{user.username}}">
<button class="navbuttons" id="addfriend">Add as friend</button>
<a/>
</div>
{% endfor %}
#in urls.py
from django.conf.urls import patterns, url
from events import views, eventview
url(r'^addFriend/(<requested_friend>[a-z]*)/', views.addFriend, name='addFriend'),
)
#in views.py
def addFriend(request, requested_friend):
currentUser = User.objects.get(username=request.session['username'])
try:
list_of_friends = Friends.objects.get(username=currentUser)
except (KeyError, Friends.DoesNotExist):
return render(request, 'events/main.html', {'friends': requested_friend})
else:
return render(request, 'events/main.html', {'friends':list_of_friends})
So when I click on the button "Add friend" in main.html, it goes to the url.py and maps it to the function addFriend in views.py with the argument and from there it does its magic. However, it's not taking in the argument. I know I'm doing something wrong in the urls.py with the regex but im not sure what. Any advice is greatly appreciated. Thanks!

When you change (<requested_friend>[a-z]*) to (?P<requested_friend>[0-9A-Za-z_\-]+) than everything looks fine.
But remember to use + instead of * in the pattern. * matches also a empty string (addFriend// is matched) but with + the string must have at least one character (addFriend// isn't matched)
You can add $ on the end of url pattern r'^addFriend/(?P<requested_friend>[0-9A-Za-z_\-]+)/$' Here you can find why.
Also check if link in browser has correct value /events/addFriend/<user_name>/ maybe is something wrong with {{ user.username }}

You have error in urls.py. In named group pattern you miss ?P prefix. See doc for reference.
Instead of
url(r'^addFriend/(<requested_friend>[a-z]*)/', views.addFriend, name='addFriend'),
It should be:
url(r'^addFriend/(?P<requested_friend>[a-z]*)/', views.addFriend, name='addFriend'),

Related

How to set a variable from within a template

My layout template contains a header and I'd like to add a CSS class to the currently selected menu option.
class="active"
I thought I found the solution here but I'm still having issues. When I paste the following code into my template I get a server error.
{% rule = request.url_rule %}
Why didn't this work? How can I set a variable to control the menu in the templates?
{% rule = request.url_rule %} is not valid syntax in Jinja. If you want to set a context variable from a template, use set:
{% set rule = request.rule %}
request is already passed to each template context automatically, you don't need to pass it in render_template.
My best guess would be that the request object isn't getting passed to the template. If it isn't being passed you wouldn't be able to access it when rendering the template. You could pass it explicitly, which would look something like this:
from flask import request
from flask import render_template
#app.route('/hello/')
def hello():
return render_template('hello.html', request=request)
Someone commented that swankswashbucklers answer wouldn't fix my problem so I'm posting my solution which was inspired by his suggestion.
I simply manually set a variable called title when creating the view.
def home():
return render_template(
'index.html',
title='Home',
)
Within the template I referenced the variable to decide which menu item to highlight.
{% if title == "Home" %}
<li class="active">
{% else %}
<li>
{% endif %}
It turned out in my situation I didn't need to access the current url.

Django context not rendering

I've got a Django template in HTML. I would like to pass a variable to this template using a context. However, when I render the template Django fills the spaces that reference this variable with the string specified by the TEMPLATE_STRING_IF_INVALID setting (I tested this).
Here's the relevant URLconf:
from django.conf.urls import patterns, url
from users import views
urlpatterns = patterns('',
url(r'^$', views.users),
url(r'(?P<pk>\d+)/$', views.userdetail),
)
and here's the view it references:
from django.template import RequestContext, loader
...
def userdetail(request, pk):
user = get_object_or_404(User, pk=pk)
template = loader.get_template('users/userdetail.html')
context = RequestContext(request, {'user': user})
return HttpResponse(template.render(context))
I'm fairly certain it's due to a syntax error in specifying the context but after looking at it for an hour I can't find one. I'm happy to post additional code if you think it may be relevant. Can anyone spot my mistake?
Template for those interested:
{% if error_message %}<p><strong>{{ error_message }}</strong></p>{% endif%}
<h1> You are viewing the page for the individual user {{ user.name }} </h1>
This user has created the following posts:
{% for post in user.post_list %}
{{ post.title }}</li>
{% endfor %}
<p>
Created on {{ user.creation_date }}
</p>
The OP wrote:
My supervisor just came around and fixed it really quickly. The issue is that templates have some predefined keywords. User is one of these keywords so django was upset that I was passing it {'user':user} in the context. Changing to {'customuser':user} avoids the collision with the django keyword and fixes this issue.

How can I include a "* required field." message in all forms with required fields?

I'm using django-crispy-forms with CRISPY_TEMPLATE_PACK = 'bootstrap3'. My templates looks like this (this is an example of the sign up form, but I have a lot of forms in my templates):
{% load crispy_forms_tags %}
<h1>Sign up</h1>
<form action="/accounts/signup/" method="POST" role="form">
{% csrf_token %}
{{ form|crispy }}
<button type="submit" class="btn btn-primary">Sing up</button>
</form>
In the rendered pages, the required fields appear correctly with an * near it to indicate that they are required, but no message appears explaining what an * means.
In my case, I'm dealing with users that are sometimes not very tech-firendly, so they might not know what an * means. I would like to show a * required field. message in the top of all forms with required fields.
I could put a <p>* required field.</p> line in the beginning of each form, but I would like to know if there is a more elegant and DRY way to do it.
Thank you!
You can override the uni_form.html template with a custom one.
https://github.com/maraujop/django-crispy-forms/blob/dev/crispy_forms/templates/bootstrap3/uni_form.html
According to the django crispy forms documentation:
https://django-crispy-forms.readthedocs.org/en/latest/crispy_tag_forms.html#change-required-fields
You will need to override the field template, that is your only option, unless you use a css hack (maybe something :before and :after for the asterisk element).
Your other option is to use the HTML crispy forms element, to make a notice at the top of your form:
HTML('<strong>Fields marked with * are required</strong>')
One solution would be to either add <p class="req_legend" style="display: none;">* required field.</p> to every form and add a js which changes its display property if required fields are found.
Here is a jquery example:
$(document).ready(function() {
if ($('.requiredField').length > 0) {
$('p.req_legend').show();
}
});
Or go full javascript and add <p> element to your only if you find a requiredField, you can than do this in a javascript that you add to the Media class of your forms

Django Paginator not working beyond first page

As mentioned in the title, my paginator doesn't show anything when I click to go to a page beyond the first.
First, let me describe my page in general:
Its function is to get a request input from the user specifying the period interval from which he wants to see a bunch of "call records" along with other filters (this is important). So essentially there's a start and end date from the request and I use it to filter my objects.
The link to "page2" is something like: "localhost:8000/?page=2" and redirects to my existing page but without any data. It's obvious now that the link to the next page should include the other parameters such as start_date=xxxx-xx-xx, or else it wouldn't work.
Here's part of my view.py and I took out a lot of lines to make it brief, the code runs fine:
if request.GET:
filter_form = ReportFilterForm(request.GET)
if filter_form.is_valid():
start = filter_form.cleaned_data["start_date"]
end = filter_form.cleaned_data["end_date"]
#a bunch of omitted lines that use the form to filter
paginator = Paginator(queryset, 100)
try:
page = int(request.GET.get('page', '1'))
except ValueError:
page = 1
try:
call_logs = paginator.page(page)
except (EmptyPage, InvalidPage):
call_logs = paginator.page(paginator.num_pages)
else:
filter_form = ReportFilterForm()
return render_to_response('xxxx.html',
{'queryset': queryset,
'filter_form': filter_form,
'call_logs': call_logs,
})
My template xxxx.html, just the paginator section, which is pretty standard, taken from the documentation:
{% if call_logs.paginator.num_pages %}
<div class="pagination">
<span class="step-links">
{% if call_logs.has_previous %}
<<
{% endif %}
<span class="current">
Page {{ call_logs.number }} of {{ call_logs.paginator.num_pages }}
</span>
{% if call_logs.has_next %}
>>
{% endif %}
</span>
</div>
{% endif %}
My question is how do I get the current window URL using django templates and not javascript?
Thank you.
You could add the full path to the context from the request object if I understand you correctly:
return render_to_response('xxxx.html',
{'queryset': queryset,
'filter_form': filter_form,
'call_logs': call_logs,,
'magic_url': request.get_full_path(),
})
My question is how do I get the
current window URL using django
templates and not javascript? Thank
you.
it's not necessary the right way to do it, but you can check this post
but i will suggest that you shouldn't mix the filter with the pagination.
rather that you can use AJAX when doing filtering you can create a new function that deal with filtering alone or you can just use the same function and test if request.is_ajax(): , like that when a users filter the contain you will have your filter data (start_date,end_date ) in the URL.
and now when a user want to pass to the next page you already have the filtered argument in the url that you can use to create a queryset that will be pass to the Paginator.
And to deal with the javascript not active you can replace AJAX with a simple POST form and just remember don't mix the filtering with the pagination :)
Hope this will Help :)

Django 1.0, using default password reset

I'm trying to use the password reset setup that comes with Django, but the documentation is not very good for it. I'm using Django 1.0 and I keep getting this error:
Caught an exception while rendering: Reverse for 'mysite.django.contrib.auth.views.password_reset_confirm' with arguments '()' and keyword arguments ...
in my urlconf I have something like this:
#django.contrib.auth.views
urlpatterns = patterns('django.contrib.auth.views',
(r'^password_reset/$', 'password_reset', {'template_name': 'accounts/registration/password_reset_form.html', 'email_template_name':'accounts/registration/password_reset_email.html', 'post_reset_redirect':'accounts/login/'}),
(r'^password_reset/done/$', 'password_reset_done', {'template_name': 'accounts/registration/password_reset_done.html'}),
(r'^reset/(?P<uidb36>[0-9A-Za-z]+)-(?P<token>.+)/$', 'password_reset_confirm', {'template_name': 'accounts/registration/password_reset_confirm.html', 'post_reset_redirect':'accounts/login/', 'post_reset_redirect':'accounts/reset/done/'}),
(r'^reset/done/$', 'password_reset_complete', {'template_name': 'accounts/registration/password_reset_complete.html'}),
)
The problem seems to be in this file:
password_reset_email.html
on line 7
{% url django.contrib.auth.views.password_reset_confirm uidb36=uid, token=token %}
I'm at loss as to what's going on, so any help would be appreciated.
Thanks
Edit: I used your example, and had to change to not use keyword parameters.
{% url django.contrib.auth.views.password_reset_confirm uid, token %}
Named parameters do work, as long as both uid and token are defined. If either are not defined or blank I get the same error you do:
{% url django.contrib.auth.views.password_reset_confirm uidb36=uid, token=token %}
Just wanted to post the solution I came up with. The problem was in this line:
{% url django.contrib.auth.views.password_reset_confirm uidb36=uid, token=token %}
I'm not really a 100% why either, so I just hard coded the url like this:
http://mysite.com/accounts/reset/{{uid}}-{{token}}/
I've struggled with this for over an hour trying everything on this page and every other page on the internet. Finally to solve the problem in my case i had to delete
{% load url from future %}
from the top of my password_reset_email.html template.
Also note, "uidb36=uid" in the url script. Here's my full password_reset_email.html template, I hope it saves someone some time:
{% autoescape off %}
You're receiving this e-mail because you requested a password reset for your user account at {{ site_name }}.
Please go to the following page and choose a new password:
{% block reset_link %}
{{ protocol }}://{{ domain }}{% url django.contrib.auth.views.password_reset_confirm uidb36=uid token=token %}
{% endblock %}
Your username, in case you've forgotten:" %} {{ user.username }}
Thanks for using our site!
The {{ site_name }} team
{% endautoescape %}
This is a problem I figured out myself not 10 minutes ago. The solution is to add the post_change_redirect value to the dictionary of arguments you are passing to the password_reset view.
So this is what mine now look like:
(r'^/password/$', password_change, {'template_name': 'testing/password.html', 'post_change_redirect': '/account/'})
I hope that does it for you! I agree that the documentation for this particular feature is lacking somewhat, but this solved the exact same issue for my project.
Edit: I really should have scrolled across - you've included that already. Apologies for that, but I hope you get it sorted :)

Categories

Resources