所以我尝试通过 django-rest-framework (DRF) 制作一个可浏览的 API,但我在嵌套序列化器时遇到了一些问题。到目前为止,我能够将 Sport 和 Category 字段/外键包含到我的 Article 中,但是当我尝试 POST 通过 API,我收到如下错误消息:
Got a
TypeErrorwhen callingArticle.objects.create(). This may be because you have a writable field on the serializer class that is not a valid argument toArticle.objects.create(). You may need to make the field read-only, or override the ArticleSerializer.create() method to handle this correctly. Original exception text was: int() argument must be a string, a bytes-like object or a number, not 'ArticleSport'.
这是我的文件:
模型.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
}
请您参考如下方法:
所以我能够使用一些 Carter_Smith 来回答这个问题的建议 - 我不是 100% 确定为什么这样做有效,但我添加了这个 create()我的方法 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和 category_id作为基于名称的 kwarg 字段,当它们应该只是 sport 时和 category ,所以压倒一切.create()允许您修复该问题,同时仍允许 read_only sport 的字段和 category .希望这对遇到同样问题的其他人有所帮助。
