首页 > 解决方案 > Django中的ManyToMany字段序列化器

问题描述

我已经成功序列化了我的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' 很可能是在我的 Category Serializer 中生成的,to_internal_value()在您看到正在打印数据的位置下!

我如何绕过它,以便创建一个博客,其中没有一个或多个类别,也没有一个或多个子类别。

也欢迎更好的方法。

标签: djangodjango-rest-frameworkdjango-serializerdjango-generic-viewsmanytomanyfield

解决方案


推荐阅读