简体   繁体   English

如何使用Django Rest Framework处理外键

[英]How to handle foreign keys with Django Rest Framework

I'm struggling to make my API work, the tutorials are quite tricky about this part. 我正在努力使我的API正常工作,这些教程在这部分上非常棘手。 I want to have a '/comments/' POST request with body {movie_id: 1, content="Some comment") and connect it to some Movie. 我想要一个带有正文{movie_id:1,content =“ Some comment”)的'/ comments /'POST请求,并将其连接到某些Movie。

In serializer I'm getting: {'movie': [ErrorDetail(string='This field is required.', code='required')]} 在序列化器中,我得到: {'movie': [ErrorDetail(string='This field is required.', code='required')]}

How can I map movie_id to movie? 如何将movie_id映射到电影? By the way, I can change the name to movie if this would be easier. 顺便说一句,如果这样会更容易,我可以将名称更改为电影。

Models.py: Models.py:

from django.db import models
from django.utils import timezone


class Movie(models.Model):
    title = models.CharField(max_length=200)
    year = models.IntegerField()


class Comment(models.Model):
    content = models.TextField(max_length=300)
    publish_date = models.DateField(default=timezone.now())
    movie = models.ForeignKey(Movie, on_delete=models.CASCADE, related_name='movie_id')

serializers.py: serializers.py:

class MovieSerializer(serializers.HyperlinkedModelSerializer):
    class Meta:
        model = Movie
        fields = '__all__'


class CommentSerializer(serializers.HyperlinkedModelSerializer):
    movie_id = serializers.PrimaryKeyRelatedField(many=False, read_only=True)

    class Meta:
        model = Comment
        fields = '__all__'

views.py (for Comment, Movie works fine): views.py(对于Comment,Movie工作正常):

from .models import Movie, Comment
from rest_framework import viewsets, status
from rest_framework.response import Response
from .serializers import MovieSerializer, CommentSerializer

class CommentViewSet(viewsets.ModelViewSet):
    queryset = Comment.objects.all()
    serializer_class = CommentSerializer

    def create(self, request, *args, **kwargs):
        serializer = CommentSerializer(data=request.data, context={'request': request})

        if serializer.is_valid(raise_exception=True): 
            serializer.save()
            return Response(serializer.data, status=status.HTTP_201_CREATED)  
        else:
            return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

I think you can try like this: 我想你可以尝试这样:

class CommentSerializer(serializers.HyperlinkedModelSerializer):
    class Meta:
        model = Comment
        fields = '__all__'

Also, related name is used for reverse relationship. 另外,相关名称用于反向关系。 So it will work like this: 因此它将像这样工作:

If Comment Model has related_name comments like this: 如果Comment模型具有related_name comments例如:

class Comment(models.Model):
    movie = models.ForeignKey(Movie, on_delete=models.CASCADE, related_name='comments')

Then you can access comments from movie like this: 然后,您可以像这样访问电影中的评论:

for m in Movie.objects.all():
    m.comments.all()

Nested data works a little differently to how I expected. 嵌套数据的工作方式与我的预期有所不同。

If you want to connect a comment to a movie, you need to pass the movie object to your comment, not the primary key of the movie object. 如果要将注释连接到电影,则需要将电影对象传递到注释,而不是电影对象的主键。

Under the hood, Django automatically creates a new field 'movie_id' on your comment object in which the movie's primary key is stored - but you don't need to worry about that. 在幕后,Django会自动在评论对象上创建一个新的字段“movie_id”,其中存储了电影的主键 - 但您无需担心这一点。 So I would call the field in the comment 'movie', otherwise Django will create a new field 'movie_id_id'. 所以我会在评论'电影'中调用该字段,否则Django将创建一个新字段'movie_id_id'。

I got something similar to work by defining a custom create method in my serializer: 通过在我的序列化程序中定义自定义创建方法,我得到了类似的工作:

In your serializer: 在您的序列化器中:

class CommentSerializer(serializers.HyperlinkedModelSerializer):
    class Meta:
        model = Comment
        fields = '__all__'


    def create(self, validated_data):
        themovieid = validated_data.pop('movie_id', None) # remove movie_id from the comment data
        themovie = Movie.objects.get(pk=themovieid) # find the movie object

        return Comment.objects.create(movie=themovie, **validated_data)

I have tried to adapt this to your code, I hope it will help you to get this working. 我已尝试将其调整为适合您的代码,希望它可以帮助您使其正常工作。 I have removed movie_id from your serializer: your model defiines everything that is needed. 我已经从序列化器中删除了movie_id:您的模型定义了所有需要的内容。

Edit: have you tried simply passing the movie's id as 'movie' in your comment data, with no custom create method and do not define 'movie_id' in your serializer? 编辑:您是否尝试过在评论数据中简单地将电影的ID作为“电影”传递,没有自定义创建方法,并且未在序列化器中定义“电影ID”?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM