【问题标题】:Passing argument from view to Custom RelatedField serializer将参数从视图传递到自定义相关字段序列化程序
【发布时间】:2015-10-15 19:00:15
【问题描述】:

如何将参数从 views.py 传递给 serializers.RelatedField 类。我需要通过 language_id 来查询该相关字段中的 Language.objects 模型。

我不确定我是否对这个问题采取了正确的方法。我想要实现的是根据语言从数据库模型中呈现与电影相关的流派信息。 MovieGenre 模型有流派 ID 字段,我想用实际流派名称替换它。

我的序列化器.py

class GenreField(serializers.RelatedField):
    def to_representation(self, value, language_id=1):
        genre_name = GenresVideo.objects.get(genre_id=value, language_id=language_id)
        return genre_name.name

class MovieGenresSerializer(serializers.ModelSerializer):
    genre_id = GenreField(read_only=True)

    class Meta:
        model = MoviesGenres

如您所见,这里我使用默认值查询 Language.objects,但我想从视图 (language_id) 中传递它。

我的意见.py:

class MovieGenresTestViewSet(viewsets.ModelViewSet):
    lookup_field = 'movie'
    queryset = MoviesGenres.objects.all()
    serializer_class = MovieGenresSerializer

    def list(self, request, language_pk):
        queryset = MoviesGenres.objects.all()
        serializer = MovieGenresSerializer(queryset, many=True)
        return Response(serializer.data)

    def retrieve(self, request, movie, language_pk):
        queryset = MoviesGenres.objects.filter(movie=movie)
        serializer = MovieGenresSerializer(queryset, many=True)
        return Response(serializer.data)

还有我的 urls.py:

router.register(r'lang', LanguagesViewSet, base_name='lang')
mov_gen = routers.NestedSimpleRouter(router, r'lang', lookup='language')
mov_gen.register(r'mg', MovieGenresTestViewSet, base_name='mg')
url(r'^api/', include(genre_spec.urls))

我的模型.py

class Languages(models.Model):
    name = models.CharField(unique=True, max_length=255)
    short_name = models.CharField(unique=True, max_length=4, blank=True, null=True)
    active = models.BooleanField(default="")

    class Meta:
        managed = False
        db_table = 'languages'
        ordering = ('id',)

class GenresVideo(models.Model):
    genre_id = models.IntegerField()
    language = models.ForeignKey('Languages')
    name = models.CharField(max_length=255, blank=True, null=True)

    class Meta:
        managed = False
        db_table = 'genres_video'
        unique_together = (('genre_id', 'language'),)
        ordering = ('genre_id',)

class MoviesGenres(models.Model):
    movie = models.ForeignKey(Movies)
    genre_id = models.IntegerField()

    class Meta:
        managed = False
        db_table = 'movies_genres'
        unique_together = (('movie', 'genre_id'),)

通过 urls 路由,我可以从 API 获得正确的响应,包括 language_id。我只需要以某种方式将其传递给视图。

非常感谢您的帮助!

【问题讨论】:

  • 我不确定您是否正确设置了路线。您的两个相关模型如何:流派和语言?你能分享他们的描述吗?
  • 我在原始帖子中添加了 models.py 的相关部分。路线按我的预期工作,所以当我发送这样的查询时:/api/lang/1/mg/33/ 我确实得到了该特定电影正确语言的正确流派列表。为了便于阅读,我只发布了我认为与此案例相关的内容,但我也可能遗漏了一些关键部分。

标签: django-rest-framework


【解决方案1】:

我将尝试以最简单的实现方式回答您的第一个问题:SerializerMethodField。因为我们将通过传递给序列化器的上下文来获取语言 id,所以我们应该为序列化器生成上下文,或者让框架为我们完成。

现在解决手头的问题:您没有按语言本身过滤查询集(MoviesGenres)。因此,我们可以避免覆盖列表和检索方法。尽管如此,路由器机制将在 kwargs 中为视图方法注入 language_pk 参数 - 这是我们将从序列化程序上下文中检索的参数:

class MovieGenresSerializer(serializers.ModelSerializer):
    genre = searializers.SerializerMethodField()

    class Meta:
        model = MoviesGenres

    def get_genre(self, instance):
        # get the language id from the view kwargs
        language_id = self.context['view'].kwargs['language_pk']
        # get the genre
        try:
            genre_name = GenresVideo.objects.get(genre_id=instance.genre_id, language_id=language_id).name
        except GenresVideo.DoesNotExist:
            genre_name = None
        # return the formatted output
        return genre_name


class MovieGenresTestViewSet(viewsets.ModelViewSet):
    lookup_field = 'movie'
    queryset = MoviesGenres.objects.all()
    serializer_class = MovieGenresSerializer

【讨论】:

  • 我得到 KeyError: 'view' from this line: language_id = self.context['view'].kwargs['parent_lookup_language']。
  • 你能检查一下 self.context 的内容吗?
  • 没关系。看起来您对列表和检索的覆盖正在渲染上下文的准备。我认为现在使用他们的默认实现是安全的。我会更新我的答案。
  • 现在我得到 KeyError for 'parent_lookup_language'
  • 嗯...通常应该是父查找的名称。你能在那个阶段调试和检查密钥吗?我们需要知道 kwargs 中有哪些可用的名称。
猜你喜欢
  • 2017-02-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-09-05
  • 1970-01-01
  • 2019-07-25
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多