В моем приложении Django-Rest-Framework мне нужно разделить API на две ветви, например:
/api/public/...
/api/private/...
Рассмотрим модель Analysis
вот так:
from django.db import models
from django.conf import settings
class Analysis(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
public = models.BooleanField(default=True)
То, что я хочу, это:
/api/public/analysis
=› отфильтровать набор запросов с помощьюQ(public=True)
/api/private/analysis
=› отфильтровать набор запросов с помощьюQ(user=request.user) | Q(public=False)
Аналогичный шаблон требуется в моделях 5+.
Я подумал о двух недоработанных решениях:
1. AbstractViewSet
делится на PublicViewSet
и PrivateViewSet
class AbstractAnalysisViewSet(viewsets.ReadOnlyModelViewSet):
queryset = Analysis.objects.all()
serializer_class = AnalysisSerializer
ordering = [
"-created_at",
]
permission_classes = [IsAuthenticated,]
class PrivateAnalysisViewSet(AbstractAnalysisViewSet):
def get_permissions(self):
permissions = super(PrivateAnalysisViewSet, self).get_permissions()
if self.action in ["retrieve"]:
permissions.append(HasObjectPermission())
return permissions
def get_queryset(self):
queryset = super(PrivateAnalysisViewSet, self).get_queryset()
if self.action in ["list"]:
auth_user = self.request.user
query = Q(user=auth_user) | Q(public=False)
queryset = queryset.filter(query)
return queryset
class PublicAnalysisViewSet(AbstractAnalysisViewSet):
def get_permissions(self):
permissions = super(PublicAnalysisViewSet, self).get_permissions()
if self.action in ["retrieve"]:
permissions.append(IsPublicObjectPermission())
return permissions
def get_queryset(self):
queryset = super(AnalysisViewSet, self).get_queryset()
if self.action in ["list"]:
query = Q(public=True)
queryset = queryset.filter(query)
return queryset
Это будет работать, но я действительно не хочу дублировать представления в несколько классов, потому что тогда мне также нужно зарегистрировать несколько наборов представлений с помощью DRF router
. Как я уже сказал, я должен применить один и тот же шаблон в 5 моделях, а это означает, что 5 * 3 = 15 классов наборов представлений, которые трудно поддерживать с течением времени, и их число быстро увеличивается по мере увеличения размера моего приложения.
2. Определите private
или public
путем разбора self.request.path
class AnalysisViewSet(viewsets.ReadOnlyModelViewSet):
queryset = Analysis.objects.all()
serializer_class = AnalysisSerializer
ordering = [
"-created_at",
]
permission_classes = [IsAuthenticated,]
def get_permissions(self):
permissions = super(PublicAnalysisViewSet, self).get_permissions()
if self.action in ["retrieve"]:
if "/private/" in self.request.path:
permissions.append(HasObjectPermission())
else:
permissions.append(IsPublicObjectPermission())
return permissions
Мне нравится этот подход, но я не могу понять, как зарегистрировать этот набор представлений в DRF router
, чтобы он позволял использовать префикс /public/
или /private/
.
Любые другие интересные идеи для решения этой проблемы приветствуются и высоко ценятся.