如何在django-rest-framework POST中包含ForeignKey

时间:2016-08-22 18:06:37

标签: python django api post django-rest-framework

所以我试图通过django-rest-framework (DRF)创建一个可浏览的API,但是我遇到了一些嵌套序列化器的问题。到目前为止,我可以将SportCategory字段/ foreignkeys包含到我的Article中,但是当我通过API尝试POST时,我收到错误消息如下:

  

在致电TypeError时获得Article.objects.create()。这可能是因为序列化程序类上的可写字段不是Article.objects.create()的有效参数。您可能需要将该字段设置为只读,或覆盖ArticleSerializer.create()方法以正确处理此字段。   原始异常文本是:int()参数必须是字符串,类似字节的对象或数字,而不是' ArticleSport'。

以下是我的文件:

models.py

[...]

class ArticleSport(TimeStampedModel):
    title = models.CharField(max_length=20, blank=False)
    slug = AutoSlugField(populate_from='title', unique=True, always_update=True)
    parent = models.ForeignKey('self', blank=True, null=True, related_name='children')  # TODO: Add on_delete?

    uuid = models.UUIDField(default=uuid.uuid4, unique=True, editable=False)

    def __str__(self):
        return '{0}'.format(self.title)

    #class Meta:  # TODO: Migrate live
        #unique_together = ('title', 'parent')


class ArticleCategory(TimeStampedModel):
    title = models.CharField(max_length=20, blank=False)
    slug = AutoSlugField(populate_from='title', unique=True, always_update=True)
    parent = models.ForeignKey('self', blank=True, null=True, related_name='children')  # TODO: Add on_delete?

    uuid = models.UUIDField(default=uuid.uuid4, unique=True, editable=False)

    def __str__(self):
        return '{0}'.format(self.title)

    class Meta:
        verbose_name_plural = 'article categories'
        #unique_together = ('title', 'parent')  # TODO: Migrate live


class Article(TimeStampedModel):
    DEFAULT_FEATURED_IMAGE = settings.STATIC_URL + 'images/defaults/default-featured-image.png'

    title = models.CharField(max_length=160, blank=False)
    slug = AutoSlugField(populate_from='title', unique=True, always_update=True)
    sport = models.ForeignKey(ArticleSport, on_delete=models.CASCADE, related_name='articleAsArticleSport')
    category = models.ForeignKey(ArticleCategory, on_delete=models.CASCADE, related_name='articleAsArticleCategory')
    featured_image = models.ImageField(upload_to=PathAndUniqueFilename('featured-images/'), blank=True)
    featured_image_caption = models.CharField(max_length=100, blank=True)
    views = models.IntegerField(default=0)

    uuid = models.UUIDField(default=uuid.uuid4, unique=True, editable=False)

    def get_absolute_url(self):
        return reverse('main:article_specific', args=[self.slug])  # TODO: Remove if standalone pages are removed

    def get_featured_image(self):
        if self.featured_image:
            return self.featured_image.url
        else:
            return self.DEFAULT_FEATURED_IMAGE

    def get_comment_count(self):
        return ArticleComment.objects.filter(article=self).count()

    def __str__(self):
        return '{0}'.format(self.title)

[...]

urls.py

[...]

class ArticleSportSerializer(serializers.HyperlinkedModelSerializer):
    class Meta:
        model = ArticleSport
        fields = ('id', 'title', 'parent', 'created', 'modified')


class ArticleCategorySerializer(serializers.HyperlinkedModelSerializer):
    class Meta:
        model = ArticleCategory
        fields = ('id', 'title', 'parent', 'created', 'modified')


class ArticleSerializer(serializers.HyperlinkedModelSerializer):
    sport = ArticleSportSerializer(read_only=True)
    sport_id = serializers.PrimaryKeyRelatedField(queryset=ArticleSport.objects.all(), write_only=True)
    category = ArticleCategorySerializer(read_only=True)
    category_id = serializers.PrimaryKeyRelatedField(queryset=ArticleCategory.objects.all(), write_only=True)
    modified = serializers.HiddenField(default=timezone.now())  #TODO: Figure out how to implement this

    class Meta:
        model = Article
        fields = ('id', 'title', 'sport', 'sport_id', 'category', 'category_id', 'featured_image', 'featured_image_caption', 'views', 'created', 'modified')

[...]

示例POST到API:

{
    "title": "This is a test Title",
    "sport_id": 1,
    "category_id": 1,
    "featured_image": null,
    "featured_image_caption": "",
    "views": null,
    "modified": null
}

2 个答案:

答案 0 :(得分:1)

您需要覆盖序列化程序的create方法以适应您的POST请求。这可能不是您正在寻找的,但您还没有包含您的样品申请,因此我们没有太大的帮助。

如果我有足够的声誉,这将是一个评论。

答案 1 :(得分:1)

所以我能够通过使用Carter_Smith的一些建议回答这个问题 - 我不是百分之百确定为什么会这样做,但是我将这个create()方法添加到我的{ {1}},它起作用了:

ArticleSerializer

我的猜测是def create(self, validated_data): # Override default `.create()` method in order to properly add `sport` and `category` into the model sport = validated_data.pop('sport_id') category = validated_data.pop('category_id') article = Article.objects.create(sport=sport, category=category, **validated_data) return article 尝试根据名称解析PrimaryKeyRelatedField()sport_id作为kwarg字段,而它们应该只是category_idsport },所以覆盖category允许你修复它,同时仍然允许.create()read_only的{​​{1}}字段。希望这可以帮助其他有同样问题的人。