I'm working on a project using allauth and i'm using customer user model and i wan the newly registered user to be redirected to a different page (say profile form page) which will be totally different from the login_redirect_url, I have tried it this way
any idea how i can make this work pls?
from django.shortcuts import get_object_or_404, redirect, render
from allauth.account.views import LogoutView
from django.urls import reverse_lazy
from allauth.account.views import SignupView
from django.views.generic import TemplateView
from .models import CustomUser
class Signup(SignupView):
success_url = reverse_lazy('business:company_profile')
def get_success_url(self):
return self.success_url
I am not sure there is way to override SignUp redirection since when you sign up in the application, you also sign in, which will use the login_redirect_url.
If you overrode login_redirect_url (documentation) you can update your logic and redirect the user to his profile if some fields are missing/empty?
def get_login_redirect_url(self, request):
if not request.user.your_custom_field:
path = "/accounts/{username}/"
return path.format(username=request.user.username)
else
return "/"
You could also implement another logic by adding a bool is_first_visit on your CustomerUser model (with default=True) and set it to False after his first visit.
Is the code that you proposed not working? What errors does it produce?
On first glance, the view that you've proposed should work. You would just have to make sure it's being used in "urls.py".
Related
I want to change the return url of a django-allauth page.
I know I could override the entire function in views.py and just change the return url at the bottom, but doesn't seem ideal as it could cause issues if associated code in the django-allauth package gets changed by the packages authors.
Is there a better way to do this?
Thank you.
How I ended up doing this:
from allauth.account.views import PasswordChangeView
from django.contrib.auth.decorators import login_required
from django.contrib.auth.mixins import LoginRequiredMixin
from django.urls import reverse
class CustomPasswordChangeView(LoginRequiredMixin, PasswordChangeView):
def get_success_url(self):
if [...]:
success_url = reverse([...], kwargs={'username': self.request.user.username})
else:
success_url = reverse([...], kwargs={'username': self.request.user.username})
return success_url
custom_password_change = login_required(CustomPasswordChangeView.as_view())
I have various applications in a Django project, but I only want users who are logged in to be able to access those pages. How can I restrict access to every pages except the login page which is my main page. For instance, mywebsite.com/home/user should be only available to user and if someone types in that it should redirect them to mywebsite.com
Currently I have two apps, main and Home, I am using ClassBased views on my Home app how can I restrict access to all my pages except login page and show a message as well?
I want to create a template that users can see other user profile details but not change or edit them. How can I do those above steps
Thanks in advance!
According to Docs you can decorate the class based views with #login_required
from django.contrib.auth.decorators import login_required
from django.utils.decorators import method_decorator
#method_decorator(login_required, name='dispatch')
class ClassBasedView(View):
...
...
Since you are using class based view, you need to add method decorator, else you can use #logine_required directly.
And the other part in the question is again a separate one from this.
You can try This, In very simple way
from django.contrib.auth.decorators import login_required
#login_required
def my_view(request):
return HttpResponse()
using #login_required means user have to login to access that view
Or If you you Want to use class then try this
from django.contrib.auth.mixins import LoginRequiredMixin
from django.views.generic import TemplateView
class RestrictedView(LoginRequiredMixin, TemplateView):
template_name = 'foo/restricted.html'
raise_exception = True
permission_denied_message = "You are not allowed here."
When changing a password via django-allauth, the default redirect after successfully posting the password change is again the password change template. Since I find this confusing, I overrode the original PasswordChnageView in my views.py file:
from allauth.account.views import PasswordChangeView
from django.urls import reverse_lazy
class MyPasswordChangeView(PasswordChangeView):
success_url = reverse_lazy('home')
and changed my urls.py file:
from django.urls import path, include
from users.views import MyPasswordChangeView
urlpatterns = [
...
# User management
path('accounts/password/change/', MyPasswordChangeView.as_view(), name="account_change_password"),
path('accounts/', include('allauth.urls')),
...
]
This works fine when the user is logged in, however when I try to access the url http://127.0.0.1:8000/accounts/password/change/ while being logged out, I get the following error message: AttributeError at /accounts/password/change/ 'AnonymousUser' object has no attribute 'has_usable_password'
Before I created my custom override, the result of the same behaviour was that I was redirected to the login url http://127.0.0.1:8000/accounts/login/?next=/
What do I need to change with my custom view, to redirect to the login url when a logged out user tries to acces the url http://127.0.0.1:8000/accounts/password/change/
Look at the source code: The PasswordChangeView from allauth doesn't have the login required decorator in itself, that's added directly in the urls: the view used is password_change = login_required(PasswordChangeView.as_view()).
There are 2 ways:
Add login_required decorator to your URL.
from django.contrib.auth.decorators import login_required
path('accounts/password/change/', login_required(MyPasswordChangeView.as_view()), name="account_change_password"),
Inherit from LoginRequiredMixin.
from django.contrib.auth.mixins import LoginRequiredMixin
class MyPasswordChangeView(LoginRequiredMixin, PasswordChangeView):
success_url = reverse_lazy('home')
Make sure that LoginRequiredMixin is to the left most side of your child class.
I have a wagtail app in which I need to return the current page's url. The code for my model.py of my app is as follows
import urllib
from django.conf import settings
from django.db import models
from wagtail.core.models import Page
from django.http import HttpResponse
class PageUrl(Page):
def returnPageUrl(self):
page_url = """ i need the page url here """
return page_url
A Page model has a field url_path. You thus can access the page URL with:
class PageUrl(Page):
def returnPageUrl(self):
return self.url_path
or you can make use of full_url to obtain the full url (including the hostname, etc.):
class PageUrl(Page):
def returnPageUrl(self):
return self.full_url
That being said, since it is already a field, I think there is not much use to define an extra method for this.
I am currently building a small project using Django, I have noticed a problem that a logged in user was getting access to the other users page by simply changing the id in the url i.e
This is the url of currently logged in user
http://localhost:8000/home/myBooks/7/
by changing that id from 7 to 6
i.e
http://localhost:8000/home/myBooks/6/
He was getting access to that page,I have used #login_required for functional based views and LoginRequiredMixin for class based views ,but they are not helping, what else I need to do to prevent this problem?
My app/views.py:
from django.shortcuts import render,redirect
from django.http import HttpResponse
from django.views.generic.edit import FormView
from . forms import BookForm
from django.contrib.auth.models import User
from . models import UserBooks
from django.contrib.auth.models import User
from django.views import generic
from django.contrib.auth.decorators import login_required
from .models import UserBooks
from django.shortcuts import get_object_or_404
from django.contrib.auth.mixins import LoginRequiredMixin
#login_required
def HomeView(request):
return render(request,'home/homepage.html')
class BookDetailsView (LoginRequiredMixin,generic.DetailView):
model=UserBooks
template_name='home/bookdetails.html'
class BooksView (LoginRequiredMixin,generic.DetailView):
model=User
template_name='home/mybooks.html'
#login_required
def addBooks(request):
if (request.method=='POST'):
form=BookForm(data=request.POST)
if(form.is_valid()):
u=UserBooks()
u.book_name=form.cleaned_data['book_name']
u.book_author=form.cleaned_data['book_author']
u.book_ISBN=form.cleaned_data['book_ISBN']
u.book_status=True
u.book_genre=form.cleaned_data['book_genre']
u.username=request.user.username
u.user_id = User.objects.get(username=request.user.username)
u.save()
return redirect('/')
else:
form = BookForm()
return render (request,'home/addbooks.html',{'form':form})
my apps/models.py:
from django.db import models
from django.contrib.auth.models import User
class UserBooks(models.Model):
user_id = models.ForeignKey(User,on_delete=models.CASCADE,null=True)
username = models.CharField(max_length=200)
book_name = models.CharField(max_length=200)
book_author = models.CharField(max_length=200)
book_ISBN=models.CharField(max_length=200)
book_genre = models.CharField(max_length=200)
book_status=models.BooleanField(default=False)
class Meta:
unique_together = (("username", "book_ISBN"),)
def __str__(self):
return self.book_name
my apps/urls.py:
from django.urls import path
from . import views
app_name='home'
urlpatterns=[
path('',views.HomeView,name='home'),
path('addBooks/',views.addBooks,name='addBooks'),
path('myBooks/<int:pk>/',views.BooksView.as_view(),name='myBooks'),
path('<int:pk>/', views.BookDetailsView.as_view(), name='myBooks'),
]
If your view should always show the detail for the current user, don't put the ID in the URL at all; get the logged-in user directly within the view.
class BooksView(LoginRequiredMixin, generic.DetailView):
model = User
template_name ='home/mybooks.html'
def get_object(self):
return self.request.user
...
path('myBooks/',views.BooksView.as_view(),name='myBooks'),
class BooksView(LoginRequiredMixin, DetailView):
...
def get(self, request, *args, **kwargs):
current_user = User.objects.get(id=self.request.user.pk)
if current_user.pk == kwargs['pk']:
return HttpResponseRedirect('/')
else:
return HttpResponseRedirect('profile-url')
Here I assume that if you are logged in user and you try to check another user profile by giving id in url. So I add a get method which will check is requested URL id is for the current user (books/7/ is 7 is current user id) if not then redirect to an URL, for example, otherwise redirects to another url. You can get some idea. This may not help you exactly.
If you have just started to develop the app, then it is okay to use pks inside of urls. However, when it comes to a real working app it can lead to some security problems.
As you wrote, one can simply change the url and get some private data.
Other problems can be:
The number of users in the database can be easily counted by iteration through your urls.
The user can be easily detected by his id. Knowing it one can easily get some private data.
If you will decide to change ids in your db, then all the external links will be broken...and etc.
Considering that I suggest an approach in which you use ids internally. For external usage (urls, links) you can use uuids.
To do that you just need additional field into your model:
import uuid
uuid = models.UUIDField(default=uuid.uuid4, editable=False, unique=True)
And here is the example url:
url(r'^myBooks/(?P<user_uuid>\b[0-9A-Fa-f]{8}\b(-\b[0-9A-Fa-f]{4}\b){3}-\b[0-9A-Fa-f]{12}\b)/$',
After you switch to uuids it will be almost impossible to "hack" the url.