2016-07-12 7 views

答えて

0

Djangoの残りのフレームワークは、少なくともバージョン2.xに、これは簡単なことはない - と私は/私は、これは中に固定ハッキングバージョンではそれを改善するために任意の計画3.

があったされているかどうかわかりませんシリアライザ内のtryキャッチを持つさまざまな場所で、問題を標準化しようとする前に、データ・ディクショナリに渡された親プロパティによって該当するフィールドのクエリーセットがフィルタリングされます。

SlugRelatedDependentField

class SlugRelatedDependentField(SlugRelatedField): 
    def __init__(self, depends_on=None, **kwargs): 
     assert depends_on is not None, 'The `depends_on` argument is required.' 

     self.depends_on  = depends_on # archive_unit__organization or organization 
     self.depends_segments = self.depends_on.split('__') 
     self.depends_parent = self.depends_segments.pop(0) 
     self.depends_field = SimpleLazyObject(lambda: self.parent.parent.fields[self.depends_parent]) 
     self.depends_queryset = SimpleLazyObject(lambda: self.depends_field.queryset) 
     self.depends_model = SimpleLazyObject(lambda: self.depends_queryset.model) 

     super(SlugRelatedDependentField, self).__init__(**kwargs) 

    def contextualize(self, instance, data): 
     self.data = data 
     self.instance = instance 

    def get_queryset(self): 
     try: 
      return self.queryset.filter(**{self.depends_on: reduce(getattr, self.depends_segments, self.get_relation())}) 
     except self.depends_model.DoesNotExist: 
      # if parent was absent or invalid, empty the queryset 
      return self.queryset.none() 
     except TypeError: 
      # if parent was a Page instance, use the full queryset, it's only a list view 
      return self.queryset.all() 

    def get_relation(self): 
     try: 
      # if an allowed parent was passed, filter by it 
      return self.depends_queryset.get(**{self.depends_field.slug_field: self.data[self.depends_parent]}) 
     except (KeyError, TypeError): 
      # if data was empty or no parent was passed, try and grab it off of the model instance 
      if isinstance(self.instance, self.parent.parent.Meta.model): 
       return getattr(self.instance, self.depends_parent) 
      elif self.instance is None: 
       raise self.depends_model.DoesNotExist 
      else: 
       raise TypeError 

使用

class RepositorySerializer(ModelSerializer): 
    organization = SlugRelatedField(queryset=Organization.objects.all(), slug_field='slug') 
    teams = SlugRelatedDependentField(allow_null=True, depends_on='organization', many=True, queryset=Team.objects.all(), required=False, slug_field='slug') 

    def __init__(self, instance=None, data=empty, **kwargs): 
     f = self.fields['teams'] 

     # assign instance and data for get_queryset 
     f.child_relation.contextualize(instance, data) 

     # inject relation values from instance if they were omitted so they are validated regardless 
     if data is not empty and instance and name not in data: 
      data[name] = [getattr(relation, f.child_relation.slug_field) for relation in getattr(instance, name).all()] 

     super(RepositorySerializer, self).__init__(instance=instance, data=data, **kwargs) 

概要

SlugRelatedDependentFieldはを受け入れるために定期的SlugRelatedFieldを拡張しますkwargは、フィールドの他のフィールドとの関係を表す文字列を受け入れます。この例では、このレポジトリに割り当てられたチームが組織に属していなければならないと説明しています。親が存在しない場合、私は.none()でクエリセットを空にする

いくつかの落とし穴

  • 、これはそうでないOPTIIONS要求と検証メッセージを介して公開することができる選択肢漏れを回避し、通常は望ましくありません。
  • 親レコードを照会するときにdataを使用しました。これは、親フィールドのオブジェクトが一致していない可能性がありますが、dataが一貫して使用できるためです。 PATCHリクエストの場合
  • シリアライザinitの後半部分に省略されたリレーション値を挿入することに気付くでしょう。これは、検証が多くのフィールドで実行されるように強制します。ユーザーがPATCHリクエスト内のレコードのorganizationを変更した場合、割り当て済みのteamsは適用されなくなりました。

遠い関係のサポート

このソリューションは、のために食料調達するもう一つの問題は、遠い関係を参照している、これはdepends_on例えばに__区切られた文字列を渡すことで行うことができますrepository__organization、私はこれのための素晴らしい例のユースケースを持っていませんが、それが必要な場合はそこにあります。

関連する問題