2016-07-08 8 views
0

DRFといくつかのシリアライザに奇妙な問題があります。あなたが見ることができるようにインスタンス化時のDjango RESTフレームワークシリアライザエラー

class Accommodation(models.Model): 
    created = models.DateTimeField(auto_now_add=True) 
    modified = models.DateTimeField(auto_now=True) 
    product = models.OneToOneField(
     Product, 
     on_delete=models.CASCADE, 
     primary_key=True, 
    ) 
    description = models.TextField(null=True, blank=True, verbose_name=_(u'Description')) 
    shared_accommodation = models.BooleanField(default=False) 
    accommodation_unit_quantity = models.PositiveSmallIntegerField(default=1, 
                   verbose_name=_(u'Number of acommodation units ' 
                       u'for this acommodation')) 
    accommodation_unit_name = models.TextField(null=False, blank=False, verbose_name=_(u'Name for accommodation units ' 
                        u'for this accommodation')) 

    class Meta: 
     verbose_name_plural = _(u'Accommodations') 

    def __unicode__(self): 
     return u'{0} <{1}>'.format(self.product.name, self.product.school) 

class Product(AbstractProduct): 

    name = models.CharField(max_length=50, verbose_name=_(u'Name')) 
    school = models.ForeignKey('school.School') 
    levels = models.ManyToManyField('school.Level',verbose_name=_(u'Level')) 
    age = IntegerRangeField(null=True) 
    gender = models.CharField(choices=GENDER_CHOICES, max_length=1, null=True, blank=True, verbose_name=_(u'Gender')) 
    num_sessions = models.PositiveSmallIntegerField(
     verbose_name=_(u'Number of sessions'), 
     default=1, 
     help_text=_(u"Number of sessions that the product has."), 
    ) 
    school_category = models.ForeignKey(
     'school.Category', 
     blank=True, null=True, 
     verbose_name=_(u'Category') 
    ) 
    addons = models.ManyToManyField('self', 
     verbose_name=_(u'Administrators'), 
     through='AddonInService', 
     symmetrical=False, 
     related_name='addon_can_be_used_in' 
    ) 

    pay_option = models.CharField(choices=PAYMENT_OPTIONS, max_length=1, null=True, blank=True, verbose_name=_(u'Pay_option'), default='U') 
    payment_type = models.CharField(choices=PAYMENT_TYPE, max_length=1, null=True, blank=True, verbose_name=_(u'pay_type')) 
    payment_amount = models.FloatField(verbose_name=_(u'Amount'), default=0.0) 

    objects = ProductManager() 

    class Meta(AbstractProduct.Meta): 
     verbose_name_plural = _(u'Products') 

    def __unicode__(self): 
     return self.name 

、基本的に製品が宿泊することができます:

は、ここに私のモデルです。ここで私は宿泊を作成しようとする簡単なテストを実行するシリアライザ

class AccommodationSerializer(serializers.ModelSerializer): 
    class Meta: 
     model = Accommodation 
     fields = [ 
      'description', 
      'shared_accommodation', 
      'accommodation_unit_quantity', 
      'accommodation_unit_name', 
     ] 


class ProductAccommodationSerializer(ProductSerializer): 

    accommodation = AccommodationSerializer() 

    class Meta(ProductSerializer.Meta): 
     fields = [ 
      'id', 
      'structure', 
      'upc', 
      'title', 
      'slug', 
      'description', 
      'rating', 
      'date_created', 
      'date_updated', 
      'is_discountable', 
      'name', 
      'age', 
      'gender', 
      'num_sessions', 
      'parent', 
      'product_class', 
      'school', 
      'levels', 
      'school_category', 
      'addons', 
      'color', 
      'price', 
      'all_prices', 
      'variants', 
      'pay_option', 
      'payment_type', 
      'payment_amount', 
      'accommodation', 
     ] 

    def create(self, validated_data): 
     accommodation_data = validated_data.pop('accommodation') 

     levels = [] 
     if 'levels' in validated_data: 
      levels = validated_data.pop('levels') 

     product = Product.objects.create(**validated_data) 
     school_accommodation, created = ProductClass.objects.get_or_create(name='School Accommodation') 
     if created: 
      product.product_class = school_accommodation 
     for lev in levels: 
      product.levels.add(lev) 
     product.save() 

     acc = AccommodationSerializer(product=product, **accommodation_data) 
     acc.save() 
     return product 

class ProductSerializer(serializers.ModelSerializer): 
    age = IntegerRangeField() 
    addons = AddonSerializer(many=True, read_only=True) 
    # Get the price for the Product, using the property in the Model 
    price = serializers.DecimalField(required=False, max_digits=7, 
           decimal_places=2, source='get_price', 
           read_only=True) 
    color = serializers.SerializerMethodField() 

    all_prices = PriceSerializer(source='stockrecords', many=True, 
            required=False) 

    variants = VariantSerializer(many=True, source='children', required=False) 

    class Meta: 
     model = Product 
     fields = [ 
      'id', 
      'structure', 
      'upc', 
      'title', 
      'slug', 
      'description', 
      'rating', 
      'date_created', 
      'date_updated', 
      'is_discountable', 
      'name', 
      'age', 
      'gender', 
      'num_sessions', 
      'parent', 
      'product_class', 
      'school', 
      'levels', 
      'school_category', 
      'addons', 
      'color', 
      'price', 
      'all_prices', 
      'variants', 
      'pay_option', 
      'payment_type', 
      'payment_amount' 
     ] 

は、私は次のエラーを取得している:

Traceback (most recent call last): 
File "/home/internetmosquito/git/mvp_opencoast/opencoast_django/opencoast/applications/accommodation/tests/test_accommodations.py", line 165, in test_create_accommodation 
response = self.client.post(url, data, format='json') 
File "/home/internetmosquito/python_envs/opencoast_django/local/lib/python2.7/site-packages/rest_framework/test.py", line 170, in post 
path, data=data, format=format, content_type=content_type, **extra) 
File "/home/internetmosquito/python_envs/opencoast_django/local/lib/python2.7/site-packages/rest_framework/test.py", line 92, in post 
return self.generic('POST', path, data, content_type, **extra) 
File "/home/internetmosquito/python_envs/opencoast_django/local/lib/python2.7/site-packages/django/test/client.py", line 380, in generic 
return self.request(**r) 
File "/home/internetmosquito/python_envs/opencoast_django/local/lib/python2.7/site-packages/rest_framework/test.py", line 159, in request 
return super(APIClient, self).request(**kwargs) 
File "/home/internetmosquito/python_envs/opencoast_django/local/lib/python2.7/site-packages/rest_framework/test.py", line 111, in request 
request = super(APIRequestFactory, self).request(**kwargs) 
File "/home/internetmosquito/python_envs/opencoast_django/local/lib/python2.7/site-packages/django/test/client.py", line 467, in request 
six.reraise(*exc_info) 
File "/home/internetmosquito/python_envs/opencoast_django/local/lib/python2.7/site-packages/django/core/handlers/base.py", line 149, in get_response 
response = self.process_exception_by_middleware(e, request) 
File "/home/internetmosquito/python_envs/opencoast_django/local/lib/python2.7/site-packages/django/core/handlers/base.py", line 147, in get_response 
response = wrapped_callback(request, *callback_args, **callback_kwargs) 
File "/home/internetmosquito/python_envs/opencoast_django/local/lib/python2.7/site-packages/django/views/decorators/csrf.py", line 58, in wrapped_view 
return view_func(*args, **kwargs) 
File "/home/internetmosquito/python_envs/opencoast_django/local/lib/python2.7/site-packages/rest_framework/viewsets.py", line 87, in view 
return self.dispatch(request, *args, **kwargs) 
File "/home/internetmosquito/python_envs/opencoast_django/local/lib/python2.7/site-packages/rest_framework/views.py", line 466, in dispatch 
response = self.handle_exception(exc) 
File "/home/internetmosquito/python_envs/opencoast_django/local/lib/python2.7/site-packages/rest_framework/views.py", line 463, in dispatch 
response = handler(request, *args, **kwargs) 
File "/home/internetmosquito/python_envs/opencoast_django/local/lib/python2.7/site-packages/rest_framework/mixins.py", line 21, in create 
self.perform_create(serializer) 
File "/home/internetmosquito/python_envs/opencoast_django/local/lib/python2.7/site-packages/rest_framework/mixins.py", line 26, in perform_create 
serializer.save() 
File "/home/internetmosquito/python_envs/opencoast_django/local/lib/python2.7/site-packages/rest_framework/serializers.py", line 191, in save 
self.instance = self.create(validated_data) 
File "/home/internetmosquito/git/mvp_opencoast/opencoast_django/opencoast/applications/accommodation/serializers.py", line 77, in create 
acc = AccommodationSerializer(product=product, **accommodation_data) 
File "/home/internetmosquito/python_envs/opencoast_django/local/lib/python2.7/site-packages/rest_framework/serializers.py", line 95, in __init__ 
super(BaseSerializer, self).__init__(**kwargs) 
TypeError: __init__() got an unexpected keyword argument 'product' 

製品=製品

を削除しようとしました

から

acc = AccommodationSerializer(product=product, **accommodation_data) 

しかし、私は同じエラーが、製品の代わりに 'shared_accommodation'フィールドと

私はここで間違っているのですか?何か案は?

EDIT:いくつかによって示唆されるように、私はAccommodationSerializerに、製品のフィールドを追加しました::追加ProductSerializer、私は

その1申し訳ありませんSECOND EDITを逃した

class AccommodationSerializer(serializers.ModelSerializer): 
    class Meta: 
     model = Accommodation 
     fields = [ 
      'product', 
      'description', 
      'shared_accommodation', 
      'accommodation_unit_quantity', 
      'accommodation_unit_name', 
     ] 

しかし、その後、作成しようとすると私はな生産を作成していないにもかかわらず、(テスト・データ・ペイロードに製品を追加した場合、十分な

{'accommodation': OrderedDict([('product', [u'This field is required.'])])} 

おかしい:インスタンス、私は次のエラーを取得します私が宿泊、dissappears上記のエラーをするためにエンドポイントを呼び出す時点)で、T:

data = { 
     "name": "Hotel Hudson", 
     "slug": "hotel-hudson", 
     "age": {'upper': 99, 'lower': 18}, 
     "school": school1.id, 
     "levels": [school1.level_set.all()[0].id], 
     "accommodation": { 
      "product": 1, 
      "description": "A very nice hotel", 
      "shared_accommodation": False, 
      "accommodation_unit_quantity": 1, 
      "accommodation_unit_name": "Room", 
      "accommodation_units": [ 
       { 
        'name': "Room-1", 
        'max_pax': 1, 
       }, 
       { 
        'name': "Room-2", 
        'max_pax': 3, 
       }, 
      ] 
     }, 
    } 

これは面白いですが、これは私が欲しいものは明らかではありません...私は合格する必要がしたくありません宿泊施設を作成するためにエンドポイントを呼び出すときに偽の製品ID ...任意のポインタ?

+0

ちょうど 'AccommodationSerializer(宿泊データ)'、ないkwargs。どのように 'product'を' accommodation_data'に置くかは、回答者に任せます。 – Brian

+0

ProductAcceterminedSerializer - メタクラス... add 'model = Product' – Jerzyk

+0

本当に' class Meta(ProductSerializer.Meta) 'が好きではない – Jerzyk

答えて

1

DRFシリアライザ階層のキーワードが一般的ではないため、dataフィールドを使用するのは正しい方法です。 dataに指定した辞書が有効な場合は、.is_valid()を呼び出した後に.save()でモデルインスタンスを作成できます。もちろん、モデルを作成する前に辞書を追加の属性で拡張することもできます。しかし、シリアライザは、シリアライザのMeta.fieldsフィールドで指定されている属性のみを使用することに注意してください。

AccomodationSerializer.Meta.fieldsにはproductフィールドは含まれていません。これは、モデルを作成する場合は必須です。

Accommodationモデルからの読み取りには、または何らかの理由でモデルの部分構造を投稿したい場合は、AccommodationSerializerを使用しても問題ありません。しかし、モデル・インスタンスを作成するためにそれを使用する場合は、ヌル可能でないか、またはデフォルト値を持つすべてのフィールドを指定する必要があります。

代わりに、ここでAccommodationSerializerを使用しての、あなただけ呼び出すことができます。

Accommodation.objects.create(product=product, **accommodation_data) 

私は、最小限の例を設定してみました。お役に立てれば。

models.py:

class Owner(models.Model): 

    owner_name = models.CharField(max_length=255) 


class Product(models.Model): 

    name = models.CharField(max_length=255) 
    owner = models.OneToOneField(Owner) 

serializer.py

class OwnerSerializer(serializers.ModelSerializer): 

    class Meta: 
     model = Owner 
     fields = [ 
      'owner_name', 
     ] 

class ProductSerializer(serializers.ModelSerializer): 

    owner = OwnerSerializer(read_only=True) 

    class Meta: 
     model = Product 
     fields = [ 
      'owner', 
      'name', 
     ] 


class ProductOwnerSerializer(serializers.ModelSerializer): 

    product = ProductSerializer() 

    class Meta: 
     model = Owner 
     fields = [ 
      'product', 
      'owner_name', 
     ] 

    def create(self, validated_data): 
     product_data = validated_data.pop('product') 
     owner = Owner.objects.create(**validated_data) 
     Product.objects.create(owner=owner, **product_data) 
     return owner 

私も、私にアンチパターンのように思える、私は本当にMeta(Superclass)を好きではないことを、Jerzykさんのコメントに同意します。

+0

詳細な応答をいただきありがとうございます。私はAccommodationSerializerに '製品'を追加しようとしましたが、このエラーが発生します。あなたが提案したものを試してみましたが、動作しますが、オブジェクトをインスタンス化してAccommodationSerializerを使用しないことで、自分自身を多く制限していると思います。 (私の場合のように)そのシリアライザにモデルにもない(読み取り専用の)フィールドを追加して返すとどうなりますか?あなたのアプローチでは、これは可能ではないでしょうか? – AlejandroVK

+0

これは正しい答えとしてマークします。これは私に正しい方向を指していたので、今働いています。ありがとう@Till – AlejandroVK

+0

これは、モデルを作成するための 'AccommodationSerializer'は必要ないということです。私がDRFを理解している限り、シリアライザはインラインで別のモデルの作成メソッド内に別個のモデルを作成するためのものではありません。読み込み操作にカスタムおよび関連オブジェクトフィールドを使用するのは問題ありませんが、より複雑な埋め込み構造を作成/更新したい場合、通常はモデルマネージャを使用して独自の 'create'メソッドを実装してインスタンスを作成する必要があります。 –

関連する問題