django rest framework - 请求上下文密钥错误

时间:2023-01-02 16:56:51

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文档)。