web-dev-qa-db-ja.com

Django Restフレームワーク、ModelSerializerに「__all__」フィールドと関連フィールドを含める方法?

私は2つのモデルを持っています。1つはM2M関係で、もう1つは関連する名前です。 allフィールドをシリアライザーと関連フィールドに含めたい。

models.py:

class Pizza(models.Model):
    name = models.CharField(max_length=50, unique=True)
    toppings = models.ManyToManyField(Topping, null=True, blank=True, related_name='pizzas')

class Topping(models.Model):
    name = models.CharField(max_length=50, unique=True)
    price = models.IntegerField(default=0)

serializer.py:

class ToppingSerializer(serializers.ModelSerializer):
    class Meta:
        model = Topping
        fields = '__all__' 

これは機能しますが、関連フィールドは含まれません。

 fields = ['name', 'price', 'pizzas'] 

これは私が望むとおりに機能しますが、Toppingsモデルに多くのフィールドがあるとどうなりますか。私は次のようなことをしたい:

fields = ['__all__', 'pizzas']

この構文では、次のエラーが発生します。

フィールド名 __all__はモデルには無効です

目的の動作を実現する方法はありますか?または、関連する名前を使用する場合、フィールドを手動で入力する必要がありますか?

21
Curtwagner1984

Django Rest Frameworkのソースコードを確認しました。フレームワークで必要な動作がサポートされていないようです。

fieldsオプションは、リスト、タプル、またはテキスト__all__でなければなりません。

関連するソースコードのスニペットを次に示します。

    ALL_FIELDS = '__all__'
    if fields and fields != ALL_FIELDS and not isinstance(fields, (list, Tuple)):
        raise TypeError(
            'The `fields` option must be a list or Tuple or "__all__". '
            'Got %s.' % type(fields).__name__
        )

タプルまたはフィールドのリストに「all」を追加することはできません...

17
DanEEStar

@DanEEStartが言ったように、DjangoRestFrameworkには、フィールドの 'all'値を拡張する簡単な方法がありません。なぜなら、get_field_namesメソッドは設計される そのように動作する

しかし、幸いなことに、このメソッドをオーバーライドして、大量のフィールドを列挙することなく、すべてのフィールドと関係を簡単に含めることができます。

このメソッドを次のようにオーバーライドします。

class ToppingSerializer(serializers.ModelSerializer):

    class Meta:
        model = Topping
        fields = '__all__'
        extra_fields = ['pizzas']

    def get_field_names(self, declared_fields, info):
        expanded_fields = super(ToppingSerializer, self).get_field_names(declared_fields, info)

        if getattr(self.Meta, 'extra_fields', None):
            return expanded_fields + self.Meta.extra_fields
        else:
            return expanded_fields

このメソッドはこのシリアライザーの動作を変更するだけであり、extra_fields属性はこのシリアライザークラスでのみ機能することに注意してください。

このようなシリアライザーがたくさんある場合は、中間クラスを作成して、このget_fields_namesメソッドを1か所に含め、何度でも再利用できます。このようなもの:

class CustomSerializer(serializers.HyperlinkedModelSerializer):

    def get_field_names(self, declared_fields, info):
        expanded_fields = super(CustomSerializer, self).get_field_names(declared_fields, info)

        if getattr(self.Meta, 'extra_fields', None):
            return expanded_fields + self.Meta.extra_fields
        else:
            return expanded_fields


class ToppingSerializer(CustomSerializer):

    class Meta:
        model = Topping
        fields = '__all__'
        extra_fields = ['pizzas']

class AnotherSerializer(CustomSerializer):

    class Meta:
        model = Post
        fields = '__all__'
        extra_fields = ['comments']
25
hugoruscitti

古い問題ですが、これは将来他の人を助けるかもしれないと考えました。

同様の問題が発生し、次の例のように手動で追加フィールドを指定することで「all」オプションが機能するようになりました。これで問題が解決するかどうかはわかりません。それは私が見た他のものよりもすっきりした光景です。

http://www.Django-rest-framework.org/api-guide/relations/#nested-relationships

class TrackSerializer(serializers.ModelSerializer):
    class Meta:
        model = Track
        fields = '__all__'

class AlbumSerializer(serializers.ModelSerializer):
    tracks = TrackSerializer(many=True, read_only=True)

    class Meta:
        model = Album
        fields = '__all__'

私はこれが同じページにリストされている他の関連フィールドオプションのいずれでも機能すると仮定します: http://www.Django-rest-framework.org/api-guide/relations/#serializer-relations =

Django Rest Frameworkバージョン3.6.2を使用しています

要求された逆関係の例:

class TrackSerializer(serializers.ModelSerializer):
    album = AlbumSerializer(source='album_id')

    class Meta:
        model = Track
        fields = '__all__'
12
Aiky30

こんにちは、 Djangoの_meta API を使用することで期待どおりの結果を得ることができました。Django 1.11。

model = MyModel
fields = [field.name for field in model._meta.fields]
fields.append('any_other_field')

プログラミングでは、常に同じ結果を達成するための多くの方法がありますが、上記のこの方法は私にとって本当に効果的です。

乾杯!

6
Wand

シリアライザーで定義されているすべてのフィールドと他のフィールドを含めるには、exclude = ()とだけ言うことができます

class ToppingSerializer(serializers.HyperlinkedModelSerializer):
   pizzas = '<>' #the extra attribute value
    class Meta:
        model = Topping
        exclude = ()

これにより、すべてのフィールド値と追加の引数pizzasがリストされます。

2
riyasyash

これは私がやった方法です、はるかに簡単です

class OperativeForm(forms.ModelForm):
    class Meta:
        model = Operative
        fields = '__all__'
        exclude = ('name','objective',)
        widgets = {'__all__':'required'}
0