ルックアップフィールドとしてid
を使用して歴史的に機能する複数のAPIがあります。
/api/organization/10
私はそれらのAPIを消費するフロントエンドを持っています。
私は新しいインターフェースを構築していますが、いくつかの理由で、IDの代わりにスラッグを使用したいと思います。
/api/organization/my-orga
APIはDjango Rest Frameworkで構築されています。ルックアップフィールドの変更を除いて、APIの動作は同じままである必要があります。
APIがslug
とpk
の両方で機能するようにするソリューションはありますか?これらの2つのパスは、同じ結果をもたらすはずです。
/api/organization/10
/api/organization/my-orga
これが私のAPI定義です:
# urls.py
router = DefaultRouter()
router.register(r'organization', Organization)
urlpatterns = router.urls
#view.py
class Organization(viewsets.ModelViewSet):
queryset = OrganisationGroup.objects.all()
serializer_class = OrganizationSerializer
# serializer.py
class OrganizationSerializer(PermissionsSerializer):
class Meta:
model = Organization
ご協力いただきありがとうございます。
これを試して
from Django.db.models import Q
import operator
class MultipleFieldLookupMixin(object):
def get_object(self):
queryset = self.get_queryset() # Get the base queryset
queryset = self.filter_queryset(queryset) # Apply any filter backends
filter = {}
for field in self.lookup_fields:
filter[field] = self.kwargs[field]
q = reduce(operator.or_, (Q(x) for x in filter.items()))
return get_object_or_404(queryset, q)
次に表示
class Organization(MultipleFieldLookupMixin, viewsets.ModelViewSet):
queryset = OrganisationGroup.objects.all()
serializer_class = OrganizationSerializer
lookup_fields = ('pk', 'another field')
お役に立てれば。
class MultipleFieldLookupMixin(object):
"""
Apply this mixin to any view or viewset to get multiple field filtering
based on a `lookup_fields` attribute, instead of the default single field filtering.
"""
def get_object(self):
queryset = self.get_queryset() # Get the base queryset
queryset = self.filter_queryset(queryset)
filter = {}
for field in self.lookup_fields:
if self.kwargs[field]: # Ignore empty fields.
filter[field] = self.kwargs[field]
return get_object_or_404(queryset, **filter) # Lookup the object
class RetrieveUserView(MultipleFieldLookupMixin, generics.RetrieveAPIView):
queryset = User.objects.all()
serializer_class = UserSerializer
lookup_fields = ('account', 'username')
retrieve
メソッドをオーバーライドし、pk
フィールドの値を任意のパターンと照合することで、同様の問題を解決しました。たとえば、数字だけで構成されている場合です。
def retrieve(self, request, *args, **kwargs):
if kwargs['pk'].isdigit():
return super(Organization, self).retrieve(request, *args, **kwargs)
else:
# get and return object however you want here.
基本的な答えは、これは適切なREST/API設計ではなく、DRFが可能にするものではないということだと思います。
公式ドキュメントには、この例があります https://www.Django-rest-framework.org/api-guide/generic-views/#creating-custom-mixins
また、urls.py
を変更して、同じビューの新しいルートを新しいフィールド名で追加する必要があります。
get_object(self)
メソッドをオーバーライドするのが最善の方法だと思います
class Organization(generics.RetrieveAPIView):
serializer_class = OrganizationSerializer
queryset = Organization.objects.all()
multiple_lookup_fields = ['pk', 'slug']
def get_object(self):
queryset = self.get_queryset()
filter = {}
for field in self.multiple_lookup_fields:
filter[field] = self.kwargs[field]
obj = get_object_or_404(queryset, **filter)
self.check_object_permissions(self.request, obj)
return obj