I want to prevent logged-in users to access login and register forms.
I've build custom mixin, but it isn't working. The problem is that even if the user is logged in, he can access login and register forms instead of beeing redirected to homepage.
My Mixin
class MustBeAnonymousMixin(object):
''' Only anonymous users (not logged in) may access login and register
'''
def dispath(self, *args, **kwargs):
if not self.request.user.is_anonymous:
return redirect(reverse('homepage'))
return super(MustBeAnonymousMixin, self).dispatch(*args, **kwargs)
LoginFormView
class LoginFormView(MustBeAnonymousMixin, TemplateView):
'''
Display basic user login form
'''
template_name = 'members/login.html'
def get_context_data(self, **kwargs):
context = super(LoginFormView, self).get_context_data(**kwargs)
context['login_form'] = UserLoginForm()
return context
I'm using Django 1.8. What am I doing wrong?
For another case where mixin does not work:
Remember: "Mixin param" must stand before "GenericView param"
Correct:
class PostDelete(LoginRequiredMixin, generic.DeleteView):
Incorrect:
class PostDelete(generic.DeleteView, LoginRequiredMixin):
Fix the typo in dispath and use is_authenticated() instead of is_anonymous (as indicated in the previous answer already)
is_anonymous should be a function call, and you probably should not use it:
is_anonymous()
Always returns False. This is a way of differentiating User and
AnonymousUser objects. Generally, you should prefer using is_authenticated() to this method.
Related
Is there anyway to prevent the Allauth Signup form from automatically logging in the User?
I found a similar post here with no answers:
prevent user login after registration using django-allauth
You get logged in because this behavior is baked into the signup view of the allauth. When the form is valid, the view calls the function called complete_signup that does two things:
Emits the user_signed_up signal
Logs a user in
To solve this, we need to leave the step 1 and replace the step 2 with a simple redirect.
Here's how this can be done:
Extend the SignupView from allauth/account/views.py and override its form_valid method like this:
class CustomSignupView(SignupView):
def form_valid(self, form):
# By assigning the User to a property on the view, we allow subclasses
# of SignupView to access the newly created User instance
self.user = form.save(self.request)
try:
signals.user_signed_up.send(
sender=self.user.__class__,
request=self.request,
user=self.user,
**{}
)
return HttpResponseRedirect(self.get_success_url())
except ImmediateHttpResponse as e:
return e.response
Haven't tested the code, but it should be working.
Wire your new view up in urls.py, so it replaces the old Signup view url.
I am using django-allauth 0.42.0
There is no need to extend the SignUp view, it can be achieved by the setting:
ACCOUNT_EMAIL_VERIFICATION = 'mandatory'
in your project settings.py file.
I am kind of new to Django, and i am trying to make sort of a news website where users can submit articles(with an account) but the admin needs to check them before they can be posted. Is that possible?
Yes, it is.
The simplest approach would be creating simple flag in model let's say a Boolean field named verified, which by default would be False. You could add permissions. So in the end you could overwrite a function in your admin form, and show the field for superuser only.
class MyUserAdmin(admin.ModelAdmin):
def get_form(self, request, obj=None, **kwargs):
self.exclude = []
if not request.user.is_superuser:
self.exclude.append('Permissions') #here!
return super(MyUserAdmin, self).get_form(request, obj, **kwargs)
I have a model named Post and have a field there called owner (foreign key to User). Of course, only owners can update or delete their own posts.
That being said, I use login_required decorator in the views to make sure the user is logged in but then, I also need to make sure the user trying to update/delete the question is the owner.
As I'm using Django: Generic Editing Views the documentation says I need to use Django: UserPassesTestMixin.
This validation will be done for the update and delete views. DRY, what is the way to go about this? should I create a class named TestUserOwnerOfPost and create a test_func() and then make the update and delete views inherit from it?
Cause that's what I have tried and didn't work, code below:
from django.views.generic.edit import UpdateView
from django.contrib.auth.decorators import login_required
from django.contrib.auth.mixins import UserPassesTestMixin
class TestUserOwnerOfPost(UserPassesTestMixin):
def test_func(self):
return self.request.user == self.post.owner
class EditPost(UpdateView, TestUserOwnerOfPost):
model = Post
#method_decorator(login_required)
def dispatch(self, *args, **kwargs):
return super(EditPost, self).dispatch(*args, **kwargs)
With the code above, every logged-in user in the system can edit/delete any post. What am I doing wrong? am I missing something? thanks.
The first problem is that the order of the classes you inherit is incorrect, as #rafalmp says.
However, fixing that doesn't solve the problem, because the UserPassesTest mixin performs the test before running the view. This means that it's not really suitable to check the owner of self.object, because self.object has not been set yet. Note I'm using self.object instead of self.post -- I'm don't think that the view ever sets self.post but I might be wrong about that.
One option is to call self.get_object() inside the test function. This is a bit inefficient because your view will fetch the object twice, but in practice it probably doesn't matter.
def test_func(self):
self.object = self.get_object()
return self.request.user == self.object.owner
Another approach is to override get_queryset, to restrict it to objects owned by the user. This means the user will get a 404 error if they do not own the object. This behaviour is not exactly the same as the UserPassesTestMixin, which will redirect to a login page, but it might be ok for you.
class OwnerQuerysetMixin(object):
def get_queryset(self):
queryset = super(OwnerQuerysetMixin, self).get_queryset()
# perhaps handle the case where user is not authenticated
queryset = queryset.filter(owner=self.request.user)
return queryset
The order of the classes you inherit from matters. For your access control to work, it must be enforced before UpdateView is executed:
class EditPost(TestUserOwnerOfPost, UpdateView):
I am generating an object from a submitted form. I want to pass along the generated AutoField to the next form as a hidden form element. However, I cannot figure out how to pass a variable from post() to get_context_data(). I know that post() is called first, followed by get_context_data(), but adding the variable to self does not yield the results I expect (the attribute does not exist on self).
Here is an example of what I am experiencing:
def get_context_data(self, **kwargs):
context = super(MyView, self).get_context_data(**kwargs)
print self.hello
return context
def post(self, request, *args, **kwargs):
self.hello = "hello"
return HttpResponseRedirect(request.path)
self.hello is not valid when called in get_context_data. I feel as though I may be mistaken with the HttpResponseRedirect(request.path) call, but I'm not sure how else to render the template.
Is it a simple mistake, or should I be approaching this an entirely different way?
By defining post yourself, you've overridden the default behaviour of the view. You can see that there is no call to get_context_data, or any of the other class methods, so naturally they won't be called.
Generally you should not be overriding the specific get or post methods. You haven't shown the full view so it's not clear what behaviour you are trying to achieve, but for example in a form view you would want to define success_url to set the place the form redirects to after submission.
You have to find a way to pass the object ID to the next page. The options that come to mind are to put it into the URL or as solarissmoke has suggested save it in the session. If you are doing it in the url you can also put the page sequence there (meaning 1 for the forst form, 2 for the second...).
The nice thing about this approach is, that you can cover all functonailty in one view: depending on the page set the respective fields in the get_object methods (self.fields=[....]) and the template names in the get_template_names method.
So using an Updateview, it would look like this:
urls.py:
....
url(r'^mysite/(?P<object_no>\d+)/(?P<form_no>\d+)$', BaseView.as_view()),
views.py:
class BaseView(UpdateView):
def get_object(self):
obj=MyModel.objects.get(id=self.kwargs['object_no'])
form_no = self.kwargs['form_no']
if form_no=="1":
self_fields=["field1","field2"...]
.....
def get_object(self):
obj=MyModel.objects.get(id=self.kwargs['object_no'])
form_no = self.kwargs['form_no']
if form_no=="1":
self_fields=["field1","field2"...]
.....
return obj
def get_template_names(self):
from_no = self.kwargs['form_no']
if form_no=="1":
return ["template1.html"]
....
You have to make sure that all your fields can be null.
Is it possible to extend a generic view to allow user authentication? I want my view to limit the number of returned results from the model if a user is not logged in.
class CustomGalleryDetailView(DetailView):
def get_queryset(self):
if request.user.is_authenticated():
return Gallery.objects.on_site().is_public()
else:
return Gallery.objects.on_site().is_public()[:5]
This returns NameError global name 'request' is not defined.
The reason I want to extend the generic view is that here I am simply overriding a single of many views used by a 3rd party app in my program, and I want to maintain some consistency with the rest of the views which mainly rely on generic views.
just change it to self.request.user.is_authenticated(), so your class will become:
class CustomGalleryDetailView(DetailView):
def get_queryset(self):
if self.request.user.is_authenticated():
return Gallery.objects.on_site().is_public()
else:
return Gallery.objects.on_site().is_public()[:5]