I'm having some trouble trying to pass a string from a URL to the views. My page has user pages, and if you go to site.com/username it brings up that users page. But when I try going it says this: [invalid literal for int() with base 10: 'username'].
Here's my code:
urls.py:
(r'^user/(?P<userName>[^/]+)/$', 'mischief_blog.mischief_app.views.user_view'),
views.py:
def user_view(request, userName):
postList = userPost.objects.filter(author=userName)
return render_to_response('user.html', {"user": user_name, "postList": postList}, context_instance=RequestContext(request))
get name from url:
(r'^user/(?P<userName>\w+)/$', 'mischief_blog.mischief_app.views.user_view'),
get user from name, then get posts from user: (get_object_or_404) and (User)
from django.shortcuts import get_object_or_404
from django.contrib.auth.models import User
def user_view(request, userName=None):
user = get_object_or_404(User, username=userName)
postList = userPost.objects.filter(author=user)
return render_to_response('user.html', {"user": user, "postList": postList}, context_instance=RequestContext(request))
Related
I have this url pattern:
path("user/<int:pk>", MyAccountView.as_view(), name='my_account'),
And this view:
class MyAccountView(DetailView):
model = CustomUser
When the user is logged Django redirect to that URL.
The problem is that any user can access other users.
For example, if the logged user has pk 25, he can access the view of user with pk 26 by writing in the browser url box:
localhost:8000/user/26
I want that each user can access to his user page only, so if user with pk 25 try to access the url with pk 26, the access should be denied.
Can you point me in some direction of how this is done? The Django documentation is very confusing in this respect.
Thanks.
You need to override the get method of DetailView
from django.core.exceptions import PermissionDenied
from django.contrib.auth.mixins import LoginRequiredMixin
class MyAccountView(LoginRequiredMixin, DetailView):
model = CustomUser
def get(self, request, pk):
if request.user.pk != pk:
raise PermissionDenied()
self.object = self.get_object()
context = self.get_context_data(object=self.object)
return self.render_to_response(context)
Easy !
First change the view path from user/<int:pk>/ to user/
Link the view to the current user, DetailView won't work because it heavily relies on either pk or slug and we won't be using none of them, so you'll have to write a new view. (Example using FBV because i do not use CBV)
# views.py
from django.contrib.auth.decorators import login_required
# redirects to login page if the user is not authenticated
#login_required(login_url='/example url you want redirect/')
def get_user_profile(request):
context = dict(user=request.user)
return render(request, "template.html", context)
And that's it, any user visiting /user/ will only see their account/profile.
I created some users for my website in Django and i want each user to access only his own profile page .
The template for the user profile page is fetched through a CBV Detail View called UserDetailView attached to a URL containing the user's and the page is loading only after authentication .( user logged in). So far so good.
urls.py:
from django.conf.urls import url
from django.urls import path
from basicapp import views
from django.contrib.auth.decorators import login_required
app_name='basicapp'
urlpatterns = [
url(r'^$',views.index,name='index'),
url(r'^user_list/',views.UserView.as_view(),name='user_list'),
url(r'^course_list/',views.CourseView.as_view(),name='course_list'),
url(r'^user_detail/(?P<pk>[-\w]+)/$',views.UserDetailView.as_view(),name='user_detail'),
]
The problem is after I login and get the user detail page : If I manually change the <pk> in the URL I get other user profile pages loaded. I don't want that to happen .
For ex, the URL for the logged in user profile is :
http://127.0.0.1:8000/basicapp/user_detail/1/
With the user already logged in i manually change the URL to :
http://127.0.0.1:8000/basicapp/user_detail/2/
and it works. It should retrict me or show me an error message
I tried using LoginRequiredMixin
views.py:
from django.contrib.auth.decorators import login_required
from django.contrib.auth.mixins import LoginRequiredMixin
from django.utils.decorators import method_decorator
class UserDetailView(LoginRequiredMixin,DetailView):
context_object_name='user_detail'
model=models.User
template_name='basicapp/user_detail.html'
raise_exception = True # Raise exception when no access instead of redirect
permission_denied_message = "This page dows not exist."
and I also tried usingmethod_decorator :
#method_decorator(login_required)
class UserDetailView(LoginRequiredMixin,DetailView):
context_object_name='user_detail'
model=models.User
template_name='basicapp/user_detail.html'
raise_exception = True # Raise exception when no access instead of redirect
permission_denied_message = "This page dows not exist."
but it doesn't seem to work . I restarted the server.
Any ideas what i am doing wrong?
The LoginRequiredMixin will ensure that you can only see the page if you are logged in, but that does not mean you have to be that user.
However if you can only see your own profile, it does not make much sense to add a primary key in the url anyway, you can just define the url as:
url(r'^user_detail/$', views.UserDetailView.as_view(), name='user_detail'),
In the view you then return the logged in user for the .get_object() method [Django-doc]:
class UserDetailView(LoginRequiredMixin,DetailView):
context_object_name='user_detail'
model=models.User
template_name='basicapp/user_detail.html'
def get_object(self, *args, **kwargs):
return self.request.user
Or you can restrict users by filtering the queryset:
path('^user_detail/<int:pk>/', views.UserDetailView.as_view(), name='user_detail'),
class UserDetailView(LoginRequiredMixin,DetailView):
context_object_name='user_detail'
model=models.User
template_name='basicapp/user_detail.html'
def get_queryset(self, *args, **kwargs):
qs = super().get_queryset(*args, **kwargs)
if not self.request.user.is_superuser:
qs = qs.filter(pk=self.request.user.pk)
return qs
I have tried to do the following, but neither redirect nor render works:
from allauth.socialaccount.adapter import DefaultSocialAccountAdapter, get_account_adapter
from allauth.account.adapter import DefaultAccountAdapter
from django.shortcuts import render
class SocialAccountAdapter(DefaultSocialAccountAdapter):
def __init__(self, request=None):
DefaultSocialAccountAdapter.__init__(self, request)
def save_user(self, request, sociallogin, form=None):
"""
Saves a newly signed up social login. In case of auto-signup,
the signup form is not available.
"""
print('saving user')
u = sociallogin.user
u.set_unusable_password()
if form:
get_account_adapter().save_user(request, u, form)
else:
get_account_adapter().populate_username(request, u)
sociallogin.save(request)
print('right before redirect')
return render(request, 'accounts/signup.html',
context={'title': 'Edit Profile', 'register_update': 'Update'})
Only an ImmediateHttpResponse(redirect('url')) works, but then it redirects to the login page.
Signals does not work either.
Oops...I've found a solution to my own problem...
Just create a sign in processor view in your views.py, like so:
def sign_in_processor(request):
user = request.user
required = [#User Fields that were not filled up by the social provider on creation]
for f in required:
if not f:
return redirect('profile_edit')
return redirect('home')
'profile_edit' is a view based off a UserChangeForm from django.contrib.auth.forms or its derivatives.
I am learning Django. Well, more or less ;)
I am writing a login form. Because I want to learn how stuff works and because I need to do this.
I am not able to get things right. The user is, after authentication, not known in my "success" view as it seems, because it redirects back to the login.
I did set up my MIDDLEWARE_CLASSES.
"Funny thing" was that I thought it went well, because it seems to work. However, I figured out that was an old session with my user credentials. Now I deleted all session/cookie stuff and I it is not working.
This is what I have so far:
# views.py
from django.shortcuts import render_to_response
from django.contrib.auth import authenticate
from django.template import RequestContext
from django.http import HttpResponseRedirect
from django.core.urlresolvers import reverse
def login(request):
username = password = usertype = login_error_message = ''
if request.POST:
username = request.POST.get('username')
password = request.POST.get('password')
usertype = request.POST.get('usertype')
user = authenticate(username=username, password=password)
if user is not None:
if user.is_active:
return HttpResponseRedirect(reverse('login:success'))
else:
login_error_message = "Not active."
else:
login_error_message = "Unknown user"
return render_response(request, 'login/login.html', {
'login_error_message': login_error_message,
'usertype': usertype
})
def success(request):
if request.user.is_authenticated():
user = request.user
return render_response(request, 'login/success.html', {
'username': user.username,
})
else:
return HttpResponseRedirect('/login/')
# https://djangosnippets.org/snippets/3/
# Wrapper simplifies using RequestContext in render_to_response.
# overkill at this point, but may come in handy in view files with more views
def render_response(req, *args, **kwargs):
kwargs['context_instance'] = RequestContext(req)
return render_to_response(*args, **kwargs)
And this are my url's:
# urls.py
from django.conf.urls import patterns, url
from diataal.apps.login import views
urlpatterns = patterns('',
url(r'^$', views.login),
url(r'^success/', views.success, name='success'),
)
My url shows the login page. If I do not add the check on the user in the "success" view, the success page is shown (a 302 response from login and then a 200 response from the success page); that seems ok to me.
But with the check, I get a 302 response from the "success" view and I am back at the login page again...
I have no clue how to solve this... What am I doing wrong?
In your login view, you only authenticate the user. You do not actually login the user.
authenticate only takes the username and password and returns a user object if the credentials are valid. This is a pre-cursor to the actual login call
I'm working on a platform for online labs registration for my university.
Login View [project views.py]
from django.http import HttpResponse, HttpResponseRedirect, Http404
from django.shortcuts import render_to_response
from django.template import RequestContext
from django.contrib import auth
def index(request):
return render_to_response('index.html', {}, context_instance = RequestContext(request))
def login(request):
if request.method == "POST":
post = request.POST.copy()
if post.has_key('username') and post.has_key('password'):
usr = post['username']
pwd = post['password']
user = auth.authenticate(username=usr, password=pwd)
if user is not None and user.is_active:
auth.login(request, user)
if user.get_profile().is_teacher:
return HttpResponseRedirect('/teachers/'+user.username+'/')
else:
return HttpResponseRedirect('/students/'+user.username+'/')
else:
return render_to_response('index.html', {'msg': 'You don\'t belong here.'}, context_instance = RequestContext(request)
return render_to_response('login.html', {}, context_instance = RequestContext(request))
def logout(request):
auth.logout(request)
return render_to_response('index.html', {}, context_instance = RequestContext(request))
URLS
#========== PROJECT URLS ==========#
urlpatterns = patterns('',
(r'^media/(?P<path>.*)$', 'django.views.static.serve', {'document_root': settings.MEDIA_ROOT }),
(r'^admin/', include(admin.site.urls)),
(r'^teachers/', include('diogenis.teachers.urls')),
(r'^students/', include('diogenis.students.urls')),
(r'^login/', login),
(r'^logout/', logout),
(r'^$', index),
)
#========== TEACHERS APP URLS ==========#
urlpatterns = patterns('',
(r'^(?P<username>\w{0,50})/', labs),
)
The login view basically checks whether the logged in user is_teacher [UserProfile attribute via get_profile()] and redirects the user to his profile.
Labs View [teachers app views.py]
from django.http import HttpResponse, HttpResponseRedirect, Http404
from django.shortcuts import render_to_response
from django.template import RequestContext
from django.contrib.auth.decorators import user_passes_test
from django.contrib.auth.models import User
from accounts.models import *
from labs.models import *
def user_is_teacher(user):
return user.is_authenticated() and user.get_profile().is_teacher
#user_passes_test(user_is_teacher, login_url="/login/")
def labs(request, username):
q1 = User.objects.get(username=username)
q2 = u'%s %s' % (q1.last_name, q1.first_name)
q2 = Teacher.objects.get(name=q2)
results = TeacherToLab.objects.filter(teacher=q2)
return render_to_response('teachers/labs.html', {'results': results}, context_instance = RequestContext(request))
I'm using #user_passes_test decorator for checking whether the authenticated user has the permission to use this view [labs view].
The problem I'm having with the current logic is that once Django authenticates a teacher user he has access to all teachers profiles basically by typing the teachers username in the url.
Once a teacher finds a co-worker's username he has direct access to his data.
Any suggestions would be much appreciated.
A simple way would be to modify the view to add an extra check:
#user_passes_test(user_is_teacher, login_url="/login/")
def labs(request, username):
if username != request.user.username:
return HttpResponseNotAllowed()
... and so on ...
Assuming you have a variable called 'teacher' that represents the profile of the teacher whose profile you're viewing, just do something like this early in the view:
if request.user.get_profile() != teacher:
..redirect, throw 404, whatever you fancy
Just a short hint.
...
user = request.user
enrollment = get_object_or_404(Enrollment, id=enrollment_id)
profile = get_object_or_404(Profile, user=user)
if not (enrollment.profile == profile or user.is_staff):
raise Http404
...
enrollment.delete()
We used such if statements to determine, whether the actual user and the action he requested match. In the example above, only the profile who create an enrollment is allowed to delete it (or someone with staff priviledges).