【问题标题】:Django rest ModelViewSet filtering objectsDjango rest ModelViewSet 过滤对象
【发布时间】:2018-01-04 11:06:32
【问题描述】:

我有两个模型:Library 和 Book。一个图书馆会有很多书。

class Library(models.Model):
    library_id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=30)
    city = models.CharField(max_length=30)
    address = models.CharField(max_length=80)
    phone = models.CharField(max_length=30, blank=True, null=True)
    website = models.CharField(max_length=60, blank=True, null=True)

class Book(models.Model):
    book_id = models.AutoField(primary_key=True)
    title = models.CharField(max_length=30)
    # A library has many books
    which_library = models.ForeignKey('Library', related_name='books', on_delete=models.CASCADE)
    reader = models.ManyToManyField('Reader', related_name='wishlist')

我的序列化器:

class LibrarySerializer(serializers.ModelSerializer):
    class Meta:
        model = Library
        fields = '__all__'

class BookSerializer(serializers.ModelSerializer):

    wishlist = ReaderSerializer(many=True, read_only=True)

    class Meta:
        model = Book
        fields = '__all__'

我的看法:

class LibraryViewSet(viewsets.ModelViewSet):
    queryset = Library.objects.all()
    serializer_class = LibrarySerializer

class BookViewSet(viewsets.ModelViewSet):
    queryset = Book.objects.filter(which_library=library_id)
    serializer_class = BookSerializer

我的网址:

router = routers.DefaultRouter()
router.register(r'libraries', LibraryViewSet)
router.register(r'books/(?P<library_id>[0-9]+)', BookViewSet)

urlpatterns = router.urls

我的图书馆路线工作正常。但是对于书籍,我需要归还仅属于特定图书馆的书籍。默认 URL 和 all() 返回数据库中的所有书籍,并且可以通过点击 books/1 检索单个书籍。

我怎样才能做到这一点?我以前可以这样做:

@api_view(['GET', 'POST'])
def books(request, library_id): 

但现在我想用 ModelViewSet 来做。

【问题讨论】:

标签: django django-rest-framework


【解决方案1】:

覆盖视图集的get_queryset 方法,您可以在其中定义以返回特定书籍。像这样工作。

class BookViewSet(viewsets.ModelViewSet):

    serializer_class = LibrarySerializer
    def get_queryset(self):
        user = self.request.user
        books = Book.objects.filter(which_library=self.kwargs['library_id'])
        return books

您还可以定义list 和detail 方法,您可以在其中定义您对图书的自定义查询。这显示为here。

基本名称应该这样设置。

router.register(r'books/(?P<library_id>[0-9]+)', BookViewSet, base_name='books')

【讨论】:

  • 首先它抛出无法从视图集中自动确定名称,因为它没有.queryset 属性。错误。如果我添加 queryset = Book.objects.all() 那么它会抛出 global name 'library_id' is not defined 错误
  • get_queryset 是 ModelViewSet 的内置函数。您可以在文档中看到这一点。 django-rest-framework.org/api-guide/viewsets/#modelviewset
  • 我在这里 (django-rest-framework.org/api-guide/routers) 看到我必须向路由器注册一些 base_name,但我不知道具体如何
  • 它应该在您的路由器中设置。查看更新的答案
  • 我在哪里传递 library_id 参数?
【解决方案2】:

您可以将detail_route 添加到库视图集:

@detail_route(methods=['GET'])
def books_list(self, request, pk=None):
    library = self.get_object()   
    books = library.books.all()
    serializer = serializers.BookSerializer(books, many=True)
    response = Response(serializer.data)
    return response

现在图书馆的书应该用这个 url libraries/{libriry_id}/books_list 列出。

【讨论】:

  • 那么只有ModelViewSet不可能吗?我已经有了@api_view,但我认为使用 ModelViewSet 会减少我的代码
  • @Nitish detail_route 是 ModelViewSet 的一部分,它只是您添加到类中的附加方法。
  • @Nitish 在此处查看完整示例django-rest-framework.org/api-guide/viewsets/…
  • 我是否有两个单独的 URL,例如 books/ 和 books/ 或者只是稍后就足够了?因为现在我正在使用我的 Swagger 选项,例如 /api/books/{library_id}/{book_id}/books_list/ 或 /api/books/{library_id}/{book_id}/ 或 /api/books/{library_id}/获取
猜你喜欢
  • 2018-03-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-01-13
  • 1970-01-01
  • 2021-07-16
  • 2017-11-16
相关资源
最近更新 更多