I am new to Django. I am trying to build a page which displays all the users who have registered on to my Website.
The logic I tried to use is getting the id of a user in the built-in User Model.
In views.py, I have created a class based view which is a DetailView like this
from django.shortcuts import render
from django.contrib.auth.models import User
from django.views.generic import DetailView
#I have not used a ListView class but I have used a function based View
def home(request):
context = {
'users': User.objects.all(),
}
return render(request, 'home_page/home.html', context)
class UserDetailView(DetailView):
model = User
urls.py:
from django.urls import path
from .views import PostDetailView, UserDetailView
urlpatterns = [
path('', views.home, name='home_page'),
path('users/<pk>/', UserDetailView.as_view(), name='user-detail'),
]
In home.html, I have added this:
{% for user in users %}
<h2><a class="article-title" href="{% url 'user-detail' user.id %}">{{ user.username }}</a></h2>
{% endfor %}
When I clicked on the username it redirects me to localhost:8000/users/None/ and I get this error:
Exception Type: ValueError
Exception Value: invalid literal for int() with base 10: 'None'
Is this the right way to get the is of a user from the User Model?
change your urls.py
from django.urls import path
from .views import PostDetailView, UserDetailView
urlpatterns = [
path('', views.home, name='home_page'),
path('user/<int:pk>/', UserDetailView.as_view(), name='user-detail'),
]
The url waits for an integer, so we have to specify this in the url.
Your view to:
from django.views import View
from django.shortcuts import get_object_or_404
class UserDetailView(View):
def get(self, request, pk):
user = get_object_or_404(User, pk=pk)
return render(request, 'home_page/user_details.html', locals())
I personally don't like using context. I use locals() which passes the variables present in the method to the template.
Create a new html user_details.html file on home_page folder
and your template to:
<h2><a class="article-title" href="{% url 'user-detail' pk=user.pk %}">{{ user.username }}</a></h2>
{% for user in users %}
<h2><a class="article-title" href="{% url 'user-detail' user.id %}">{{ user.username }}</a></h2>
{% endfor %}
Its user, not users in the loop
If you do not have any User(s) yet, the QueryDict will have no elements (i.e. None) which is what I believe the error code is referring to. Once the User(s) have been created, the result should be an Integer (i.e. primary key to the User). In order to bypass this error, check whether the QueryDict has any elements before your for loop i.e.
{% if users %}
{% for user in users %}
<h2><a class="article-title" href="{% url 'user-detail' user.id %}">{{ user.username }}</a></h2>
{% endfor %}
{% else %}
<h2>There are no users loaded yet </h2>
{% endif %}
Related
In class base view "django" I have a problem , after post email with "PasswordResetView" the django go to login page but it must show me "PasswordChangeDoneView"
views:
class UserPassReset(PasswordResetView):
template_name = 'accounts/password_reset_form.html'
success_url = reverse_lazy('accounts:PasswordChangeDone')
#success_url = 'done'
email_template_name = 'accounts/password_reset_email.html'
class PasswordChangeDone( PasswordChangeDoneView):
template_name='accounts/password_reset_done.html'
urls:
path('login/', views.UserLogin.as_view() , name='UserLogin'),
path('passreset/', views.UserPassReset.as_view() , name='UserPassReset'),
path('passreset/done', views.PasswordChangeDone.as_view(), name='PasswordChangeDone'),
HTML reset password:
{% block content %}
<h3>Enter Email </h3>
<form action="" method="POST">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Send">
</form>
{% endblock %}
I think you are confused between password change & password reset Views.
This view is used when you redirect after changing password:
PasswordChangeDoneView
And this view is used when you redirect after reseting password:
PasswordResetCompleteView
This is built-in view so you have to import it & then use it directly in urls.py like this:
from django.contrib.auth import views as auth_views
path('passreset/done', auth_views.PasswordResetCompleteView.as_view
(template_name='accounts/password_reset_done.html'), name='passreset_done'),
I am trying to make a contact form, but I guess I'm doing it wrong.
When I access /contact and put name, email, content in each field and click a submit button, I got an error.
NoReverseMatch at /contact/ Reverse for 'contact_result' not found.
'contact_result' is not a valid view function or pattern name.
view.py
from django.urls import reverse_lazy
from django.views.generic import TemplateView
from django.views.generic.edit import FormView
from .forms import ContactForm
class ContactFormView(FormView):
template_name = 'contact/contact_form.html'
form_class = ContactForm
success_url = reverse_lazy('contact_result')
def form_valid(self, form):
form.send_email()
return super().form_valid(form)
class ContactResultView(TemplateView):
template_name = 'contact/contact_result.html'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['success'] = "completed"
return context
urls.py
from . import views
from .views import DbDetail,ContactFormView, ContactResultView
app_name = 'db'
urlpatterns = [
path('', views.DbList.as_view(), name='list'),
path('contact/', ContactFormView.as_view(), name='contact_form'),
path('contact/result/', ContactResultView.as_view(), name='contact_result'),
]
contact_form.html
{% block content %}
<div class="container">
<div class="row">
<div class="col-md-8">
<h1>inquily</h1>
<p>inquily form</p>
<form method="POST">{% csrf_token %}
{{ form.as_p }}
<button type="submit" class="btn btn-primary">submit</button>
</form>
</div>
</div>
</div>
{% endblock %}
contact_result.html
{% block content %}
{{ success }}
{% endblock %}
I just mentioned the above settings in this question but still if more code is required then tell me I'll update my question with that information.
I always get this error:
Reverse for 'user_home' with arguments '()' and keyword arguments '{u'pk': None}' not found. 1 pattern(s) tried: ['ibs/(?P[0-9]+)/home/$']
in my template I can display my user.pk (it is equal to 1) but when i use it and pass it in my views i got the error above (pk: none). I have read some threads about this. Some are because of the url patterns but I changed and check my urls but nothing happened. Still gets the error.
this is my url:
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^ibs/$', views.index, name='index'),
url(r'^ibs/register/$', views.user_add, name='user_add'),
url(r'^ibs/login/$', views.user_login, name='user_login'),
url(r'^ibs/(?P<pk>[0-9]+)/home/$', views.user_home, name='user_home'),
url(r'^ibs/(?P<user_pk>[0-9]+)/logout/$', views.user_logout, name='user_logout'),
url(r'^ibs/(?P<pk_item_add>[0-9]+)/additem/$', views.item_add, name='item_add'),
url(r'^ibs/(?P<pk_item>[0-9]+)/viewitem/(?P<pk_user>[0-9]+)/$', views.item_detail, name='item_detail'),
]
my template:
{% block home %}
<li class="active">Home</li>
{% endblock home %}
{% block register %}
{% endblock register %}
{% block login %}
{% endblock login %}
{% block logout %}
<li>
<a method="post" href="{% url "user_logout" user_pk=user.pk %}"><span class="glyphicon glyphicon-log-out"></span> Logout
</a>
</li>
{% endblock logout %}
{% block post %}
<li>
<a method="post" href="{% url "item_add" pk_item_add=user.pk %}"> {{user.pk}}
</a>
</li>
{% endblock post %}
def user_login(request):
if request.method == "POST":
#username is unique, get User where username is equal to requested username
username = User.objects.get(username = request.POST['username'])
if username.password == request.POST['password']:
request.session['username'] = username.id
return redirect('system.views.user_home', pk=username.id)
else:
return render(request, 'system/user_login.html')
views.py
def user_home(request, pk):
user = get_object_or_404(User, pk=pk)
try:
if request.session['username'] == user.pk:
items = Item.objects.all()
types = Type.objects.all()
return render(request, 'system/user_home.html', {'user':user, 'types':types,
'items': items})
else:
return redirect('system.views.user_login')
except KeyError:
return redirect('system.views.user_login')
def user_logout(request, user_pk):
user = get_object_or_404(User, pk=user_pk)
try:
del request.session['username']
return redirect('system.views.user_login')
except KeyError:
pass
return redirect('system.views.user_login')
Where did I go wrong? I passed all the necessary data from views to templates.
When a user is not logged in the user is likely the models.AnonymousUser which does not have a primary key.
https://docs.djangoproject.com/en/1.8/ref/contrib/auth/#anonymous-users
If the user is not logged in then you probably don't want them to see that template at all. Redirect them to the login page in the view or check that the user is not anonymous in the template.
I have my page deployed at http://example.com. I also have my django application deployed at http://example.com/djangoapp.
I'm using Apache 2.2 with this configuration (/etc/apache2/apache2.conf): WSGIPythonPath /home/brian/djangoprojects/djangoapp.
I also added the line WSGIScriptAlias /djangoapp /home/brian/djangoprojects/djangoapp/djangoapp/wsgi.py to the default Apache Virtual Host file and it works really nice.
However, in my application I'm using the auth module to register and login users, and have some problems with it. Sometimes I got redirected to the main page, http://example.com/, sometimes to http://example.com/register instead of http://example.com/djangoapp/register.
Changes I made in my project:
Edited settings.py and added:
LOGIN_URL = '/djangoapp/accounts/login/'
USE_X_FORWARDED_HOST = True
FORCE_SCRIPT_NAME = '/djangoapp'
SUB_SITE = "/djangoapp"
My urls.py file looks like this:
from django.conf.urls import include, url
from django.contrib import admin
from djangoapp import views
urlpatterns = [
url(r'^admin/', include(admin.site.urls)),
url(r'^$', 'django.contrib.auth.views.login'),
url(r'^logout/$', views.logout_page),
url(r'^accounts/login/$', 'django.contrib.auth.views.login'), # If user is not login it will redirect to login page
url(r'^register/$', views.register),
url(r'^register/success/$', views.register_success),
url(r'^home/$', views.home),
]
And here's my views.py file:
from django.contrib.auth.decorators import login_required
from django.contrib.auth import logout
from django.contrib.auth.models import User
from django.views.decorators.csrf import csrf_protect
from django.shortcuts import render_to_response
from django.http import HttpResponseRedirect
from django.template import RequestContext
from djangoapp.forms import RegistrationForm
#csrf_protect
def register(request):
if request.method == 'POST':
form = RegistrationForm(request.POST)
if form.is_valid():
user = User.objects.create_user(
username=form.cleaned_data['username'],
password=form.cleaned_data['password1'],
email=form.cleaned_data['email']
)
return HttpResponseRedirect('register/success/')
else:
form = RegistrationForm()
variables = RequestContext(request, {
'form': form
})
return render_to_response(
'registration/register.html',
variables,
)
def register_success(request):
return render_to_response(
'registration/success.html',
)
def logout_page(request):
logout(request)
return HttpResponseRedirect('/')
#login_required
def home(request):
return render_to_response(
'home.html',
{'user': request.user}
)
This is the production server and it's available online. I tried to use a work-around, but with no effect. I simply changed links on page and added djangoapp at the beginning, for instance:
{% extends "base.html" %}
{% block title %}Login{% endblock %}
{% block head %}Login{% endblock %}
{% block content %}
{% if form.errors %}
<p>Your username and password didn't match. Please try again.</p>
{% endif %}
<form method="post" action=".">{% csrf_token %}
<table border="0">
<tr><th><label for="id_username">Username:</label></th><td>{{ form.username }}</td></tr>
<tr><th><label for="id_password">Password:</label></th><td>{{ form.password }}</td></tr>
</table>
<input type="submit" value="Login" />
<input type="hidden" name="next" value="/home" />
</form>
Register
{% endblock %}
And I tried to change Register to Register but I'm sure there's got to be a smarter solution. Any advice?
You need to use the {% url %} tag and the reverse function consistently. So:
Register
and
return HttpResponseRedirect(reverse('register_success'))
For this to work you also need to give your URL patterns names:
url(r'^register/$', views.register, name="register"),
url(r'^register/success/$', views.register_success, name="register_success"),
Aso, as I said in the comment, you do not need to set FORCE_SCRIPT_NAME yourself.
I am trying to create simple application that allows just login existing user and logout if logged in.
views.py
from django.views.generic.edit import FormView
from django.views.generic import DetailView
from django.contrib.auth import logout
from django.contrib.auth.models import User
from django.contrib.auth.forms import AuthenticationForm
from django.core.urlresolvers import reverse_lazy
from django.http import HttpResponseRedirect
class UserDetailView( DetailView ):
model = User
template_name = "main/user_detail.html"
class UserLoginView( FormView ):
form_class = AuthenticationForm
success_url = reverse_lazy("UserDetails")
template_name = "main/user_form.html"
def logout_view(request):
logout(request)
return HttpResponseRedirect('/login/')
urls.py
from django.conf.urls import patterns, include, url
from main import views
urlpatterns = patterns('',),
url( r'users/(?P<pk>\d+)/', views.UserDetailView.as_view(), name="UserDetails"),
url( r"logout/", views.logout_view, name="UserLogOut" ),
url( r"login/", views.UserLoginView.as_view(), name="UserLogIn" ),
)
user_form.html
{% if user.is_authenticated %}
Logout
{{ user.username }}
{% else %}
<form method='post'> {% csrf_token %}
<table>
{{ form.as_table }}
</table>
<input type='submit' value='Submit'>
</form>
{% endif %}
I don't know why, but server returns this error
Request Method: POST
Request URL: http://0.0.0.0:9000/login/
Django Version: 1.6.5
Exception Type: NoReverseMatch
Exception Value:
Reverse for 'UserDetails' with arguments '()' and keyword arguments '{}' not found. 0 pattern(s) tried: []
What's wrong?
UPD
I've tried this dirty hack success_url = reverse_lazy("Main:UserDetails", kwargs={ 'pk':1 } ) just to check that it's working. I've also added
{% if user.is_authenticated %}
Hooray!
{% else %}
What the hell???
{% endif %}
to the user_detail.html and for some reason got What the hell??? instead of Hooray!
Why authentication form doesn't actually authenticates user?
I think the problem is in this statement
success_url = reverse_lazy("UserDetails")
You need to provide user pk to reverse_lazy args, because URL is in form "users/user_id/".
So it's impossible to find out correct success URL.
In this line in your urlconf
url( r'users/(?P<pk>\d+)/', views.UserDetailView.as_view(), name="UserDetails"),
you are defining the url for UserDetails as 'something/users/pk'. But then you are not supplying a pk argument to that url. That's why your error says that the reverse was not found, because it tries to find a pattern which has no arguments.
There are several ways to fix your error, but I think the best solution would be to make the pk argument optional, like this:
url( r'users(?:/(?P<pk>\d+))?/', views.UserDetailView.as_view(), name="UserDetails"),
Hope this helps.