Hi
I've got a problem with the Django Template system. When I want to check in the template if a user is logged in with:
{% if user.is_authenticated %}
# success
{% else %}
<p>Welcome, new user. Please log in.</p>
{% endif %}
I dont get to the success part. When I use in a view:
if not request.user.is_authenticated():
return render_to_response('index.html', {'inhalt': 'Not loggged in'})
else:
return render_to_response('index.html', {'inhalt': 'Succesfully loged in'})
it shows me correctly the else part.
Hope somebody can help me.
Thanks Phil
There is an example of handling the context in part 4 of the Django tutorial. However, in short...
The best way to do this is with Django's auth context proccessor. Make sure you still have it in your settings. You then need to use RequestContext
This will essentially change your code to this.
from django.template import RequestContext
# ...
return render_to_response('index.html', {
'inhalt': 'Succesfully loged in'
}, RequestContext(request))
Remember to add 'django.core.context_processors.request' to your TEMPLATE_CONTEXT_PROCESSORS in your settings.py
Example:
# Context processors
TEMPLATE_CONTEXT_PROCESSORS = (
'django.contrib.auth.context_processors.auth',
'django.core.context_processors.debug',
'django.core.context_processors.i18n',
'django.core.context_processors.media',
'django.core.context_processors.static',
'django.core.context_processors.request',
'django.contrib.messages.context_processors.messages',
)
And add RequestContext(request):
# import
from django.template import RequestContext
# render
if not request.user.is_authenticated():
return render_to_response('index.html', {'inhalt': 'Not loggged in'})
else:
return render_to_response('index.html', {'inhalt': 'Succesfully logged in'}, RequestContext(request))
In your python you retrieve the user object that is logged in. I.e define a function get_current_user.
so your response would look something like:
class Index(webapp.RequestHandler):
def get(self):
user= get_current_user()
templates.render(self, 'mypage.html', user=user)
Then on your django template you can simply go like:
{% if user %}
<p>Hallo user {{user.name}}</p>
{% else %}
<p>Welcome, new user. Please log in.</p>
{% endif %}
You need to make sure that either you pass 'request.user' into the renderer. Or better yet use context based rendering:
return render_to_response('index.html',
my_data_dictionary,
context_instance=RequestContext(request))
The context_instance will use the auth middleware context processor to set the 'user' in your view.
Did you pass in your "user" instance from the view to the template? You need to make sure it is in the same context you pass into the render_to_response(), or whichever rendering method you choose for rendering the view context into the template.
Related
I am using Django for develop a website. The website is intended to use to search information stored in a MySQL database.
This is the current basic flow of the web site.
1) index.html - this has a form to select an option
2) according the option, users will redirect to search.html (include a form)
3) once the user provides the criteria, the result will be displayed in reply.html
In my views.py , I have two functions.
from django.shortcuts import render
from website.models import WebsiteRepository
from .forms import SearchForm
from .forms import SelectTypeForm
def Search(request):
if request.method == 'POST':
#do something
return render(request, 'reply.html', {'env_dict':env_dict})
else:
#do something
return render(request, 'search.html', context = context)
def index(request):
if request.method =='POST':
#do something
return render(request, 'search.html', context = context)
else:
#do something
return render(request, 'index.html', context= context)
When I go to index.html page, I can select a option and it will direct me to search.html. After, I fill the form there and submit, it wont give me the reply.html page.
I have a feeling that, I could make this work by changing urls.py.
from django.urls import path
from website import views
urlpatterns = [
path('', views.index, name='index'),
#path('search/', view.Search, name ='Search')
]
I tried to google it. But its too much details and Iam kind of lost.
Do any of you guys know how to achieve this?
Thanks
search.html
{% extends "base_generic.html" %}
{% block content %}
<h3>Welcome to search information Repository</h3>
<form method="post">
{% csrf_token %}
{{form.as_p}}
<button type = 'submit'>submit</button>
</form>
{% endblock %}
index.html
{% block content %}
<h3>Welcome to information Repository</h3>
<form method="post">
{% csrf_token %}
{{form.as_p}}
<button type = 'submit'>submit</button>
</form>
just for clarify things more, ill add the forms.py too
from django import forms
from .models import WebsiteRepository
class SearchForm(forms.Form):
websiterepository = WebsiteRepository
env_indicators = websiterepository.objects.filter (key_aspect='Environmental').values_list('repo_id','indicator')
indicator = forms.ChoiceField(choices=env_indicators,label = 'Indicator' )
OPTIONS = (('2000','2000'),('2001','2001'),('2002','2002'), ('2003','2003'),('0000','0000'),)
year = forms.ChoiceField(choices=OPTIONS)
class SelectTypeForm(forms.Form):
OPTIONS = (('1', 'Envirnmental Indicators'),('2','Economic Indicators'),('3','Social Indicators'),)
types = forms.ChoiceField(choices=OPTIONS)
Your code is wrong on many points.
First thing first: for a search, you want a GET request, not a POST (POST is for updating the server's state - adding or updating your database mostly). This is the semantically correct method (since you want to GET data), and it will allow a user to bookmark the url.
Second point: you don't want to submit the search form to the index view but to the search view. No need for redirects etc, just use the {% url %} templatetag to fill the action attribute of your form (you of course need to have a 'Search' url in your urls.py):
<form method="get" action="{% url 'Search' %}">
{% csrf_token %}
{{form.as_p}}
<button type = 'submit'>submit</button>
</form>
if you want to have this form on more than one page (which is often the case for search forms), use an inclusion tag tha will take care of creating an unbound SearchForm and render the template fragment.
Then in your search view, you only want GET requests, and do not use two different templates, this will only lead to useless duplication.
def Search(request):
form = SearchForm(request.GET)
# use the form's data - if any - to get search results
# and put those results (even if empty) in you context
return render(request, 'reply.html', {'env_dict':env_dict})
And finally, your search form is totally broken:
class SearchForm(forms.Form):
# this is totally useless
websiterepository = WebsiteRepository
# this will only be evaluated once at process startup, so you will
# get stale data in production - and probably different data
# per process, in a totally unpredictable way.
# You need to either put this in the form's __init__ or wrap it
# in a callable and pass this callable
env_indicators = websiterepository.objects.filter (key_aspect='Environmental').values_list('repo_id','indicator')
indicator = forms.ChoiceField(choices=env_indicators,label = 'Indicator' )
# are you going to manually add a new year choice every year ???
OPTIONS = (('2000','2000'),('2001','2001'),('2002','2002'), ('2003','2003'),('0000','0000'),)
year = forms.ChoiceField(choices=OPTIONS)
For the "indicators" ChoiceField you want something like:
def get_indicators_choices():
return Websiterepository.objects.filter (key_aspect='Environmental').values_list('repo_id','indicator')
class SearchForm(forms.Form):
# IMPORTANT : we are NOT calling the function here, just
# passing it (python functions are objects) to the field, which
# will call it everytime the form is instanciated, so you don't
# have stale data
indicator = forms.ChoiceField(
choices=get_indicator_choices,
label='Indicator')
As a last note: be consistent with your namings (ie why name one view in all lower (index) and capitalize the other (Search) ? Whichever convention you choose (I strongly suggest respecting pep8 here), at least stick to it for the whole project.
The problem is that code is not redirecting to /search, instead rendering search.html after post from index.html.
Try doing like-
views.py-
#your code
def index(request):
#do something
if request.method == 'POST':
return redirect('Search')
else:
#render index.html
def search(request):
#do something
if request.method == 'POST':
#render reply.html
else:
#render search.html
Another way to achieve this is if you specify action in your form so that form posts on /search.
search.html
<form method="post" action="/search">
{% csrf_token %}
{{form.as_p}}
<button type = 'submit'>submit</button>
</form>
I have a form view for user feedback:
urls.py:
url(
r'^feedback/$',
'tool.views.Feedback',
name='feedback'
),
url(
r'^thanks/$',
direct_to_template, {
'template': 'tool_feedback_thanks.html'
},
name='feedback_thanks'
),
forms.py:
class FeedbackForm(forms.Form):
yes_no = forms.ChoiceField(
choices=YES_NO_CHOICE,
initial=1,
widget=forms.RadioSelect(attrs={'class': 'can_reveal_input'}),
label="Are you happy with Our service?"
)
comments = forms.CharField(
widget=forms.Textarea(attrs={
'class': 'hidden', 'placeholder': 'Leave us your comments...'
}),
required=False,
label=""
)
views.py:
def Feedback(request,
template_name='tool_feedback.html'):
title = u'Leave us some feedback'
form = FeedbackForm(request.POST or None)
if form.is_valid():
yes_no = form.cleaned_data['yes_no']
comments = form.cleaned_data['comments']
sender = "A Unirac website user"
recipients = ['person#example.com']
send_mail(yes_no, comments, sender, recipients)
return HttpResponseRedirect(
reverse('feedback_thanks')
)
return render_to_response(template_name, {
'title': title,
'form': form,
}, RequestContext(request))
This works a treat, but now the client is asking that this form be included on every single page. I guess the form can be submitted via js to the appropriate url, but what is the best way to include the unbound form on every page?
Any help would be much appreciated.
I'd create a context processor, to include the form in every view.
EDIT:
To get the user to the previous URL he/she was browsing, you can use just URLs.
# yourapp/context_processors.py
def feedback_form_context_processor(request):
return {
'feedback_form': FeedbackForm(),
'feedback_form_url': reverse("feed_app:form_process", args=(request.path))
}
This is how urls.py could look like:
urlpatterns = patterns('feed_app.views',
url(r'^process-feedback-form/(?P<next_url>\d+)', 'form_process', name='form_process'),
)
And the view for the form:
def form_process(request, next_url):
# Process form, do your stuff here
# if its valid redirect to the url
return redirect(next_url)
And you should structure your templates to have the correct layout. For example, having a base template:
# templates/base.html
<html>
<body>
..
{% block maincontent %}
{% endblock %}
..
{# The form!!! #}
<form action='{{feedback_form_url}}' method='POST'>
#csrftoken
{{ feedback_form.as_p }}
</form>
</body>
</html>
To create a simple view just use the correct template.
# templates/just_a_random_view.html
{% extends base.html %}
{% block maincontent %}
<h1>Content!</h1>
{% endblock %}
Finally, include it in your settings:
# settings.py
TEMPLATE_CONTEXT_PROCESSORS = (
"django.contrib.auth.context_processors.auth",
...
"yourapp.context_processors.feedback_form_context_processor"
)
I believe that easiest way to include form would be to use a assignment_tag:
In template library:
#register.assignment_tag
def feedback_form(format_string):
return FeedbackForm()
In template
{% feedback_form as form %}
{# display form... %}
{{ form.as_p }}
To add on to #bmihelac, who's answer worked really well for me. Since django 2.0 assignment_tag is deprecated in favor of simple_tag. So you can pretty much follow his answer exactly by replacing assignment_tag with simple_tag, like so:
from django import template
from .forms import FeedbackForm
register = template.Library()
#register.simple_tag
def feedback_form():
return FeedbackForm()
And then just refer to https://docs.djangoproject.com/en/2.1/howto/custom-template-tags/#code-layout for info about how to import it into the template!
Hi I'm writing a django project, and I write template code like this:
<ul id="nav">
<li>Home</li>
<li>Users</li>
{% if user %}
<li>Settings</li>
<li>Log Out</li>
{% else %}
<li>Log In</li>
<li>Sign Up</li>
{% endif %}
</ul>
Now in login view I write like this:
def login(request):
if user_logged_in(request):
return redirect('/')
if request.method == 'GET':
form = LogInForm()
return render_to_response(LOGIN_PATH, {'form':form}, context_instance=RequestContext(request))
But when I run the server, no user is logged in, and visit login page, it shows Settings and Log Out(there is a user object in context), but it shouldn't!
If I remove RequestContext, say return render_to_response(LOGIN_PATH, {'form':form}), it will be OK. And
return render_to_response(LOGIN_PATH, {'form':form, 'user':None}, context_instance=RequestContext(request))
is OK too. But I don't want to do it.
I know it's dirty design, well... I'm looking for suggestions and solutions. Many thanks~!
{% if user.is_authenticated %}
your tag just checks for a user object, not for an authenticated one.
check here for more informations on what you can do with an auth user :)
The default setting for TEMPLATE_CONTEXT_PROCESSORS includes "django.contrib.auth.context_processors.auth". This context processor adds a user to cotnext, which will be anonymous if the user is not provided in request so.
If you want to be able to know whether or not the user is authenticated in template the #Samuele Mattiuzzo answer is what you should use, but if you don't want, for any reason, to include the user in context, then you need to modify the default TEMPLATE_CONTEXT_PROCESSORS setting without the auth context processor.
For more information read the docs or the code.
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))
I'm using direct_to_template for a url but I need the logged in user to display the page. How do I pass it to direct_to_template?
If your TEMPLATE_CONTEXT_PROCESSORS variable in settings.py is set to include 'django.contrib.auth.context_processors.auth', it will already be on the page context. (This is configured by default).
The direct_to_template generic view uses RequestContext, so there will be a context variable called user that will provide the currently logged in user (or an AnonymousUser if there is no logged in user).
For example, to display the username in your template: {{ user.username }}.
For more details see the django docs on the auth context processor.
put following in your login view before GET method
def custom_proc(request):
return {
'app': 'myapp',
'user': request.user,
'ip_address': request.META['REMOTE_ADDR']
}
in login view in post
......some code here......
return render(request, 'html file name',
context_instance=RequestContext(request,processors=custom_proc]))
in setting.py
TEMPLATE_CONTEXT_PROCESSORS = ( 'django.contrib.auth.context_processors.auth',
'django.core.context_processors.request',
)
and in html file
Hello, username = {{ user.username }} id ={{ user.id }}