I have two models (Like and News). I am using django-rest-framework to make a web api out of it.
我有两个模型(喜欢和新闻)。我正在使用django-rest-framework来制作一个web api。
class Like(models.Model):
user = models.ForeignKey(User)
content_type = models.ForeignKey(ContentType)
object_id = models.PositiveIntegerField()
content_object = GenericForeignKey('content_type', 'object_id')
class News(models.Model):
user = models.ForeignKey(User)
title = models.CharField(max_length=150)
...
likes = GenericRelation(Like)
A Like object has its own user field to store who liked the News object. Now to check if a specific user exists in any of the likes of a News object, I am getting request.user from a SerializerMethodField.
Like对象有自己的用户字段来存储喜欢News对象的人。现在要检查特定用户是否存在于任何类似的News对象中,我从SerializerMethodField获取request.user。
class NewsSerializer(serializers.HyperlinkedModelSerializer):
user = UserSerializer()
likes_count = serializers.IntegerField(source='likes.count', read_only=True)
user_in_likes = serializers.SerializerMethodField()
class Meta:
model = News
fields = ('user', 'title', 'body', 'article_image', 'pub_date', 'likes_count', 'user_in_likes')
def get_user_in_likes(self, obj):
user = self.context['request'].user
what = obj.likes.filter(user=user).exists()
return what
When I go the /news/ url, I get the json objects including the user_in_likes
to true/false for each news object.
当我去/ news / url时,我得到每个新闻对象的json对象,包括user_in_likes为true / false。
However, I have another serialzer for different model which imports NewsSerializer class
and other similar serializers:
但是,我有另一个用于不同型号的序列器,它可以导入NewsSerializer类和其他类似的序列化器:
class ActivityObjectRelatedField(serializers.RelatedField):
def to_representation(self, value):
if isinstance(value, User):
serializer = UserSerializer(value)
elif isinstance(value, Job):
serializer = JobSerializer(value)
elif isinstance(value, News):
serializer = NewsSerializer(value)
elif isinstance(value, Tender):
serializer = TenderSerializer(value)
else:
raise Exception('Unexpected type of tagged object')
return serializer.data
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')
Now if I visit /activities/
, to get the activities objects I am getting an error:
现在,如果我访问/ activities /,获取活动对象,我收到一个错误:
KeyError at /activities/
/ activities /中的KeyError
'request'
And it points to the line of SerializerMethod of NewsSerialize class where self.context['request'].user
is used.
它指向NewsSerialize类的SerializerMethod行,其中使用了self.context ['request']。user。
Exception Location: /vagrant/myproject/news/serializers.py in get_user_in_likes, line 25
例外位置:/vagrant/myproject/news/serializers.py in get_user_in_likes,第25行
Again if I visit /news/
url, everything is fine and I get news objects. What am I missing here? Why is request
not being recognized in the ActivitiesSerializer class
? Please help me solve this problem. Thank you.
再次,如果我访问/ news / url,一切都很好,我得到新闻对象。我在这里想念的是什么?为什么请求未在ActivitiesSerializer类中被识别?请帮我解决这个问题。谢谢。
2 个解决方案
#1
5
You are getting this error because you are not passing request
in the context when instantiating the NewsSerializer
class or other similar serializers in the to_representation()
method.
您收到此错误是因为在to_representation()方法中实例化NewsSerializer类或其他类似的序列化程序时,您没有在上下文中传递请求。
You are manually instantiating the particular serializer class in to_representation()
method. So, after instantiation, that particular serializer does not have access to ActivitySerializer
's context
thereby leading to the error.
您是在to_representation()方法中手动实例化特定的序列化程序类。因此,在实例化之后,该特定的序列化程序无法访问ActivitySerializer的上下文,从而导致错误。
You can pass the ActivitySerializer
's context
during instantiation of the relevant serializer in the to_representation()
method.
您可以在to_representation()方法中实例化相关序列化程序期间传递ActivitySerializer的上下文。
class ActivityObjectRelatedField(serializers.RelatedField):
def to_representation(self, value):
if isinstance(value, User):
serializer = UserSerializer(value, context=self.context) # pass context
elif isinstance(value, Job):
serializer = JobSerializer(value, context=self.context) # pass context
elif isinstance(value, News):
serializer = NewsSerializer(value, context=self.context) # pass context
elif isinstance(value, Tender):
serializer = TenderSerializer(value, context=self.context) # pass context
else:
raise Exception('Unexpected type of tagged object')
return serializer.data
#2
2
It seems like you don't populate the context
dictionary of NewsSerializer
with your request in the /activities/
view.
您似乎没有在/ activities /视图中使用您的请求填充NewsSerializer的上下文字典。
You probably use a class based view provided by Django REST Framework which populates this dictionary for you (see the get_serializer_context()
method) and passes it to the Serializer
instance. That's why it's automatically available to your serializer in your /news/
view.
您可能使用Django REST Framework提供的基于类的视图,它为您填充此字典(请参阅get_serializer_context()方法)并将其传递给Serializer实例。这就是为什么它会自动提供给/ news / view中的序列化程序。
In your /activities/
view, though, the context is passed to ActivitySerializer
and isn't (automatically) propagated further from there. That's why there's no request
key in your context dictionary of NewsSerializer
. You would need to pass your request object to the NewsSerializer
instance. To pass extra context to a Serializer you can add a context
parameter containing a dictionary when instantiating (see the DRF documentation).
但是,在/ activities / view中,上下文将传递给ActivitySerializer,并且不会(自动)从那里进一步传播。这就是为什么NewsSerializer的上下文字典中没有请求键。您需要将请求对象传递给NewsSerializer实例。要将额外的上下文传递给Serializer,您可以在实例化时添加包含字典的上下文参数(请参阅DRF文档)。
#1
5
You are getting this error because you are not passing request
in the context when instantiating the NewsSerializer
class or other similar serializers in the to_representation()
method.
您收到此错误是因为在to_representation()方法中实例化NewsSerializer类或其他类似的序列化程序时,您没有在上下文中传递请求。
You are manually instantiating the particular serializer class in to_representation()
method. So, after instantiation, that particular serializer does not have access to ActivitySerializer
's context
thereby leading to the error.
您是在to_representation()方法中手动实例化特定的序列化程序类。因此,在实例化之后,该特定的序列化程序无法访问ActivitySerializer的上下文,从而导致错误。
You can pass the ActivitySerializer
's context
during instantiation of the relevant serializer in the to_representation()
method.
您可以在to_representation()方法中实例化相关序列化程序期间传递ActivitySerializer的上下文。
class ActivityObjectRelatedField(serializers.RelatedField):
def to_representation(self, value):
if isinstance(value, User):
serializer = UserSerializer(value, context=self.context) # pass context
elif isinstance(value, Job):
serializer = JobSerializer(value, context=self.context) # pass context
elif isinstance(value, News):
serializer = NewsSerializer(value, context=self.context) # pass context
elif isinstance(value, Tender):
serializer = TenderSerializer(value, context=self.context) # pass context
else:
raise Exception('Unexpected type of tagged object')
return serializer.data
#2
2
It seems like you don't populate the context
dictionary of NewsSerializer
with your request in the /activities/
view.
您似乎没有在/ activities /视图中使用您的请求填充NewsSerializer的上下文字典。
You probably use a class based view provided by Django REST Framework which populates this dictionary for you (see the get_serializer_context()
method) and passes it to the Serializer
instance. That's why it's automatically available to your serializer in your /news/
view.
您可能使用Django REST Framework提供的基于类的视图,它为您填充此字典(请参阅get_serializer_context()方法)并将其传递给Serializer实例。这就是为什么它会自动提供给/ news / view中的序列化程序。
In your /activities/
view, though, the context is passed to ActivitySerializer
and isn't (automatically) propagated further from there. That's why there's no request
key in your context dictionary of NewsSerializer
. You would need to pass your request object to the NewsSerializer
instance. To pass extra context to a Serializer you can add a context
parameter containing a dictionary when instantiating (see the DRF documentation).
但是,在/ activities / view中,上下文将传递给ActivitySerializer,并且不会(自动)从那里进一步传播。这就是为什么NewsSerializer的上下文字典中没有请求键。您需要将请求对象传递给NewsSerializer实例。要将额外的上下文传递给Serializer,您可以在实例化时添加包含字典的上下文参数(请参阅DRF文档)。