Django csrf forbidden on url variation - django

Hi I have an html template for switching languages on my site:
<form action="{{ SITE_URL }}i18n/setlang/" name="postlink" method="post">{% csrf_token %}
<ul class="lang">
<li class="lang">
{% for lang in LANGUAGES %}
{% if lang.0 != LANGUAGE_CODE %}
<input type="hidden" name="language" value="{{ lang.0 }}">
<a class="active" href=# onclick="submitPostLink()">{{ lang.1 }}</a>
{% else %}
{{ lang.1 }}
{% endif %}
{% if forloop.last %}{% else %} | {% endif %}
{% endfor %}
</li>
</ul>
</form>
All this works fine on the dev server and in production and in production at the normal url of www.mysite.com/project/
However, if I try project.mysite.com or mysite.com.project I get my home page as normal but changing the language brings up the 403 Forbidden failure.
Do I need to define the root url variations I need for setlang somewhere?
Any help much appreciated.

Since these urls are running on different subdomains, you should check the domain setting for the CSRF cookie CSRF_COOKIE_DOMAIN: https://docs.djangoproject.com/en/1.3/ref/contrib/csrf/#subdomains

Related

Django URL Translation - Stay on the same page when changing language

I developped a Django app with i18n for urls as well.
That look really nice but when changing the language I would like to stay on the same/previous page.
What is the best way of doing that ?
Basically to get the new url I need to do a reverse on the name of the previous page after having changed the language and do a redirect but how can I know the url name of the previous page?
Edit:
A solution that came from a collegue:
Calculate a next parameter for each language using request.resolver_match.
For each language : activate(language) + reverse('{app_name}:{url_name}', args, kwargs) using request.resolver_match elements
Do you see a better idea?
After change language with django-modeltranslation redirecting to home ?
If you want to redirect to the same page, you can replace this part of code:
{% get_current_language as LANGUAGE_CODE %}
{% get_available_languages as LANGUAGES %}
{% get_language_info_list for LANGUAGES as languages %}
<div class="languages">
<p>{% trans "Language" %}: </p>
<ul class="languages">
{% for language in languages %}
<li>
<a href="/{{ language.code }}/
{% if language.code == LANGUAGE_CODE %} class="selected"{% endif %}>
{{ language.name_local }}
</a>
</li>
{% endfor %}
</ul>
</div>
to:
{% get_current_language as LANGUAGE_CODE %}
{% get_available_languages as LANGUAGES %}
{% get_language_info_list for LANGUAGES as languages %}
<div class="languages">
<p>{% trans "Language" %}: </p>
<ul class="languages">
{% for language in languages %}
<li>
<a href="/{{ language.code }}/{{request.get_full_path|slice:"4:"}}"
{% if language.code == LANGUAGE_CODE %} class="selected"{% endif %}>
{{ language.name_local }}
</a>
</li>
{% endfor %}
</ul>
</div>
Attention please:
<a href="/{{ language.code }}/
replaced to <a href="/{{ language.code }}/{{request.get_full_path|slice:"4:"}}"
Two options for you:
Option 1
If you use the form from the documentation then will take you which brings you back to the page you were on.
Option 2
When changing the language you could use the referrer header, HTTP_REFERER , and redirect back to where you came from
# Change the language
# ... code ...
# Redirect back to where we came from
redirect_to = request.META.get('HTTP_REFERER', reverse('default-redirect-page'))
return HttpResponseRedirect(redirect_to)

Django authentication acting weird. Working "some times", not always

I'm having some trouble with Django's authentication system. I've managed to set up a login page, logout page and a basic profile page. Now I'm trying to restrict different areas on the site to only authenticated users. It works on some templates, and not on others.
The weirdest, maybe, is that it works/not works in the same template.
This is base.html:
<div id="account">
{% if user.is_authenticated %}
Hello, {{ user.username }}! | Log out
{% else %}
Log in
or
Sign up
{% endif %}
</div>
<div id="sidebar">
{% if user.is_authenticated %}
<h3 id="plus" style="padding-top: 20px;">Sign up!</h3>
Log in
{% else %}
<div style="margin-top: 45px">
Profile
</div>
{% endif %}
</div>
Works in the account-div, but not in the sidebar-div.
Any suggestions?
You have
{% if user.is_authenticated %}
<h3 id="plus" style="padding-top: 20px;">Sign up!</h3>
Log in
{% else %}
why does he have to sign up if he's logged in?
You can try {% if not user.is_authenticated %}

django - Invalid block tag: 'add_pinned_status', expected 'else' or 'endif'

I get the following error when serving my django application using Nginx+FastCGI
Invalid block tag: 'add_pinned_status', expected 'else' or 'endif'
Oddly, the site works just fine when I'm serving using the Django development server. It also works with Nginx most of the time, but the error randomly appears and reappears with refreshes. Any idea what the problem could be?
EDIT: Here's the code, just to clarify that there's NO hanging if statement.
{% extends 'master.html'%}
{% load thumbnail %}
{% load tags %}
{% block 'title' %}
{{ title }}
{% endblock %}
{% block 'content' %}
<div id="feed" class="content">
{% for book in books.object_list %}
<div class="book_preview">
<div class="thumbnail">
<a href="/book/{{ book.id }}/{{ book.get_slug }}/">
{% if book.cover_image %}
{% thumbnail book.cover_image "120" as im %}
<img src="{{ im.url }}" alt="Python for Software Design"/>
{% endthumbnail %}
{% else %}
<img src="{{ STATIC_URL }}default_thumb.jpg" alt="Python for Software Design"/>
{% endif %}
</a>
</div>
<div class="book_details">
<h2 class="book_title">
<a class="book_profile_link" href="/book/{{ book.id }}/{{ book.get_slug }}/">{{ book.title }}</a>
{% if user != book.uploader %}
<a class="shelf_adder {% add_pinned_status request book.pk %}" href="/shelf/{{ book.id }}/toggle/?next={{ request.get_full_path }}" title="Toggle shelf status"></a>
{% endif %}
</h2>
<h3 class="book_subtitle">
{% if book.subtitle %}
{{ book.subtitle }}
{% else %}
<a href='/book/{{book.id}}/edit/#subtitle'>Provide subtitle</a>
{% endif %}
</h3>
<h3 class="book_authors"> by {{ book.author.filter|join:", " }}</h3>
<div class="book_description">
{% if book.description %}
<p>
{{ book.description|truncatewords:25 }}
</p>
{% else %}
<p class="message">No description available. Create one.</p>
{% endif %}
</div>
<div class="book_links">
<a href="/book/{{ book.id }}/{{ book.get_slug }}/" class="book_profile_link" title="Book profile">
Book profile
</a>
<a href="http://{{ book.homepage }}" class="book_website_link" title="Book website" target="_blank">
Book website
</a>
</div>
<p>Points: {{ book.shelf_additions }}</p>
<div class="book_tags">
{% if book.topics.all %}
{% for topic in book.topics.filter %}
{{ topic }}
{% endfor %}
{% else %}
<a href="/book/{{ book.id }}/edit/#topics" title='Click to add'>no topics added☹</a>
{% endif %}
</div>
</div>
<div style="clear: both;"></div>
</div>
{% endfor %}
<div class="pagination">
{% if books.has_previous %}
previous
{% endif %}
<span class="current">
Page {{ books.number }} of {{ books.paginator.num_pages }}
</span>
{% if books.has_next %}
next
{% endif %}
</div>
</div>
{% endblock %}
The problem starts on the line after the if user != book.uploader statement, which as you can see is terminated with the appropriate endif. I suspect it may be some sort of timeout but I'm not entirely sure. Keep in mind, it works sometimes but randomly stops when using Nginx. It works flawlessly with the dev server.
Django gives that error when you have an unclosed templatetag. In this case an {% if ... %} templatetag.
As to why it only happens in certain scenarios, it might be inside a conditional tag itself, so it's not always processed, but I think Django processes the whole template despite what's going on conditionally or not. It might also be possible that there was some mistake in updating your production site and it's using a different/older version than your development site.
Regardless, the error is the error. Find the unclosed templatetag, and you'll solve it across the board.
UPDATE: The alternative is that the add_pinned_sites templatetag is undefined. Assuming it is in fact loaded in {% load tags %}, make sure that that templatetag library is available in all running environments, i.e. it literally exists on the server. If it is in fact there, make sure you completely reload your Nginx+FastCGI environment, or just reboot the server to be completely sure.
Is "tags" the actual name of the tag library that holds add_pinned_sites? Might be worth changing it to a clearer name-- just wondering if it's possible you're seeing import collisions between that and another tag library (like Django's built-in tags).

Django: Redirect after posting a comment

I am trying to redirect the user back to the page where the comment was posted. I found this post on Django's site but I am doing something wrong because it won't redirect back.
Where should the input be placed to have it properly redirected?
{% load comments i18n %}
<form action="{% comment_form_target %}" method="post">{% csrf_token %}
{% if next %}<input type="hidden" name="next" value="{{ next }}" />{% endif %}
{% for field in form %}
{% if field.is_hidden %}
{{ field }}
{% else %}
{% if field.errors %}{{ field.errors }}{% endif %}
<input type="hidden" name="next" value="{% url proposal proposal.id %}" />
<p
{% if field.errors %} class="error"{% endif %}
{% ifequal field.name "honeypot" %} style="display:none;"{% endifequal %}
{% ifequal field.name "name" %} style="display:none;"{% endifequal %}
{% ifequal field.name "email" %} style="display:none;"{% endifequal %}
{% ifequal field.name "url" %} style="display:none;"{% endifequal %}
{% ifequal field.name "title" %} style="display:none;"{% endifequal %}>
<!-- {{ field.label_tag }} -->{{ field }}
</p>
{% endif %}
{% endfor %}
<p class="submit">
<!-- <button><input type="submit" name="post" value="{% trans "Send" %}" /></button> -->
<button type="submit">Send</button>
<!-- <input type="submit" name="preview" class="submit-preview" value="{% trans "Preview" %}" /> -->
</p>
</form>
Maybe you don't need to check for next variable in your template. You could try changing:
{% if next %}<input type="hidden" name="next" value="{{ next }}" />{% endif %}
to just:
<input type="hidden" name="next" value="/added/comment/page/" />
In case you use views.py, redirecting from there seems more obvious, at least for me, as it helps keep the concern away from the template:
from django.http import HttpResponseRedirect
HttpResponseRedirect("/path/to/redirect")
The problem with axel22's answer is that it requires a change to each template that requires the comment form - if you have multiple object types that can be commented on, this is not DRY.
Unfortunately, I'm also still looking for an answer that works.
if you are using {% render_comment_form for object %} tag in your template, just add something like {% url object's_named_view object.id as next %} or wrap it with {% with object.get_absolute_url as next %} ... {% endwith %} construction.
See my solution here: Django: Redirect to current article after comment post
It basically uses a view that's triggered by the comment post url which redirects back to the original referrer page.

django url tag performance

I was trying to integrate django-voting into my project following the RedditStyleVoting instruction.
In my urls.py, i did something like this:
url(r'^sections/(?P<object_id>\d+)/(?P<direction>up|down|clear)vote/?$',
vote_on_object,
dict(
model=Section,
template_object_name='section',
template_name='script/section_confirm_vote.html',
allow_xmlhttprequest=True
),
name="section_vote",
then, in my template:
{% vote_by_user user on section as vote %}
{% score_for_object section as score %}
<form class="sectionvote" id="sectionup{{ section.id }}"{% if vote and vote.is_upvote %} action="{% url section_vote object_id=section.id, direction="clear" %}"{% else %} action="{% url section_vote object_id=section.id, direction="up" %}"{% endif %} method="POST">
<input type="image" id="sectionuparrow{{ section.id }}" src="{{ MEDIA_URL }}/aup{% if vote and vote.is_upvote %}mod{% else %}grey{% endif %}.png"></form>
{{ score.score|default:0 }}
<form class="sectionvote" id="sectiondown{{ section.id }}"{% if vote and vote.is_downvote %} action="{% url section_vote object_id=section.id, direction="clear" %}"{% else %} action="{% url section_vote object_id=section.id, direction="down" %}"{% endif %} method="POST">
<input type="image" id="sectiondownarrow{{ section.id }}" src="{{ MEDIA_URL }}/adown{% if vote and vote.is_downvote %}mod{% else %}grey{% endif %}.png"></form>
It takes over 1.3s to load the page, but by hard coding it like this:
<form class="sectionvote" id="sectionup{{ section.id }}"{% if vote and vote.is_upvote %} action="sections/{{section.id}}/clearvote/"{% else %} action="sections/{{section.id}}/clearvote/"{% endif %} method="POST">
<form class="sectionvote" id="sectiondown{{ section.id }}"{% if vote and vote.is_downvote %} action="sections/{{section.id}}/clearvote/"{% else %} action="sections/{{section.id}}/downvote/"{% endif %} method="POST">
I got 50ms. Just avoid the url tag resolving stuff I got a 20+ times performance improvement.
Is there something I did wrong? If not, then what's the best practice here, should we do things the right way or the fast way?
If you're using the development version, there has recently been a regression which has massively increased the time it takes to reverse-lookup URLs - see the ticket here. It is scheduled to be fixed before the final release of 1.2.