DRF Фильтрация модели по идентификатору другой модели
У меня есть эти модели:
class Organization(models.Model):
name = models.CharField(
"Organization name", max_length=100, unique=True
)
description = models.TextField("Organization description")
districts = models.ManyToManyField(
"District",
related_name="organizations",
blank=True,
)
class District(models.Model):
name = models.CharField("District name", max_length=100, unique=True)
И мне нужно отфильтровать организации по идентификатору района, поэтому url должен быть:
organizations/<district_id>/
Какой способ лучше?
В настоящее время у меня есть два решения, первое:
urls.py
router.register("organizations", OrganizationViewSet, basename="organizations")
router.register(
"organizations/(?P<district_id>\d+)",
OrganizationViewSet,
basename="organizations_by_district",
)
views.py
class OrganizationViewSet(viewsets.ModelViewSet):
serializer_class = OrganizationSerializer
def get_queryset(self):
district = self.kwargs.get("district_id")
if district:
return Organization.objects.filter(districts__in=[district])
return Organization.objects.all()
Второе решение:
urls.py
urlpatterns = [
path(r"organizations/<int:district_id>/",
get_orgs_by_district, name="org_by_district"),
...
]
views.py
@api_view(http_method_names=['GET'])
def get_orgs_by_district(request, district_id):
objs = Organization.objects.filter(districts__in=[district_id])
data = OrganizationSerializer(objs, many=True).data
return Response(data, status=200)
Оба решения работают, но какое из них лучше? И может быть есть другое решение, о котором я не знаю?
Если ваш параметр необязателен, я бы просто использовал параметры запроса, чтобы у вас был только один url для обоих случаев:
# views.py
from rest_framework.generics import ListAPIView
class OrganizationsList(ListAPIView):
serializer_class = OrganizationSerializer
def get_queryset(self):
queryset = Organization.objects.all()
district = self.request.query_params.get('district_id')
if district:
queryset = queryset.filter(districts__in=[district])
return queryset
# urls.py
urlpatterns = [
path('organizations/', views.OrganizationsList.as_view(), name='organizations_list'),
...
]
Вы бы вызвали свой API следующим образом:
{{base_url}}/organizations/ # Retrieve all organizations
{{base_url}}/organizations/?district_id=5 # Filter against district_id
Больше подробностей в официальном документе здесь.