Django Rest Framework - ModelSerializer'da özel alan nasıl eklenir


89

Bir oluşturdum ModelSerializerve modelimin parçası olmayan özel bir alan eklemek istiyorum.

Fazladan alanlar eklemek için bir açıklama buldum burada ve ben aşağıdakileri denedim:

customField = CharField(source='my_field')

Bu alanı eklediğimde ve validate()işlevimi çağırdığımda bu alan attrdiktenin bir parçası değil . attrekstra alanlar dışında belirtilen tüm model alanlarını içerir. Bu yüzden üzerine yazdığım doğrulamada bu alana erişemiyorum, değil mi?

Bu alanı alan listesine şöyle eklediğimde:

class Meta:
    model = Account
    fields = ('myfield1', 'myfield2', 'customField')

sonra bir hata alıyorum çünkü customFieldmodelimin bir parçası değil - doğru olanı sadece bu serileştirici için eklemek istiyorum.

Özel alan eklemenin herhangi bir yolu var mı?


"Ama benim alanım serileştiricide belirtilen model alanı listesinde olmadığında, validate () attr-sözlüğünün bir parçası değildir.", Bunun çok açık olduğundan emin değilim.
Tom Christie

Ayrıca "modelimde customField alanım olmadığından - doğru bir şekilde şikayet ediyor.", Gördüğünüz istisna hakkında açık olur musunuz - teşekkürler! :)
Tom Christie

Gönderimi güncelledim ve umarım şimdi daha nettir. Modelimin parçası olmayan bir alanı nasıl ekleyebileceğimi öğrenmek istiyorum ...
Ron


Yanıtlar:


63

Doğru olanı yapıyorsunuz, bunun dışında CharField(ve diğer yazılan alanlar) yazılabilir alanlar içindir.

Bu durumda sadece basit bir salt okunur alan istiyorsunuz, bunun yerine şunu kullanın:

customField = Field(source='get_absolute_url')

4
teşekkürler, ama yazılabilir bir alan istiyorum. Kullanıcımı tanımlayan belirli bir kullanıcı jetonu iletiyorum. ama benim modelimde token değil kullanıcıya sahibim. bu yüzden belirteci iletmek ve onu bir sorgu aracılığıyla bir kullanıcı nesnesine "dönüştürmek" istiyorum.
Ron

sonraki şey, kaynağın bir model özelliğini hedeflemesi gerektiğidir, değil mi? benim durumumda işaret edecek bir özelliğim yok.
Ron

Yorumun kullanıcı / simge bitini anlamıyorum. Ancak, serileştiriciye, bir model örneğine geri yüklemeden önce kaldırılan bir alanı dahil etmek istiyorsanız .validate(), özniteliği kaldırmak için yöntemi kullanabilirsiniz . Bkz: django-rest-framework.org/api-guide/serializers.html#validation Gerçekten kullanım senaryosunu anlamıyorum bile, neye ihtiyacınız yapardım O veya bir neden istediğini yazılabilir a ile iç içedir alanı salt okunur özellik get_absolute_url?
Tom Christie

unutmak get_absolute_urlsadece kopyalayıp dokümanlardan onu paste'd I. Ben sadece içinde erişebileceğim normal bir yazılabilir alan istiyorum validate(). Bu sourceözelliğe ihtiyacım olacağını tahmin ettim ...
Ron

Bu daha mantıklı. :) Değer doğrulamak için geçmelidir, bu nedenle serileştiriciyi nasıl başlattığınızı ve bu değerin gerçekten sağlanıp sağlanmadığını iki kez kontrol ederim.
Tom Christie

85

Aslında hiçbir modele dokunmadan bir çözüm var. SerializerMethodFieldSerileştiricinize herhangi bir yöntemi takmanıza izin veren kullanabilirsiniz .

class FooSerializer(ModelSerializer):
    foo = serializers.SerializerMethodField()

    def get_foo(self, obj):
        return "Foo id: %i" % obj.pk

6
OP belirtildiği gibi bu yorumun , onlar yazılabilir bir alanı, istediğiniz SerializerMethodFieldler değildir
esmail

14

... netlik açısından, aşağıdaki şekilde tanımlanan bir Model Yönteminiz varsa:

class MyModel(models.Model):
    ...

    def model_method(self):
        return "some_calculated_result"

Söz konusu yöntemi çağırmanın sonucunu serileştiricinize şu şekilde ekleyebilirsiniz:

class MyModelSerializer(serializers.ModelSerializer):
    model_method_field = serializers.CharField(source='model_method')

ps Özel alan modelinizde gerçekten bir alan olmadığından, genellikle bunu salt okunur yapmak istersiniz, örneğin:

class Meta:
    model = MyModel
    read_only_fields = (
        'model_method_field',
        )

3
Ya yazılabilir olmasını istersem?
Csaba Toth

1
@Csaba: Sadece ek içerik için tasarruf yazma özel ve silme kanca gerekir: Bkz "Kaydet ve silme kancaları" "Yöntemleri" başlığı altında ( Burada ) Sen yazma özel gerekir perform_create(self, serializer), perform_update(self, serializer), perform_destroy(self, instance).
Lindauson

13

Sorunuzun cevabı burada. Model Hesabınıza eklemelisiniz:

@property
def my_field(self):
    return None

şimdi kullanabilirsiniz:

customField = CharField(source='my_field')

kaynak: https://stackoverflow.com/a/18396622/3220916


6
Bu yaklaşımı mantıklı olduğunda kullandım, ancak yalnızca belirli API çağrıları için gerçekten kullanılan şeyler için modellere fazladan kod eklemek harika değil.
Andy Baker

1
Şunun

10

Göstermek self.author.full_nameiçin bir hata aldım Field. Şunlarla çalıştı ReadOnlyField:

class CommentSerializer(serializers.HyperlinkedModelSerializer):
    author_name = ReadOnlyField(source="author.full_name")
    class Meta:
        model = Comment
        fields = ('url', 'content', 'author_name', 'author')

6

Django Rest Framework'ün son sürümü ile modelinizde eklemek istediğiniz alanın adıyla bir yöntem oluşturmanız gerekir.

class Foo(models.Model):
    . . .
    def foo(self):
        return 'stuff'
    . . .

class FooSerializer(ModelSerializer):
    foo = serializers.ReadOnlyField()

    class Meta:
        model = Foo
        fields = ('foo',)

4

Bir model serileştiriciye yazılabilir bir özel alan eklemek için bir çözüm arıyordum. Bu sorunun yanıtlarında ele alınmayan bunu buldum.

Görünüşe göre gerçekten kendi basit Serileştiricinizi yazmanız gerekiyor.

class PassThroughSerializer(serializers.Field):
    def to_representation(self, instance):
        # This function is for the direction: Instance -> Dict
        # If you only need this, use a ReadOnlyField, or SerializerField
        return None

    def to_internal_value(self, data):
        # This function is for the direction: Dict -> Instance
        # Here you can manipulate the data if you need to.
        return data

Artık bu Serileştiriciyi bir ModelSerializer'a özel alanlar eklemek için kullanabilirsiniz.

class MyModelSerializer(serializers.ModelSerializer)
    my_custom_field = PassThroughSerializer()

    def create(self, validated_data):
        # now the key 'my_custom_field' is available in validated_data
        ...
        return instance

Bu aynı zamanda, Model MyModelgerçekten adlandırılan bir özelliğe sahipse, my_custom_fieldancak onun doğrulayıcılarını göz ardı etmek istiyorsanız da işe yarar .


yani my_custom_field, MyModel'in bir özelliği değilse çalışmaz, değil mi? Hatayı aldım Serileştirici alanı yanlış adlandırılmış olabilir ve örnekteki herhangi bir özellik veya anahtarla eşleşmeyebilir MyModel.
Sandeep Balagopal

3

Buradaki tüm cevapları okuduktan sonra, bunu temiz bir şekilde yapmanın imkansız olduğu sonucuna varıyorum. Kirli oynamalı ve bir write_only alanı oluşturmalı ve sonra validateve to_representationyöntemlerini geçersiz kılmalısınız . Bu benim için çalıştı:

class FooSerializer(ModelSerializer):

    foo = CharField(write_only=True)

    class Meta:
        model = Foo
        fields = ["foo", ...]

    def validate(self, data):
        foo = data.pop("foo", None)
        # Do what you want with your value
        return super().validate(data)

    def to_representation(self, instance):
        data = super().to_representation(instance)
        data["foo"] = whatever_you_want
        return data
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.