Reputation: 5676
I have 3 objects - Company, Expert and RecentProject where RecentProject has ForeignKey to Company and ManyToMany relation to expert:
class RecentProject(BaseProfileObject):
company = models.ForeignKey(
'experts.Company',
verbose_name=_("Company"),
blank=True,
null=True,
related_name='projects')
experts = models.ManyToManyField(
"Expert",
verbose_name=_("Experts"),
blank=True,
null=True,
related_name='projects')
class Meta:
verbose_name = _("Recent project")
verbose_name_plural = _("Recent projects")
What i want is to be able to post new recent project from endpoints like
api/v1/companies/1/recentprojects/ and api/v1/experts/1/recentprojects/
In 1st case the seralizer should be able to validate (or rather make permission check) if user can make changes to company and in 2nd case if user can make changes to expert. What i can't seem to find is an example of how to make permissions be aware of parent object (company in 1st case and expert in 2nd).
I understand that it can be done with permissions so i created permission like:
class UserCanModifyCompany(permissions.BasePermission):
def has_permission(self, request, view):
# Do check here
return False
And i added it to my viewset: class RecentProjectViewSet(viewsets.ModelViewSet): queryset = RecentProject.objects.all() serializer_class = RecentProjectSerializer
@permission_classes((UserIsAuthenticatedExpert, UserCanModifyCompany))
def create(self, request, *args, **kwargs):
return super(RecentProjectViewSet, self).create(request, *args, **kwargs)
@permission_classes((UserIsAuthenticatedExpert, UserCanModifyCompany))
def update(self, request, *args, **kwargs):
return super(RecentProjectViewSet, self).update(request, *args, **kwargs)
But how can i make sure the permission check has info available for company/expert access check. Or do i need to create different viewsets for both company/expert recent projects saving and have different permission classes for both of them?
Upvotes: 0
Views: 750
Reputation: 4795
First of all, creating two different endpoints for the same resource is not a good idea. I suggest you use single endpoint: api/v1/recentprojects/
.
Having said that, I have been in similar situation, and I think your best option is to use @detail_route
on Company and Expert viewsets.
For example, in your ExpertViewSet
:
@detail_route(methods=['post'], , permission_classes=[UserIsAuthenticatedExpert, UserCanModifyCompany])
def recentprojects(self, request, pk=None):
expert = self.get_object()
serializer = RecentProjectSerializer(data=request.data)
if serializer.is_valid():
recent_project = serializer.save(company=somecompany)
recent_project.experts.add(expert)
return Response({'status': 'ok'})
else:
return Response(serializer.errors,
status=status.HTTP_400_BAD_REQUEST)
This will let you post new recent projects to api/v1/experts/{pk}/recentprojects/
.
As for permissions, you need to implement has_object_permission
since this is a single object endpoint:
class UserIsAuthenticatedExpert(permissions.BasePermission):
def has_object_permission(self, request, view, obj):
return some_condition
You can also override get_queryset
together with self.action
to filter Expert or Company instances that the endpoint can operate on, but that will raise 404 errors instead of 403.
Upvotes: 2