I am building my first django app that uses user authentication and I'm using
some examples I found on the web for reference. My examples use a method 'direct_to_template'.
The problem is that I get a blank screen when I use this. I know that the
template is in my templates directory.
Why am I getting a blank screen at login? How can I fix this?
The examples I'm using:
Example #1: https://docs.djangoproject.com/en/dev/topics/auth/
Example #2:
http://www.nerdydork.com/django-login-form-on-every-page.html
My code is below:
-------------base.html-------------
Here is the trigger it's in the header bar.
<li>Log-In</li>
--------- views.py -----------------------
from django.template import Context, loader
from django.conf.urls import patterns, url, include
from django.views.generic.simple import direct_to_template
from django.http import HttpResponse
VER = "1a" # Global I like to print; making sure my latest code is running.
def mylogin(request):
print "mylogin called [%s] " % VER
if request.method == 'POST':
user = authenticate(username=request.POST['username'],
password=request.POST['password'])
if user is not None:
if user.is_active:
login(request, user)
# success
return HttpResponseRedirect('/')
else:
# disabled account
return direct_to_template(request, 'inactive_account.html')
else:
# invalid login
return direct_to_template(request, 'invalid_login.html')
# User just clicked login
# *** I know this is getting called and I get a blank screen here ***
print "calling: direct_to_template('login.html')"
return direct_to_template(request, 'login.html')
def mylogout(request):
print "mylogout called"
logout(request)
return direct_to_template(request, 'logged_out.html')
--------- urls.py -----------------------
from django.conf.urls import patterns, include, url
from django.views.generic.simple import direct_to_template
from django.contrib import admin
admin.autodiscover()
urlpatterns = patterns('',
(r'^customers/$', 'jim.views.index'),
(r'^customers/(?P<customer_id>\d+)/$', 'jim.views.detail'),
(r'^media/(?P<path>.*)$', 'django.views.static.serve', {'document_root': '/media'}),
(r'^static/(?P<path>.*)$', 'django.views.static.serve', {'document_root': '/static'}),
(r'^login/$', 'jim.views.mylogin'),
(r'^logout/$', 'jim.views.mylogout'),
(r'^site_media/(?P<path>.*)$', 'django.views.static.serve', {'document_root': '/media'}),
url(r'^admin/doc/', include('django.contrib.admindocs.urls')),
url(r'^admin/', include(admin.site.urls)),
)
urlpatterns += patterns('django.views.generic.simple', (r'^accounts/login/$', 'direct_to_template', {'template': 'login_required.html'}),
)
--------- templates/login.html -----------------------
{% if user.is_authenticated %}
<!-- Authenticate account menu -->
{% else %}
<h3>Login</h3>
<form action="/login/" method="post" accept-charset="utf-8">
<label for="username">Username</label><input type="text" name="username" value="" id="username" />
<label for="password">Password</label><input type="password" name="password" value="" id="password" />
<p><input type="submit" value="Login"></p>
</form>
{% endif %}
Errr if your template is such
{% if user.is_authenticated %}
<!-- Authenticate account menu -->
{% else %}
stuff
{% endif %}
it seems pretty logical that your template is blank -_-
further more.. 200 is not an HTTP error it means 200 OK: Standard response for successful HTTP requests.
I have added a comment for you question asking for more details. But without those details my wild guess is that you need a view to display your "login.html" template.
You can write a sepearate view for that and put it in the urls.py. You can use the generic direct_to_template view in urls.py. Or you can modify your current "mylogin" view, for example:
def mylogin(request):
print "mylogin called [%s] " % VER
if request.method == 'POST':
user = authenticate(username=request.POST['username'],
password=request.POST['password'])
if user is not None:
if user.is_active:
login(request, user)
# success
return HttpResponseRedirect('/')
else:
# disabled account
return direct_to_template(request, 'inactive_account.html')
else:
# display login form
return direct_to_template(request, 'login.html')
The difference is in the indendation and in the last line (no POST data, means it's a GET request to display the login form).
But as I said, there are w few ways to handle it, mine is only a suggestion and I'm not going into any of your design decisions :)
Related
From the page
This page isn’t working. If the problem continues, contact the site owner.
HTTP ERROR 405
From the terminal
Method Not Allowed (POST): /
Method Not Allowed: /
[20/Dec/2021 22:00:27] "POST / HTTP/1.1" 405 0
How to redirect to the same page after page upload click.
form.html->included in sidebar.html-> included in home.html
<form method = "POST" action='.' enctype="multipart/form-data">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">Upload</button>
</form>
views.py
from django.shortcuts import render
from .forms import UserProfileForm
def index(request):
print(request.POST)
return render(request,'home.html')
urls.py
from django.conf import settings
from django.urls import path
from django.views.generic.base import TemplateView # new
urlpatterns = [
path('', TemplateView.as_view(template_name='home.html'), name='home'),
]
In your urls.py
Change to:
path(' ', index, name = 'home'),
And you also have to import your view in urls.py
Since you are redirecting to the same page, I assume you are also making a get request when you are serving the form on the webpage.
But when the page is served as a response to a GET request, it is not supposed to contain an empty dictionary in the POST attribute.
Thus, it provides an error.
According to me
def index(request):
if request.method == "POST" :
print(request.POST)
return render(request,'home.html')
Should solve the issue
Acc, to the Django documentation
It’s possible that a request can come in via POST with an empty POST dictionary – if, say, a form is requested via the POST HTTP method but does not include form data. Therefore, you shouldn’t use if request.POST to check for use of the POST method; instead, use if request.method == "POST"
For further reference - https://docs.djangoproject.com/en/3.2/ref/request-response/
I have code that works perfectly on localhost, but it is giving an error when placed on the server.
The point is that when I upload a file, it returns "base.com/home/home" (home twice = 404) instead of just "base.com/home" or the destination of the redirect.
Template:
<form method="post" enctype="multipart/form-data">
{% csrf_token %}
<input type="file" name="myfile">
<button type="submit">Upload</button>
</form>
View:
def login_page(request):
if request.user.is_authenticated:
return redirect('base-home')
form = UserLoginForm(request.POST or None)
nextr = request.GET.get('next')
if form.is_valid():
username = form.cleaned_data.get('username')
password = form.cleaned_data.get('password')
user = authenticate(username=username, password=password)
login(request, user)
if nextr:
return redirect(nextr)
return redirect('base-home')
return render(request, 'base/login.html', {'form': form})
#login_required
def home(request):
if request.method == 'POST':
return redirect('base-temp', 1)
return render(request, 'base/home.html', {'test': 'test'})
Url:
urlpatterns = [
path('', views.login_page, name='base-login'),
path('logout/', views.logout_page, name='base-logout'),
path('home/', views.home, name='base-home'),
path('temp/<int:pk>/', views.temp, name='base-temp')
]
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
Project settings:
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
All other pages, media, statics are working fine. Only the post in this view.
I tried using action with ".", "/home/" and "{% url 'base-home'%}", but they all give the same 404 for duplicating the home url.
I also tried to create a separate view to handle the upload, but the error became "home/upload" instead of "upload".
I saw some similar questions in the stackoverflow, but I didn't find an answer that would work for me.
Any suggestion?
EDIT:
It works if I change the template to:
<form method="post">
{% csrf_token %}
<textarea name="text"></textarea>
<button type="submit">Send</button>
</form>
And the view to:
def home(request):
if request.method == 'POST':
return redirect('base-temp', 2)
return render(request, 'base/home.html', {'test': 'test'})
I'm not using django's forms.py.
That's it. Nothing else. Only the imports and a simple function view/template for base-temp.
Edit 2: Added more details about the views.
SOLUTION:
In case anyone else has the same problem, I leave the solution here, based on Maxwell O. Oyaro's answer.
I changed the home route to the empty path of the app urls.py:
urlpatterns = [
path('', views.home, name='base-home'),
path('logout/', views.logout_page, name='base-logout'),
path('temp/<int:pk>/', views.temp, name='base-temp')
]
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
Then, I moved login path to the project urls.py:
...
from base import views as base_views
urlpatterns = [
path('admin/', admin.site.urls),
path('login/', base_views.login_page, name='login'),
path('', include('base.urls'))
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
Check if your home is defined globaly for the django project or it is for the app itself.
Putting templates globally for the project and for the app alone can be confusing. If you have a templates for the project with home and you have another home template in the app calle home, it may not give you what you expect.
Just check keenly.
I have internationalization correctly installed.
It's works with urls like:
/en/bookings/ #English
/es/reservas/ #Spanish
In the home page the language switching works fine too.
- What's the issue?
When I change the language in a translated page, like /en/bookings/, if I turn the language to Spanish (es) I am redirected to /en/bookings/ again and I see the page in English.
If I change the prefix (like this answer) the redirection goes to /es/bookings/ that doesn't exists.
I don't want to be redirected to the home page.
- What I like?
If I am in the /en/bookings/ and switch to Spanish I want to be redirected to /es/reservas/, for all the translated urls.
What is the best way?
Thanks.
I had similar problem so I sending my resolution to save Your time.
main(urls.py)
from django.conf.urls import include, url
from django.conf.urls.i18n import i18n_patterns
urlpatterns = [
url(r'^i18n/', include('django.conf.urls.i18n')),
]
urlpatterns += i18n_patterns(
url(r'^', include('index.urls', namespace='index')),
)
(index.urls.py)
from django.conf.urls import url
from django.views.generic import TemplateView
from django.utils.translation import ugettext_lazy as _
urlpatterns = [
url(r'^$', TemplateView.as_view(template_name='index/index.html'), name='index'),
url(_(r'^python-programming/$'), TemplateView.as_view(template_name='index/new_page.html'),
name='new_page'),
]
Creating template tag to return urls for current location in all languages that we support (index.templatetags.helper_tags.py)
from django.template import Library
from django.core.urlresolvers import resolve, reverse
from django.utils.translation import activate, get_language
register = Library()
#register.simple_tag(takes_context=True)
def change_lang(context, lang=None, *args, **kwargs):
"""
Get active page's url by a specified language
Usage: {% change_lang 'en' %}
"""
path = context['request'].path
url_parts = resolve(path)
url = path
cur_language = get_language()
try:
activate(lang)
url = reverse(url_parts.view_name, kwargs=url_parts.kwargs)
finally:
activate(cur_language)
return "%s" % url
Creating middleware to change site language when user will click at alternative link to this sub site but in different language
(middleware.py)
from django.utils import translation
from django.conf import settings
from django.utils.deprecation import MiddlewareMixin
class LangBasedOnUrlMiddleware(MiddlewareMixin):
#staticmethod
def process_request(request):
if hasattr(request, 'session'):
active_session_lang = request.session.get(translation.LANGUAGE_SESSION_KEY)
if active_session_lang == request.LANGUAGE_CODE:
return
if any(request.LANGUAGE_CODE in language for language in settings.LANGUAGES):
translation.activate(request.LANGUAGE_CODE)
request.session[translation.LANGUAGE_SESSION_KEY] = request.LANGUAGE_CODE
Adding it to (settings.py) just after LocaleMiddleware
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.locale.LocaleMiddleware',
'our_app.middleware.LangBasedOnUrlMiddleware',
]
Sample usage in template:
{% load i18n %}
{% load helper_tags %}
{% get_available_languages as languages %}
{% for lang_code, lang_name in languages %}
<a href="{{ request.scheme }}://{{ request.META.HTTP_HOST }}{% change_lang lang_code %}">
{% endfor %}
When I had the same problem, I implemented a custom template tag (current_url) that, given the request in context, re-renders the url for the active language:
{% load custom_tags %}
<ul>
{% get_language_info_list for LANGUAGES as languages %}
{% for language in languages %}
{# IMPORTANT! enclose the 'current_url' tag in a 'language' block #}
{% language language.code %}
<li {% if language.code == LANGUAGE_CODE %}class="active"{% endif %}>
{{ language.name_local }}
</li>
{% endlanguage %}
{% endfor %}
</ul>
Here is the code for the custom tag (custom_tags.py):
import six
import sys
from django.template import Node, TemplateSyntaxError, Library
from django.conf import settings
register = Library()
class CurrentURLNode(Node):
def __init__(self, asvar=None):
self.asvar = asvar
def render(self, context):
request = context['request']
from django.core.urlresolvers import reverse, NoReverseMatch
url = ''
try:
url = reverse(request.resolver_match.view_name, args=request.resolver_match.args, kwargs=request.resolver_match.kwargs, current_app=context.current_app)
except NoReverseMatch:
exc_info = sys.exc_info()
if settings.SETTINGS_MODULE:
project_name = settings.SETTINGS_MODULE.split('.')[0]
try:
url = reverse(project_name + '.' + request.resolver_match.view_name,
args=request.resolver_match.args, kwargs=request.resolver_match.kwargs,
current_app=context.current_app)
except NoReverseMatch:
if self.asvar is None:
six.reraise(*exc_info)
else:
if self.asvar is None:
raise
if self.asvar:
context[self.asvar] = url
return ''
else:
return url
#register.tag
def current_url(parser, token):
bits = token.split_contents()
bits = bits[1:]
asvar = None
if len(bits) >= 2 and bits[-2] == 'as':
asvar = bits[-1]
bits = bits[:-2]
if len(bits):
raise TemplateSyntaxError("Unexpected arguments to current_url tag")
return CurrentURLNode(asvar)
There is no need to use the 'set_language' django view. There is no need to make a POST request to change the active language. With only html archors linking all your internationalized content together, it's better for SEO.
I don't know if its me but {% tag ??? %} has bee behaving a bit sporadically round me (django ver 1.2.3). I have the following main.html file:
<html>
{% include 'main/main_css.html' %}
<body>
test! logout
test! logout
</body>
</html>
with the urls.py being:
from django.conf.urls.defaults import *
import settings
from login.views import *
from mainapp.views import *
from client.views import *
# Uncomment the next two lines to enable the admin:
from django.contrib import admin
admin.autodiscover()
urlpatterns = patterns('',
# Example:
# (r'^weclaim/', include('weclaim.foo.urls')),
(r'^login/$', 'login.views.login_view'),
(r'^logout/$', 'login.views.logout_view'),
(r'^$', 'mainapp.views.main_view'),
(r'^client/search/last_name/(A-Za-z)/$', 'client.views.client_search_last_name_view'),
#(r'^client/search/post_code/(A-Za-z)/$', 'client.views.client_search_last_name_view'),
# Uncomment the next line to enable the admin:
(r'^admin/', include(admin.site.urls)),
(r'^static/(?P<path>.*)$', 'django.views.static.serve',{'document_root': settings.MEDIA_ROOT}),
)
and the views.py for login being:
from django.shortcuts import render_to_response, redirect
from django.template import RequestContext
from django.contrib import auth
import mainapp.views
def login_view(request):
if request.method == 'POST':
uname = request.POST.get('username', '')
psword = request.POST.get('password', '')
user = auth.authenticate(username=uname, password=psword)
# if the user logs in and is active
if user is not None and user.is_active:
auth.login(request, user)
return redirect(mainapp.views.main_view)
else:
return render_to_response('loginpage.html', {'login_failed': '1',}, context_instance=RequestContext(request))
else:
return render_to_response('loginpage.html', {'dave': '1',}, context_instance=RequestContext(request))
def logout_view(request):
auth.logout(request)
return render_to_response('loginpage.html', {'logged_out': '1',}, context_instance=RequestContext(request))
and the views.py for clients being:
from django.shortcuts import render_to_response, redirect
from django.template import RequestContext
import login.views
def client_search_last_name_view(request):
if request.user.is_authenticated():
return render_to_response('client/client_search_last_name.html', {}, context_instance=RequestContext(request))
else:
return redirect(login.views.login_view)
Yet when I login it django raises an 'NoReverseMatch' for {% url client.views.client_search_last_name_view %} but not for {% url login.views.logout_view %}
Now why would this be?
The "client.views.client_search_last_name_view" url's regex capatures a value (with the parens), so in order to {% url %} it, you need to pass it a value for that parameter.
If you are creating a URL which is supposed to accept a last name the correct way would be as follows:
(r'^client/search/last_name/(?P<last_name>[a-zA-Z]+)/$',
'client.views.client_search_last_name_view'),
The (?P<last_name>[a-zA-Z]+) part of the regex allows you to capture the last name which is at least one character in length and then have it passed as an argument to your view function.
However you then need to ensure that your view does accept this argument:
def client_search_last_name_view(request, last_name):
...
The reason you cannot then do:
{% url client.views.client_search_last_name_view %}
is because your regex states (like the view) that it needs one argument, which is a string consisting of lower or upper cases letters from A to Z. So for example this would work:
{% url client.views.client_search_last_name_view 'somelastname' %}
If you want to give your URL a name as another answer has suggested you can, but that is a separate matter and has no effect other than shortening that template tag.
The reason {% url login.views.logout_view %} does work is because its entry in urls.py does not specify any arguments to be passed to the view and, through default alone you have not passed any.
AFAIK you want to add a name='foo' arg to each of your url regexes. That name is what is used in the reverse match. Like this:
urls.py
(r'^login/$', 'login.views.login_view', name="login"),
template.html
{% url login %}
I have looked a lot on google for answers of how to use the 'url' tag in templates only to find many responses saying 'You just insert it into your template and point it at the view you want the url for'. Well no joy for me :( I have tried every permutation possible and have resorted to posting here as a last resort.
So here it is. My urls.py looks like this:
from django.conf.urls.defaults import *
from login.views import *
from mainapp.views import *
import settings
# Uncomment the next two lines to enable the admin:
from django.contrib import admin
admin.autodiscover()
urlpatterns = patterns('',
# Example:
# (r'^weclaim/', include('weclaim.foo.urls')),
(r'^login/', login_view),
(r'^logout/', logout_view),
('^$', main_view),
# Uncomment the admin/doc line below and add 'django.contrib.admindocs'
# to INSTALLED_APPS to enable admin documentation:
# (r'^admin/doc/', include('django.contrib.admindocs.urls')),
# Uncomment the next line to enable the admin:
(r'^admin/', include(admin.site.urls)),
#(r'^static/(?P<path>.*)$', 'django.views.static.serve',{'document_root': '/home/arthur/Software/django/weclaim/templates/static'}),
(r'^static/(?P<path>.*)$', 'django.views.static.serve',{'document_root': settings.MEDIA_ROOT}),
)
My 'views.py' in my 'login' directory looks like:
from django.shortcuts import render_to_response, redirect
from django.template import RequestContext
from django.contrib import auth
def login_view(request):
if request.method == 'POST':
uname = request.POST.get('username', '')
psword = request.POST.get('password', '')
user = auth.authenticate(username=uname, password=psword)
# if the user logs in and is active
if user is not None and user.is_active:
auth.login(request, user)
return render_to_response('main/main.html', {}, context_instance=RequestContext(request))
#return redirect(main_view)
else:
return render_to_response('loginpage.html', {'box_width': '402', 'login_failed': '1',}, context_instance=RequestContext(request))
else:
return render_to_response('loginpage.html', {'box_width': '400',}, context_instance=RequestContext(request))
def logout_view(request):
auth.logout(request)
return render_to_response('loginpage.html', {'box_width': '402', 'logged_out': '1',}, context_instance=RequestContext(request))
and finally the main.html to which the login_view points looks like:
<html>
<body>
test! logout
</body>
</html>
So why do I get 'NoReverseMatch' every time?
*(on a slightly different note I had to use 'context_instance=RequestContext(request)' at the end of all my render-to-response's because otherwise it would not recognise {{ MEDIA_URL }} in my templates and I couldn't reference any css or js files. I'm not to sure why this is. Doesn't seem right to me)*
The selected answer is out of date and no others worked for me (Django 1.6 and [apparantly] no registered namespace.)
For Django 1.5 and later (from the docs)
Warning
Don’t forget to put quotes around the function path or pattern name!
With a named URL you could do:
(r'^login/', login_view, name='login'),
...
logout
Just as easy if the view takes another parameter
def login(request, extra_param):
...
login
Instead of importing the logout_view function, you should provide a string in your urls.py file:
So not (r'^login/', login_view),
but (r'^login/', 'login.views.login_view'),
That is the standard way of doing things. Then you can access the URL in your templates using:
{% url login.views.login_view %}
Make sure (django 1.5 and beyond) that you put the url name in quotes, and if your url takes parameters they should be outside of the quotes (I spent hours figuring out this mistake!).
{% url 'namespace:view_name' arg1=value1 arg2=value2 as the_url %}
link_name
The url template tag will pass the parameter as a string and not as a function reference to reverse(). The simplest way to get this working is adding a name to the view:
url(r'^/logout/' , logout_view, name='logout_view')
I run into same problem.
What I found from documentation, we should use namedspace.
in your case {% url login:login_view %}
Judging from your example, shouldn't it be {% url myproject.login.views.login_view %} and end of story? (replace myproject with your actual project name)