Django PermissionRequiredMixin not working - django

When I place the PermissionRequiredMixin as the most left paramenter, my requests get forwarded to the login URL even though the request is coming from an already authenticated user.
class ExampleViewSet(PermissionRequiredMixin, viewsets.ModelViewSet):
permission_required = ('example.example_view',)
When I place the PermissionRequiredMixin after the ModelViewSet the authenticated user is detected, however, the permission_required is ignored, and every user without the permission is allowed as well. And this answer suggested, that this is caused by the placement of the parameter, which leads to the first problem.
class ExampleViewSet(viewsets.ModelViewSet, PermissionRequiredMixin):
permission_required = ('example.example_view',)
How do I solve this problem?

It is not a problem. Order of inheritance classes is important. View base class have to set at last position. Mixins by theirs positions can override some function of the django view. The ordering of overriding function by the child class is in part defined by this ordering. First parent in the order will be called at first.
In your case, if you put a breakpoint in your PermissionRequiredMixin, you will see that python does not pass in it when you call your page
You can read some links as:
https://en.wikipedia.org/wiki/Multiple_inheritance#The_diamond_problem
http://python-history.blogspot.com/2010/06/method-resolution-order.html
How does Python's super() work with multiple inheritance?

Related

DRF: How to access "context" inside custom DecimalField class?

I am subclassing the DecimalField class from Django RestFramework and need to access context. Formatting for decimal fields includes settings that are user-selectable, so I need to access the user object (which, I assume, should be inside context) inside the to_representation() method.
Via debug, I've looked at all properties of self inside my CustomDecimalField class, but, of course, I can't see class methods, so I don't know if there's an appropriate "get" method to get context. I've tried self.context (as a property), self.get_context(), and self.getcontext(), but none worked.
I found this announcement re: require_context:
https://www.django-rest-framework.org/community/3.11-announcement/
...but it seems to be valid only for validation and default value methods.
This seems like such a simple thing; hard to believe it is so difficult.
You have to manually set the user inside the context. So, in your view:
serializer = YourSerializer(your_data, context={'user': request.user})
And you will then be able to access it in your to_representation() method:
def to_representation(self, instance):
user = self.context.get("user")
Please see the documentation for more information.

django view based template problem with PermissionRequieredMixin

i'm new in Django. I'm trying to "override" a permission_required for inheriting view. Example:
class ValetView(PermissionRequieredMixin, View):
permission_required = ('lav.add_valets')
this works fine. If I go to this view, it's works dependient on /admin setted permissions. But now, I need to separate permission in ADD and EDIT, so I created this view inheriting from base:
class ValetsEditView(ValetsView)
ValetsView.permission_required = ('lav.edit_valets')
When I try to access any of two, it said: permission denied but I allow the user only edit feature, NOT add. How can I grant permission only for edit??
I hope it is understood. Thanks!
As Willem said the problem lies with ValetsView.permission_required. This shoudl be simply permission_required. Full code is:
class ValetView(PermissionRequieredMixin, View):
permission_required = 'lav.add_valets'
class ValetsEditView(ValetsView)
permission_required = 'lav.edit_valets'
That should now work for you. I've also removed the parenthesis around the permissions, as they were serving no purpose.
Something you didn't ask for
The following would also have been valid, as Django supports specifying a sequence of tuples. Note the trailing , below, which is required to specify a tuple of a single value in Python:
class ValetView(PermissionRequieredMixin, View):
permission_required = ('lav.add_valets',)
class ValetsEditView(ValetsView)
permission_required = ('lav.edit_valets',)
In your code you had ('lav.edit_valets') (without a trailing ,), which python does not interpret as a tuple, rather it just removes the parenthesis and sees it as the string 'lav.edit_valets'. Just one of those little quirks.
Your original code ValetsView.permission_required = ('lav.edit_valets') is modifying the parent view's permission_required. Change it to the following:
class ValetsEditView(ValetsView)
permission_required = ('lav.edit_valets')

What is 'success_url' variable default value

I am creating a form in Django by extending the CreateView class and everything works fine.
But what I don't quite understand is that when the form is submitted, web browser automatically redirects me to the url specified by model's get_absolute_url() method.
Is it a default behavior that 'success_url' field is at some point assigned by an url returned by that method?
If your view class defines a success_url attribute this is used as the success url. Otherwise it will use get_absolute_url() method of the created/edited object. See the documentation here.
So if you don't want to redirect to the object's absolute url you can either define success_url on the class or re-define the class' get_success_url() method if you need to fine-tune it more.

Get an url pk in a generic RESTful view?

I'm trying to manage my REST API like that :
http://xxx/users/userid[0-9]+/projects/projectid[0-9]+/tasks/taskid[0-9]+/
So I can access the JSON easily in my website. But, the thing is, I defined my view classes using the REST framework generic views. For example, here is my UserDetail view :
class UserDetail(generics.RetrieveUpdateDestroyAPIView):
queryset = User.objects.all()
serializer_class = UserSerializer
But of course I don't want all my users to be displayed, I just want my user with the ID userid to be displayed. I don't really know how to do it, I tried
queryset = User.objects.filter(id=userid)
but of course userid is not defined... Any help please ?
Edit : just to clarify, here is the url that leads to this view :
url(r'^users/(?P<pku>[0-9]+)/$', views.UserDetail.as_view(
), name='user-detail'),
First of all, If you want to use class based views, you should read some more about them. They are thoroughly explained on Django's docs and you can read about the specific generics of the framework you're using on the REST framework docs too. I'm not saying that you haven't read those, just that you seem to be missing some basic concepts that are explained there.
Now, to the problem at hand, if you look at the doc's of the generic view you're extending, you can see that it represents the endpoints for a single instance, meaning that it won't act on all your model's instances (as you seem to assume).
Also, you can see that this view is built on top of a series of other classes, the more critical one being GenericAPIView. On there you can see two things:
The queryset class field in this context is meant for filtering the posible instances you can manipulate, not obtaining the specific instance described on your url.
The lookup_field is the field that defines which attribute from your model will be used for getting the actual instance. You should define this field to whatever field you're going to use on your url to identify your object (generally it's pk). It's also important to note that the url should include a keyword argument corresponding to this value.
Internally, the view will take care of calling the get_object method, which usese the lookup_field value to find the specific model, and then feed that object to the serializer and return the result back to the client.
DISCLAIMER: I've never used Django REST framework, I put this answer togheter by reading the relevants docs and based on my experience.
I guess you need this:
Resolve function (django 1.4)
Then in your view class method you can do:
temp1, args, kwargs = resolve(self.request.path)

Django: Is there a way to add a model instance method to the admin?

I'm looking to add a method that my Ticket model has called process to the admin, so that I could click a link in the list view, and "process" my model instance (do an API call behind the scenes).
To clarify:
class Ticket(models.Model):
title = models.CharField(max_length=255)
def process(self):
... hardcore processing action ...
I need to add the process() method directly to the admin without using a separate function.
You just need to provide a small method in your ModelAdmin class that returns a link pointing at a view that calls your model method, and add the name of that method to the modeladmin's list_display tuple. You'll obviously also need to define this view itself, and a url that points to it.
Yes, thats possible; Check out this documentation, just what you need:
http://docs.djangoproject.com/en/1.1/ref/contrib/admin/actions/#ref-contrib-admin-actions