2013-07-09 16 views
17

私はオプションのフィールドを持つオブジェクトを持っています。私は私のシリアライザをこのように定義していますDjango RESTフレームワーク - オプションのフィールドをシリアライズ

class ProductSerializer(serializers.Serializer): 
    code = serializers.Field(source="Code") 
    classification = serializers.CharField(source="Classification", required=False) 

私が存在しない場合は、フィールドをバイパスの仕事をするだろうthoughtrequired=False。ただし、ドキュメントでは、これがシリアル化ではなく非直列化に影響することが記載されています。私はシリアル化されたインスタンスの.dataにアクセスしようとすると、何が起こっている

'Product' object has no attribute 'Classification' 

私は次のエラーを取得しています。 (これは、これを発生させている非直列化を意味しません)

これは、Classificationを持たないインスタンスで発生します。シリアライザクラスからClassificationを省略すると、うまく動作します。

これを正しく行うにはどうすればよいですか?オプションのフィールドを持つオブジェクトをシリアル化します。

+0

それは許容されますか? –

+0

これらは存在しません。私はSOAP Webサービスを呼び出しています。これには、sudsを使用するオプションのフィールドがあります。応答オブジェクトは、返されるXMLを表し、場合によってはオプションフィールドを含みません。 – abstractpaper

+0

トム私はちょうどあなたが意味していることを理解している。理想的には、私はそれらが全く存在しないようにしたいですが、私は当面は「None」と一緒に暮らすことができます。 – abstractpaper

答えて

9

シリアライザは固定フィールドセットを使用するよう意図的に設計されているため、オプションでキーの1つを削除することは容易ではありません。

SerializerMethodFieldを使用して、フィールド値を返すか、フィールドが存在しない場合はNoneを返すか、シリアライザをまったく使用できず、単にレスポンスを直接返すビューを作成することができます。

RESTフレームワーク3.0用の更新serializer.fieldsは、インスタンス化されたシリアライザで変更できます。ダイナミックシリアライザクラスが必要な場合は、カスタムSerializer.__init__()メソッドのフィールドを変更することをお勧めします。

+7

これまでのところ私のプロジェクトでフレームワークがどれほどフレンドリーであるかを考えると、存在しないキーに対しては、デフォルトでは 'None'というオプションを用意しておくといいでしょう。 – abstractpaper

+0

@TomChristie Hey Tom、DRF 3がリリースされましたので、DRF 3を使用して推奨される方法で回答を更新できますか?私はDRF 3を使っていろいろな方法を提案する人がいるので、私は尋ねています。最良の選択肢が何であるかはわかりません(下記のMarkの答えを参照するか、ここのDavidの答えをご覧ください:http://stackoverflow.com/questions/27015931/ DRF 3を使用してこれを達成する方法の例については、django-rest-framework-responseからremove-null-fieldsを参照してください。)DRF 3を使用する最良の方法は何ですか? – user2719875

16

DjangoのRESTフレームワークに対応しまし3.0+
ダイナミックフィールド、http://www.django-rest-framework.org/api-guide/serializers/#dynamically-modifying-fieldsを参照してください - このアプローチは、シリアライザ内のすべてのフィールドを定義し、その後、あなたは選択したくないものを削除することができます。

またはあなたはまた、シリアライザの初期化中Meta.fieldsとあなたの周りには混乱モデルシリアライザ、このような何かを行うことができます:これは "ある場合にかかわらず、

class ProductSerializer(serializers.ModelSerializer): 
    class Meta: 
     model = Product 
     fields = ('code',) 

    def __init__(self, *args, **kwargs): 
     if SHOW_CLASSIFICATION: # add logic here for optional viewing 
      self.Meta.fields = list(self.Meta.fields) 
      self.Meta.fields.append('classification') 
     super(ProductSerializer, self).__init__(*args, **kwargs) 

あなたはトムに依頼する必要があるだろう長期計画には適合しない可能性があるため、「正しい方法」を選択する必要があります。

DjangoのRESTフレームワーク< 3.0
このような何か試してみてください:

class ProductSerializer(serializers.Serializer): 
    ... 
    classification = serializers.SerializerMethodField('get_classification') 

    def get_classification(self, obj): 
     return getattr(obj, 'classification', None) 

複数のシリアライザ

別のアプローチをフィールドの異なるセットを持つ複数のシリアライザを作成することです。 1つのシリアライザは別のシリアライザを継承し、追加のフィールドを追加します。次に、get_serializer_classメソッドでビュー内の適切なシリアライザを選択できます。次に、このアプローチを使用して、異なるシリアライザを呼び出して、ユーザオブジェクトがリクエストユーザと同じ場合に異なるユーザデータを表示する方法の実際の例を示します。私はセキュリティコンテキストで使用してきた別のアプローチは、to_representation方法でフィールドを削除することで表現

からフィールドを削除する

def get_serializer_class(self): 
    """ An authenticated user looking at their own user object gets more data """ 
    if self.get_object() == self.request.user: 
     return SelfUserSerializer 
    return UserSerializer 

def remove_fields_from_representation(self, representation, remove_fields): 
    """ Removes fields from representation of instance. Call from 
    .to_representation() to apply field-level security. 
    * remove_fields: a list of fields to remove 
    """ 
    for remove_field in remove_fields: 
     try: 
      representation.pop(remove_field) 
     except KeyError: 
      # Ignore missing key -- a child serializer could inherit a "to_representation" method 
      # from its parent serializer that applies security to a field not present on 
      # the child serializer. 
      pass 

のようなメソッドを定義して、あなたのシリアライザで、

def to_representation(self, instance): 
    """ Apply field level security by removing fields for unauthorized users""" 
    representation = super(ProductSerializer, self).to_representation(instance) 
    if not permission_granted: # REPLACE WITH PERMISSION LOGIC 
     remove_fields = ('classification',) 
     self.remove_fields_from_representation(representation, remove_fields) 
    return representation 

のようにそのメソッドを呼び出して、このアプローチは簡単で柔軟性があるが、それは時々表示されないフィールドをシリアル化のコストがかかります。しかし、それはおそらく大丈夫です。

+0

これは、許可に基づいて条件付きでデータを表示するタスクです。これを処理する快適な方法はないと思います。 あなたの最初のアプローチはうまくいくようですが、それは一種の猿パッチです。新しいインスタンスを作成するたびにProductSerializer.Meta.fieldsが増加し、最初の状態が失われます。 – meteor

+0

@meteorセキュリティの用途のために最近私がこの問題を解決する方法。私はあなたがもう言及した例を使用することはお勧めしません。 –

+0

最初の例は、ドキュメントの提案にかなり近いですか?私はノブで、なぜそれが良い方法ではないのか混乱していますか? 出典:http://www.django-rest-framework.org/api-guide/serializers/#dynamically-modifying-fields –

0

「DRFとDjangoの具体的な実装の詳細に依存する恐ろしいハックですが、少なくとも今のところは動作しますが、ここでは、シリアライザのメソッドの実装を「作成」:

def create(self, validated_data) 
    # Actual model instance creation happens here... 
    self.fields["debug_info"] = serializers.DictField(read_only=True) 
    my_model.debug_info = extra_data 
    return my_model 

これは私は、データが作成プロセス中に特定のリモートサービスから受信した生応答の一部を表示するには、閲覧可能なAPIを使用することができます一時的なアプローチです。将来、私はこの機能を維持する傾向がありますが、デフォルトで下位レベルの情報を返すのではなく、作成要求の「レポートデバッグ情報」フラグの後ろに隠してしまいます。

0

この目的のために、シリアライザはpartial引数を持ちます。シリアライザの初期化時にpartial=Trueを渡すことができます。あなたはジェネリックやミックスインを使用している場合、次のようにget_serializer機能をoverriderことができます。

def get_serializer(self, *args, **kwargs): 
    kwargs['partial'] = True 
    return super(YOUR_CLASS, self).get_serializer(*args, **kwargs) 

そして、それは、トリックを行います。

注:注:これにより、すべてのフィールドを任意のフィールドにすることができます。詳細のみが必要な場合は、メソッド(更新)をオーバーライドして、さまざまなフィールドの存在のバリデーションを追加できます。

0

以下の方法で私の仕事ができました。 かなり簡単で、簡単で、私のために働いた。これらのフィールドはNONE` `としてシリアル化する、またはキーが全く存在してはならないため

DRFバージョン使用= djangorestframework(3.1.0)

class test(serializers.Serializer): 
    id= serializers.IntegerField() 
    name=serializers.CharField(required=False,default='some_default_value') 
関連する問題