API Django Rest Framework 上的多对多字段 POST 请求
Many to Many field POST requests on API Django Rest Framework
所以我有 3 个模型感兴趣:
models.py
class Author(models.Model): #Author of books
name = models.CharField(max_length = 100)
@property # This is code to get the books linked to an author
def books(self):
book = Book.objects.filter(authors = self.id)
return ', '.join(map(str,book)) #This makes the book list in this format "A, B, C"
def __str__(self):
return self.name.title()
class Genre(models.Model): #Genre of books
name = models.CharField(max_length = 50, unique = True)
@property
def books(self):
book = Book.objects.filter(genre = self.id)
return ', '.join(map(str,book))
def __str__(self):
return self.name.title()
class Book(models.Model):
name = models.CharField(max_length = 150,) #Name of books
authors = models.ManyToManyField(Author,) #Many to many because multiple books can have multiple authors
genre = models.ManyToManyField(Genre)
def __str__(self):
return self.name.title()
这些是模型,类型和作者都与书籍有多对多的关系
serializers.py
class AuthorListSerializer(serializers.ModelSerializer):
class Meta:
model = models.Author
fields = ('name',)
class GenreListSerializer(serializers.ModelSerializer):
class Meta:
model = models.Genre
fields = ('name',)
class BookListSerializer(serializers.ModelSerializer):
authors = AuthorListSerializer(many = True,) #To represent the relationship as a string instead of id
genre = serializers.SlugRelatedField(many = True, queryset = models.Genre.objects.all(),slug_field = 'name')
class Meta:
model = models.Book
fields = ('name','authors','rating', 'genre')
class BookDetailSerializer(serializers.ModelSerializer):
publisher = serializers.SlugRelatedField(queryset = models.Publisher.objects.all(), slug_field= 'name') #To display publisher name instead of id
authors = serializers.StringRelatedField(many = True,) #To represent the relationship as a string instead of id
genre = serializers.StringRelatedField(many = True,)
class Meta:
model = models.Book
fields = ('name', 'authors', 'rating','genre',
'publisher', 'total_qty', 'avail_qty',
'pub_date','isbn','price',)
所以在我的 Django-Rest-Framework Browsable api 中,正常的 ForeignKey 字段显示了它们的选项以创建一个新的对象实例。
例如,“BookDetailSerializer”中的发布者将所有发布者显示为 POST 或 PUT 或 PATCH 请求的选项。
但是对于包括 Genre 和 Author 在内的多对多字段,它不仅是空白的,而且似乎我无法输入任何内容。
我已经尝试使用 DRF-writable-nested 第三方包但没有任何改变:
class BookListSerializer(WritableNestedModelSerializer):
authors = AuthorListSerializer(many = True,) #To represent the relationship as a string instead of id
genre = serializers.SlugRelatedField(many = True,
queryset = models.Genre.objects.all(),slug_field = 'name')
我的问题是如何才能通过可浏览的 DRF api 提出 POST 作者和流派列表请求?
提前致谢!!
This image shows the options available for making a POST request involving publishers
This image shows that you can't add any input for POST request involving both Genre and Authors as many-to many relations.
更新:所以我加了create方法还是不行,如下图:
class BookListSerializer(serializers.ModelSerializer):
authors = AuthorListSerializer(many = True,) #To represent the relationship as a string instead of id
genre = serializers.SlugRelatedField(many = True,
queryset = models.Genre.objects.all(),slug_field = 'name')
class Meta:
model = models.Book
fields = ('name','authors','rating', 'genre')
def create(self,validated_data):
authors_data = models.Author.objects.all()
book = Book.objects.create(authors = authors_data,**validated_data,)
return book
我能做什么?
折腾了4天终于找到答案了
在处理多对多关系时,你希望代码如下。
class BookListSerializer(serializers.ModelSerializer):
class Meta:
model = models.Book
fields = ('name','authors','rating', 'genre')
depth = 1
添加深度允许嵌套关系完全序列化。
因为关系是嵌套的,并且是多对多关系,所以您必须在 views.py 中创建自己的创建函数,如下所示:
class BookViewSet(GetSerializerClassMixin, viewsets.ModelViewSet):
queryset = models.Book.objects.all()
serializer_class = serializers.BookDetailSerializer
serializer_action_classes = {'list': serializers.BookListSerializer}
permission_classes = [IsAdminOrReadOnly, permissions.IsAuthenticated,]
def create(self,request, *args, **kwargs):
data = request.data
new_book = models.Book.objects.create(name = data["name"], publisher = models.Publisher.objects.get(id = data["publisher"]),
pub_date = data["pub_date"],
price = data["price"],
isbn = data['isbn'],)
new_book.save()
for author in data['authors']:
author_obj = models.Author.objects.get(name = author['name'])
new_book.authors.add(author_obj)
for gen in data['genre']:
gen_obj = models.Genre.objects.get(name = gen['name'])
new_book.genre.add(gen_obj)
serializer = serializers.BookListSerializer(new_book)
return Response(serializer.data)
对于多对多关系,您必须在保存对象后创建它们并手动将它们添加到对象中。
那里存在一个外键关系“发布者”
对于这种关系,您必须手动指向它在数据库中的位置,因此代码如下。
name = data["name"], publisher = models.Publisher.objects.get(id = data["publisher"]),
对于问题中的 Detail book serializer,它与 BookListSerializer 是一回事
这就是我在多对多关系中处理 POST 请求的方式
所以我有 3 个模型感兴趣:
models.py
class Author(models.Model): #Author of books
name = models.CharField(max_length = 100)
@property # This is code to get the books linked to an author
def books(self):
book = Book.objects.filter(authors = self.id)
return ', '.join(map(str,book)) #This makes the book list in this format "A, B, C"
def __str__(self):
return self.name.title()
class Genre(models.Model): #Genre of books
name = models.CharField(max_length = 50, unique = True)
@property
def books(self):
book = Book.objects.filter(genre = self.id)
return ', '.join(map(str,book))
def __str__(self):
return self.name.title()
class Book(models.Model):
name = models.CharField(max_length = 150,) #Name of books
authors = models.ManyToManyField(Author,) #Many to many because multiple books can have multiple authors
genre = models.ManyToManyField(Genre)
def __str__(self):
return self.name.title()
这些是模型,类型和作者都与书籍有多对多的关系
serializers.py
class AuthorListSerializer(serializers.ModelSerializer):
class Meta:
model = models.Author
fields = ('name',)
class GenreListSerializer(serializers.ModelSerializer):
class Meta:
model = models.Genre
fields = ('name',)
class BookListSerializer(serializers.ModelSerializer):
authors = AuthorListSerializer(many = True,) #To represent the relationship as a string instead of id
genre = serializers.SlugRelatedField(many = True, queryset = models.Genre.objects.all(),slug_field = 'name')
class Meta:
model = models.Book
fields = ('name','authors','rating', 'genre')
class BookDetailSerializer(serializers.ModelSerializer):
publisher = serializers.SlugRelatedField(queryset = models.Publisher.objects.all(), slug_field= 'name') #To display publisher name instead of id
authors = serializers.StringRelatedField(many = True,) #To represent the relationship as a string instead of id
genre = serializers.StringRelatedField(many = True,)
class Meta:
model = models.Book
fields = ('name', 'authors', 'rating','genre',
'publisher', 'total_qty', 'avail_qty',
'pub_date','isbn','price',)
所以在我的 Django-Rest-Framework Browsable api 中,正常的 ForeignKey 字段显示了它们的选项以创建一个新的对象实例。 例如,“BookDetailSerializer”中的发布者将所有发布者显示为 POST 或 PUT 或 PATCH 请求的选项。 但是对于包括 Genre 和 Author 在内的多对多字段,它不仅是空白的,而且似乎我无法输入任何内容。 我已经尝试使用 DRF-writable-nested 第三方包但没有任何改变:
class BookListSerializer(WritableNestedModelSerializer):
authors = AuthorListSerializer(many = True,) #To represent the relationship as a string instead of id
genre = serializers.SlugRelatedField(many = True,
queryset = models.Genre.objects.all(),slug_field = 'name')
我的问题是如何才能通过可浏览的 DRF api 提出 POST 作者和流派列表请求? 提前致谢!!
This image shows the options available for making a POST request involving publishers
This image shows that you can't add any input for POST request involving both Genre and Authors as many-to many relations.
更新:所以我加了create方法还是不行,如下图:
class BookListSerializer(serializers.ModelSerializer):
authors = AuthorListSerializer(many = True,) #To represent the relationship as a string instead of id
genre = serializers.SlugRelatedField(many = True,
queryset = models.Genre.objects.all(),slug_field = 'name')
class Meta:
model = models.Book
fields = ('name','authors','rating', 'genre')
def create(self,validated_data):
authors_data = models.Author.objects.all()
book = Book.objects.create(authors = authors_data,**validated_data,)
return book
我能做什么?
折腾了4天终于找到答案了 在处理多对多关系时,你希望代码如下。
class BookListSerializer(serializers.ModelSerializer):
class Meta:
model = models.Book
fields = ('name','authors','rating', 'genre')
depth = 1
添加深度允许嵌套关系完全序列化。 因为关系是嵌套的,并且是多对多关系,所以您必须在 views.py 中创建自己的创建函数,如下所示:
class BookViewSet(GetSerializerClassMixin, viewsets.ModelViewSet):
queryset = models.Book.objects.all()
serializer_class = serializers.BookDetailSerializer
serializer_action_classes = {'list': serializers.BookListSerializer}
permission_classes = [IsAdminOrReadOnly, permissions.IsAuthenticated,]
def create(self,request, *args, **kwargs):
data = request.data
new_book = models.Book.objects.create(name = data["name"], publisher = models.Publisher.objects.get(id = data["publisher"]),
pub_date = data["pub_date"],
price = data["price"],
isbn = data['isbn'],)
new_book.save()
for author in data['authors']:
author_obj = models.Author.objects.get(name = author['name'])
new_book.authors.add(author_obj)
for gen in data['genre']:
gen_obj = models.Genre.objects.get(name = gen['name'])
new_book.genre.add(gen_obj)
serializer = serializers.BookListSerializer(new_book)
return Response(serializer.data)
对于多对多关系,您必须在保存对象后创建它们并手动将它们添加到对象中。 那里存在一个外键关系“发布者” 对于这种关系,您必须手动指向它在数据库中的位置,因此代码如下。
name = data["name"], publisher = models.Publisher.objects.get(id = data["publisher"]),
对于问题中的 Detail book serializer,它与 BookListSerializer 是一回事
这就是我在多对多关系中处理 POST 请求的方式