2

Django REST Frameworkのドキュメントにあるセットアップと同じ、API URL のベースで変数を使用します。

/api/<brand>/states/<state_pk>/

ベース ブランド スラッグの後の部分はすべて標準の API 形式であるため、ModelViewSets を使用して、オブジェクトのすべてのリスト ビューと詳細ビューを生成します。API 内のすべてがブランドによってフィルタリングされるため、この設定は理にかなっています。

簡略化されたプロジェクト/urls.py

urlpatterns = patterns(
    '',
    url(r'^v2/(?P<brand_slug>\w+)/', include(router.urls, namespace='v2')),
)

簡略化された api/urls.py

router = routers.DefaultRouter()
router.register(r'states', StateViewSet)
router.register(r'cities', CityViewSet)

また、すべてのモデルのハイパーメディア リンクも必要ですが、ここで問題が発生しました。REST フレームワークは、このブランド変数を取得し、それを使用して正しいリンクを生成する方法を知りません。ドキュメントに従ってこの問題を解決しようとすると、2 つの後退が生じます。

  1. ドキュメントは HyperlinkRelatedField クラスを上書きする方法を説明していますが、シリアライザーで動作するようにそのクラスをどこに置くべきかは決して述べていません。
  2. ブランド変数を URL から HyperlinkRelatedField クラスに実際に取得する方法については言及されていません。

ここに欠けている要素は何ですか?

4

1 に答える 1

2

それで、私はそれを理解しました。

URL 変数をシリアライザーに取得する

これを行うには、ModelViewSet の get_serializer_context() メソッドを上書きし、kwargs から変数を送信する必要があります。

class BrandedViewSet(viewsets.ModelViewSet):
    def get_serializer_context(self):
        context = super().get_serializer_context()
        context['brand_slug'] = self.kwargs.get('brand_slug')
        return context

次に、そのクラスですべての ModelViewSets を拡張できます。

class StateViewSet(BrandedViewSet):
    queryset = State.objects.all()
    serializer_class = StateSerializer

すばらしいのは、シリアライザーにこの変数を注入したとしても、 を介して HyperlinkedRelatedField クラスからもアクセスself.contextできることです。これにより、次の部分が可能になります。

追加の URL 変数を使用したカスタム ハイパーメディア リンクの構築

ドキュメントは上書きで正しかったget_url()

class BrandedHyperlinkMixin(object):
    def get_url(self, obj, view_name, request, format):
        """ Extract brand from url
        """
        if hasattr(obj, 'pk') and obj.pk is None:
            return None

        lookup_value = getattr(obj, self.lookup_field)
        kwargs = {self.lookup_url_kwarg: lookup_value}
        kwargs['brand_slug'] = self.context['brand_slug']
        return reverse(
            view_name, kwargs=kwargs, request=request, format=format)

ただし、パート 1 で設定したコンテキストから変数を取得していることに気付くでしょう。ドキュメントが示唆するようにオブジェクトからコンテキストを取得できませんでしたが、この方法はより簡単であることが判明しました。

これが mixin である理由はurl、関連するフィールドのハイパーリンクだけでなく、すべてのハイパーリンクで機能するようにするには、2 つのクラスを拡張する必要があるためです。

class BrandedHyperlinkedIdentityField(BrandedHyperlinkMixin,
                                      serializers.HyperlinkedIdentityField):
    pass


class BrandedHyperlinkedRelatedField(BrandedHyperlinkMixin,
                                     serializers.HyperlinkedRelatedField):
    pass


class BrandedSerializer(serializers.HyperlinkedModelSerializer):
    serializer_related_field = BrandedHyperlinkedRelatedField
    serializer_url_field = BrandedHyperlinkedIdentityField

これで、シリアライザーを安全に拡張でき、ハイパーリンクにブランド変数が表示されます!

class StateSerializer(BrandedSerializer):
    class Meta:
        model = State
        fields = ('url', 'slug', 'name', 'abbrev', )
于 2015-10-20T18:58:44.870 に答える