Сериализатор полей ManyToMany в django
Я успешно сериализовал свою модель Blog, но в ней есть два отношения ManyToMany, одно для Category, а другое для SubCategory, все эти отношения могут быть одним или несколькими. Метод GET
работает, как и ожидалось, проблема остается с POST
.
Модели: `
class Category(models.Model):
category_name = models.CharField(max_length=100)
sub_category = models.ManyToManyField(SubCategory, blank=True, )
added_on = models.DateTimeField(auto_now=True)
icon = models.CharField(default="pi-angle-double-right", max_length=30,
help_text="Icons can be picked from https://www.primefaces.org/primevue/showcase-v2/#/icons")
def __str__(self) -> str:
return self.category_name
@property
def total_blogs(self):
return Blog.objects.filter(category=self).count()
class Blog(models.Model):
"""
Blog table
"""
colors = [("r", "danger"), ("s", "success"),
("i", "info"), ]
title = models.CharField(max_length=250, help_text="Unique, catchy topic of the article", unique=True, null=True, blank=True)
body = CKEditor5Field(
'Add a body', help_text="Full body of the article, supports markup", config_name='default', null=True,
blank=True)
introductory_file = models.ImageField(
upload_to="blog_intros", null=True, blank=True, help_text="Cover image to introduce the rest of the blog",
validators=[validate_image_file_extension, validate_img_extension])
author = models.ForeignKey(Author, on_delete=models.CASCADE)
blog_color = models.CharField(
choices=colors, null=True, blank=True, max_length=10)
posted_on = models.DateTimeField(auto_now_add=True)
upvotes = models.ManyToManyField(
User, blank=True, related_name="upvoters")
downvotes = models.ManyToManyField(
User, blank=True, related_name="downvoters")
slug = models.SlugField(unique=True, blank=True, null=True)
category = models.ManyToManyField(Category, verbose_name="category")
sub_category = models.ManyToManyField(
SubCategory, blank=True, verbose_name="subCategory")
schedule_to = models.DateField(
null=True, help_text="If you are want to schedule the blog to a future date.", blank=True)
contributors = models.ManyToManyField(
Author, blank=True, related_name="coauthors")
def __str__(self):
return self.title
class SubCategory(models.Model):
sub_category_name = models.CharField(max_length=100)
added_on = models.DateTimeField(auto_now=True)
icon = models.CharField(default="pi-angle-double-right", max_length=30,
help_text="Icons can be picked from https://www.primefaces.org/primevue/showcase-v2/#/icons")
def __str__(self):
return self.sub_category_name
`
Тогда мой Blogserializer будет выглядеть следующим образом
`
class CategorySerializer(serializers.RelatedField):
def to_representation(self, value):
return {"category_name": value.category_name, "icon": value.icon}
def get_queryset(self):
queryset = Category.objects.all()
return queryset
def to_internal_value(self, data):
print(data)
category_name = data.get('category_name', None)
try:
category = Category.objects.get(category_name=category_name)
except Category.DoesNotExist:
raise serializers.ValidationError('Category does not exist')
return Category(category_name=category_name)
class Meta:
model = Category
class SubCategorySerializer(serializers.RelatedField):
def to_representation(self, value):
return {"sub_category_name": value.sub_category_name, "icon": value.icon}
def get_queryset(self):
queryset = SubCategory.objects.all()
return queryset
def to_internal_value(self, data):
sub_category_name = data.get('sub_category_name', None)
try:
sub_category = SubCategory.objects.get(sub_category_name=sub_category_name)
except SubCategory.DoesNotExist:
raise serializers.ValidationError('Sub category does not exist')
return SubCategory(sub_category_name=sub_category_name)
class Meta:
model = SubCategory
class BlogSerializer(serializers.ModelSerializer):
"""
Blog serializers
"""
category = CategorySerializer(many=True)
sub_category = SubCategorySerializer(many=True)
total_upvotes = serializers.ReadOnlyField()
total_downvotes = serializers.ReadOnlyField()
total_comments = serializers.ReadOnlyField()
poster_image = serializers.SerializerMethodField()
full_name = serializers.SerializerMethodField()
blog_color = DisplayNameWritableField()
class Meta:
model = Blog # the model we working on
fields = '__all__'
`
Когда я делаю запрос get, я получаю нормальный и ожидаемый ответ, но createview выдает ошибку.
ListCreateAPIView `
class BlogListCreateView(generics.ListCreateAPIView):
"""
Get all articles or create one
"""
permission_classes = [IsAuthenticatedOrReadOnly, IsAuthor]
model = Blog
serializer_class = BlogSerializer
queryset = Blog.objects.all()
filter_backends = [filters.SearchFilter, DjangoFilterBackend]
search_fields = ["title", "author__user__username",
"category__category_name", "sub_category__sub_category_name"]
filterset_fields = ["title", "author__user__username",
"category__category_name", "sub_category__sub_category_name"]
def get_queryset(self):
now = datetime.datetime.now()
return Blog.objects.filter(Q(schedule_to__lte=now) | Q(schedule_to=None))
def perform_create(self, serializer):
if self.request.user.profile.is_author:
author_now = Author.objects.get(user=self.request.user)
serializer.save(author=author_now)
else:
return JsonResponse({"error": "You need to be an author to create an article"})
`
Ошибка, возвращаемая моим почтальоном, следующая
AttributeError at /api/blog/articles 'str' object has no attribute 'get'
которая, скорее всего, генерируется в моем сериализаторе категорий под to_internal_value()
, откуда, как вы видите, я печатаю данные!
Как мне обойти это, чтобы создать блог с одной, одной или несколькими категориями и одной, одной или несколькими подкатегориями.
Лучший подход также приветствуется.