I am having problems with user authentication for my django site. I have a log-in screen that seems to work. When the user clicks log-in, I call the django.contrib.auth.login and it seems to work fine. However on subsequent pages have no knowledge that there is a user logged in. Example {% user.is_authenticated %} is false. There are also some menu functions that I want to be available for logged in users such as my-account and logout. Those functions are not available, except on the log-in page. Which is really strange.
This seems to be a user context problem. But I'm not sure how I am supposed to be passing a context around to ensure that my login is stable. Does anyone know at could be going on here? Any advice?
---------part of base.html------------
<!--- The following doesn't register even though I know I'm authenticated -->
{% if user.is_authenticated %}
<div id="menu">
<ul>
<li>My Customers</li>
<li>Customer Actions</li>
<li>My Account</li>
</ul>
</div>
{% endif %}
---------my views.py -----------------
# Should I be doing something to pass the user context here
def customer_list(request):
customer_list = Customer.objects.all().order_by('lastName')[:5]
c = Context({
'customer_list': customer_list,
})
t = loader.get_template(template)
return HttpResponse(t.render(cxt))
If you're using Django 1.3, you can use the render() shortcut, which automatically includes RequestContext for you.
from django.shortcuts import render
def customer_list(request):
customer_list = Customer.objects.all().order_by('lastName')[:5]
return render(request, "path_to/template.html",
{'customer_list': customer_list,})
In this case, you could go one step further, and use the generic ListView:
from django.views.generic import ListView
class CustomerList(Listview):
template_name = 'path_to/template.html'
queryset = Customer.objects.all().order_by('lastName')[:5]
Use a RequestContext.
As Daniel Suggested, use the RequestContext... or better, just use the render_to_response shortcut:
from django.template import RequestContext
from django.shortcuts import render_to_response
def customer_list(request):
customer_list = Customer.objects.all().order_by('lastName')[:5]
return render_to_response(
"path_to/template.html",
{'customer_list':customer_list,},
context_instance=RequestContext(request))
Related
I'm trying to get the standard Aldryn Newsblog Buttons working in my Frontend Page. So every User can Add, Delete and Edit Articles(only the articles they created themselves but thats not the question). This is the Menu with the links:
Menu in the Toolbar
So i want to add a Button in my template wich triggers the edit, add or delete prompt: Delete prompt
I hope someone can help me. Thanks in advance.
If you really don't want all employees to see the toolbars, then you're taking on quite a bit of extra work. I would still consider this as an option, as you can apply permissions so that a user can only edit the content you allow, which means that users can take full advantage of Django CMS's built in functionality, which is great.
If you still don't want to take this route then you're going to have to build your own mini admin for your article model. Below I've quickly thrown together an idea for how you can approach this to hopefully help point you in the right direction.
First, your article view should be something like:
from django.views.generic import DetailView
from .models import Article
class ArticleView(DetailView):
context_object_name = 'article'
model = Article
template_name = 'path/to/article.html'
def get_context_data(self, **kwargs):
context = super(ArticleView, self).get_context_data(**kwargs)
context['show_controls'] = (self.request.user.is_authenticated() and
context[self.context_object_name].article == self.request.user)
return context
With the article template like:
<section>
{% if show_controls %}
<div class="controls">
Delete
Edit
</div>
{% endif %}
<article>
...
</article>
</section>
The path to delete view could be a confirm page like the Django admin. So you'd have a view like:
from django.contrib.auth.decorators import login_required
from django.core.exceptions import PermissionDenied
from django.shortcuts import get_object_or_404, redirect, render
from .models import Article
#login_required
def delete_article(request, article_pk):
if request.method == "POST":
article = get_object_or_404(Article, pk=article_pk)
if request.user != article.author:
raise PermissionDenied
article.delete()
return redirect('/redirect/url')
else:
context = {}
...
return render(request, 'path/to/confirm/delete.html', context)
With a template along the lines of:
<section>
<form method="POST">
{% csrf_token %}
<p>Are you sure you want to delete?</p>
<input type="submit" value="Delete">
</form>
</section>
You'd then create a similar setup for the edit page, navigate the user to a page that has a form where the fields can be amended and submitted etc.
I have a bit of an issue with CSRF verification in my Django app. I have two other {% csrf_token %} tags in my app, in two different HTML templates. These work fine, and always have. When attempting to add a third in another new template though, I receive the '403 Forbidden' page. I've copied the style of the two working 'post' commands exactly, but for some reason this one will not work. Any suggestions?
The 'post' form contains a single select/drop-down object, and a submit button. Clicking the button should direct to a view to process the posted data, written again just like the first 2, but it throws the 403 error instead, with the reason for failure being 'CSRF token missing or incorrect'. I'm running Django 1.4.22 also, with User authentication enabled. Here is the not-working view:
from django.shortcuts import render_to_response, get_object_or_404
from django.template import RequestContext
from django.http import HttpResponseRedirect
from django.core.urlresolvers import reverse
from django.contrib.auth.decorators import login_required
...Other Views...
#login_required
def Process(request, id):
...
try:
choice = request.POST['choice']
except(KeyError, Item.DoesNotExist):
return render_to_response('app/home.html', context_instance=RequestContext(request))
else:
...Process posted data...
return HttpResponseRedirect(reverse('app.views.display', args=()))
Here is the working view:
#Same includes/imports as earlier, in same file
#login_required
def Submit(request, id, id_2, data):
try:
new_data = request.POST[data.name]
except(KeyError, DataPoint.DoesNotExist):
return render_to_response('app/home.html', context_instance=RequestContext(request))
else:
...Process new data...
return HttpResponseRedirect(reverse('app.views.Data_View', args=()))
And here is the HTML file:
<!DOCTYPE html>
...
<table>
<tr><td>
<form action="/app/page/to/redirect/to/" method="post">
{% csrf_token %}
<select name="choice">
<option name="yes" value="yes" selected>Yes</option>
<option name="no" value="no">No</option>
</select>
</form></td></tr>...</table>
I wrote a function that allows the user to delete his article on a blog website. The problem is, if he plays a little with the url, he can access to another article and delete it.
What is the common strategy to avoid such cases with django?
here are the codes I wrote for the fonction:
views.py
def delete_article(request, id):
deleted = False
logged_user = get_logged_user_from_request(request) #that line allow to ensure that the user is connected. I use the session to achieve that instead of extending the User model
offer = get_object_or_404(Offer, id=id)
if request.method == 'POST':
offer.delete()
deleted = True
return render(request, 'offers/delete_article.html', locals())
urls.py
urlpatterns = patterns('article.views',
url(r'^send_article$', 'send_article', name='send_article'),
url(r'^my_articles$', 'show_my_articles', name='my_articles'),
url(r'^article/(?P<id>\d+)$', 'read', name='read'),
url(r'^articles$', 'show_articles', name='articles'),
url(r'^search_article$', 'search', name='search'),
url(r'^delete_article/(?P<id>\d+)$', 'delete_offer', name='delete_offer'),
)
delete_article.html
{% if not deleted %}
Hey, are you sure you want to delete {{ article.title }}?
<form method="POST">
{% csrf_token %}
<button type="submit" class="deleting_offer_button">delete</button>
</form>
{% elif deleted %}
<p>the article was successfully deleted</p>
get back to the homepage<br />
{% endif %}
As you can see, if the user change the numer of the id in the url, he can delete other article when he is directed to the confirmation of deleting page.
What webmasters are doing to ensure users cannot interfere with objects of other users?
HttpResponseForbidden can be used here which uses a 403 status code. A 403 response generally used when authentication was provided, but the authenticated user is not permitted to perform the requested operation.
Assuming you have author as an foreign key in Offer model, you can change your views like this:
In your views.py you have to import :
from django.http import HttpResponseForbidden
And then in your delete_article method use this code
offer = get_object_or_404(Offer, id=id)
if offer.author != request.user:
return HttpResponseForbidden()
When you get the article/offer. Make sure that the owner of that article is the authenticated user.
I'm not sure what your models look like but it would be something like
offer = get_object_or_404(Offer, id=id, author=logged_user)
This way if they don't own the article, it will 404
I'm new at django and I'm having problems with a simple form POST.I have a ModelForm in forms.py and when user enters information in html, views.py taks it and saves it. However, I keep getting an error saying it can't find the view doesn't exist in view.py. Please help me find the error. Thank you!
urls.py
urlpatterns = patterns('',
(r'^mypage/(?P<username>\w+)/$', 'recipeapp.views.my_view'),
forms.py
class NewRecipeForm(forms.ModelForm):
user_info = forms.ForeignKey(User)
title = forms.CharField(min_length=2,max_length=50,required=True,)
post_date = forms.DateField(auto_now=True)
ingredients = forms.TextField(widget=forms.Textarea(),)
picture = forms.ImageField(upload_to='photos/%Y/%m/%d',)
content = forms.TextField(widget=forms.Textarea(),)
views.py
#csrf_protect
from recipeapp.forms import NewRecipeForm
def my_view(request,username):
if request.method == 'POST':
form = NewRecipeForm(request.POST)
if form.is_valid():
form.save()
else:
form = NewRecipeForm()
return render_to_response('postlogin.html',{'username':username},{'form': form}, RequestContext(request))
postlogin.html
<form action="" method="post" id="form">
{% csrf_token %}
<div id="dish-name">
<label><p>Dish name</p></label>
{{form.title}}
</div>
<div id="ingredients">
<label><p>Ingredients</p></label>
{{form.ingredients}}
</div>
<div id="content">
<label><p>Content</p></label>
{{form.content}}
</div>
{{form.picture}}
</form>
Is that really your whole views.py? You have at least three issues:
Firstly, you haven't imported csrf_protect - like any name, a decorator needs to be defined before you can use it.
Secondly, you have to decorate an actual function, not a file. The decorator should go just before the function definition for my_view.
Thirdly, your indentation is broken - the def should not be indented at all.
Given all those, I expect that Python is failing to import your views because of syntax errors.
Also note that you shouldn't really use csrf_protect - you should enable CSRF protection in your middleware (it's on by default) and only use the csrf_exempt decorator, and then only on very very rare occasions.
In my template, I have the following:
<ul class="tabbed" id="network-tabs">
{% if user.is_authenticated %}
<li>My Account</li>
<li>Log Out</li>
{% else %}
<li>Log in</li>
<li>Register</li>
{% endif %}
</ul>
It seems to work fine, unless the page been created has a #login_required decorator, in which case the page works fine but the navigation appears as if the user is not logged in, even when they are.
You should check your view function to see where the user variable is coming from. Unless you're specifically passing user into the context from the view, that's your problem.
You do have access to request.user, though, and that will always return true in a template rendered from a view that has the #login_required decorator.
The reason I can tell you for certain that there's nothing wrong with the decorator, though, is that in the code for User and AnonymousUser (located in django.contrib.auth.models) the is_authenticated method strictly returns true for User and false for AnonymousUser. The decorator does not and cannot change that. And what that means is that your template isn't actually getting a User object where you're checking user.
To follow on from Gabriel's answer, is the user variable coming from the auth context processor? If it is, and you are using the render_to_response shortcut, you need to use a RequestContext instance.
from django.template import RequestContext
...
#login_required
def some_view(request):
# ...
return render_to_response('my_template.html',
my_data_dictionary,
context_instance=RequestContext(request))