2016-06-20 10 views
4

私はアクティビティモデルを構築していますが、これはややこのpackageに似ています。それは俳優、動詞とターゲットを持っています。どちらのモデル(入札、仕事やニュース)の新しいオブジェクトが作成されるたびに今、新しいActivityオブジェクトがtargetこれら3つのモデルのいずれかのオブジェクトであることと、作成されています。ContentTypeオブジェクト用のdjango-rest-frameworkシリアライザ

class Activity(models.Model): 
    actor_type = models.ForeignKey(ContentType, related_name='actor_type_activities') 
    actor_id = models.PositiveIntegerField() 
    actor = GenericForeignKey('actor_type', 'actor_id') 
    verb = models.CharField(max_length=10) 
    target_type = models.ForeignKey(ContentType, related_name='target_type_activities') 
    target_id = models.PositiveIntegerField() 
    target = GenericForeignKey('target_type', 'target_id') 
    pub_date = models.DateTimeField(default=timezone.now) 

eg. user (actor) published (verb) title (target)

class Tender(models.Model): 
    title = models.CharField(max_length=256) 
    description = models.TextField() 

class Job(models.Model): 
    title = models.CharField(max_length=256) 
    qualification = models.CharField(max_length=256) 

class News(models.Model): 
    user = models.ForeignKey(settings.AUTH_USER_MODEL) 
    title = models.CharField(max_length=150) 

私は私に必要なJSONデータを取得するAPIを作っています。このデータを取得するために。私はこのためにdjango-rest-frameworkを使用しており、非常に新しいです。上記のシリアライザで

class ActorSerializer(serializers.HyperlinkedModelSerializer): 
    class Meta: 
     model = User 
     fields = ('id', 'username', 'email') 

class ActivitySerializer(serializers.HyperlinkedModelSerializer): 
    actor = ActorSerializer() 
    class Meta: 
     model = Activity 
     fields = ('url', 'actor', 'verb', 'pub_date') 

、私はactorがユーザーになることを知っていました。それで、ActorSerializerクラスのUserモデルを使用しました。しかし、targetについては、これらの3つのモデル(ニュース/ジョブ/入札)のいずれかにすることができます。私はActivitySerializerクラスフィールドにtargetを使用できるように

はどのようにしてたContentTypeオブジェクトのシリアライザ(例えば。TargetSerialierクラス)を作ることができますか?

答えて

1

わかりましたので、ここで自分の質問に答えます。私はzymudの答えにいくつかの助けをしました。したがって、明らかにdocumentationには、一般的な関係をシリアル化する方法があります。 )( `引数付きのニュース - 詳細 '」のためのリバース:

class ActivityObjectRelatedField(serializers.RelatedField): 
    def to_representation(self, value): 
     if isinstance(value, User): 
      return 'User: ' + value.username 
     elif isinstance(value, News): 
      return 'News: ' + value.title 
     elif isinstance(value, Job): 
      return 'Job: ' + value.title 
     elif isinstance(value, Tender): 
      return 'Tender: ' + value.title 
     raise Exception('Unexpected type of tagged object') 


class ActivitySerializer(serializers.HyperlinkedModelSerializer): 
    actor = ActivityObjectRelatedField(read_only=True) 
    target = ActivityObjectRelatedField(read_only=True) 

    class Meta: 
     model = Activity 
     fields = ('url', 'actor', 'verb', 'target', 'pub_date') 
+0

これは、これらのフィールドが現在読まれていることを意味しますか? ActivityObjectを保存しようとしたらどうなりますか? read_onlyを与えないと、クエリーセットを渡す必要がありますが、そこに到達する前にどんなモデルになるのか分かりません。私は誤解していますか? –

2

汎用キーのカスタムフィールドを実装できます。例:使用法の

from django.core.urlresolvers import resolve 
from rest_framework.fields import Field 

class GenericRelatedField(Field): 
    """ 
    A custom field that expect object URL as input and transforms it 
    to django model instance. 
    """ 
    read_only = False 
    _default_view_name = '%(model_name)s-detail' 
    lookup_field = 'pk' 

    def __init__(self, related_models=(), **kwargs): 
     super(GenericRelatedField, self).__init__(**kwargs) 
     # related models - list of models that should be acceptable by 
     # field. Note that all this models should have corresponding 
     # endpoint. 
     self.related_models = related_models 

    def _get_url_basename(self, obj): 
     """ Get object URL basename """ 
     format_kwargs = { 
      'app_label': obj._meta.app_label, 
      'model_name': obj._meta.object_name.lower() 
     } 
     return self._default_view_name % format_kwargs 

    def _get_request(self): 
     try: 
      return self.context['request'] 
     except KeyError: 
      raise AttributeError('GenericRelatedField have to be initialized with `request` in context') 

    def to_representation(self, obj): 
     """ Serializes any object to its URL representation """ 
     kwargs = {self.lookup_field: getattr(obj, self.lookup_field)} 
     request = self._get_request() 
     return request.build_absolute_uri(reverse(self._get_url_basename(obj), kwargs=kwargs)) 

    def clear_url(self, url): 
     """ Removes domain and protocol from url """ 
     if url.startswith('http'): 
      return '/' + url.split('/', 3)[-1] 
     return url 

    def get_model_from_resolve_match(self, match): 
     queryset = match.func.cls.queryset 
     if queryset is not None: 
      return queryset.model 
     else: 
      return match.func.cls.model 

    def instance_from_url(self, url): 
     url = self.clear_url(url) 
     match = resolve(url) 
     model = self.get_model_from_resolve_match(match) 
     return model.objects.get(**match.kwargs) 


    def to_internal_value(self, data): 
     """ Restores model instance from its URL """ 
     if not data: 
      return None 
     request = self._get_request() 
     user = request.user 
     try: 
      obj = self.instance_from_url(data) 
      model = obj.__class__ 
     except (Resolver404, AttributeError, MultipleObjectsReturned, ObjectDoesNotExist): 
      raise serializers.ValidationError("Can`t restore object from url: %s" % data) 
     if model not in self.related_models: 
      raise serializers.ValidationError('%s object does not support such relationship' % str(obj)) 
     return obj 

例:

class ActivitySerializer(serializers.HyperlinkedModelSerializer): 
    target = GenericRelatedField(related_models=(News, Job, Tender)) 
    ... 
+0

私はこのエラーを取得しています:

だから、私がしなければならなかったすべては、カスタムフィールドを作成してシリアライザ自体にそのフィールドを関連付けました'およびキーワード引数' {'pk':3} 'が見つかりませんでした。 0個のパターンが試されました:[] ' – Aamu

+0

' News'モデル用のエンドポイントがないか、basenameが 'news-detail'ではないためです。 DRFモデルはエンドポイントをURLとして表現する必要があります。 – zymud

関連する問題