【问题标题】:Django REST api and django_filter problemDjango REST api 和 django_filter 问题
【发布时间】:2019-10-15 17:11:13
【问题描述】:

rest_framework.viewsets.ReadOnlyModelViewSet 有问题。

class ProductFilter(filters.FilterSet):
    meat_type = filters.CharFilter(lookup_expr='slug__iexact')
    category = filters.CharFilter(lookup_expr='slug__iexact')

    class Meta:
        model = Product
        fields = {
            'price': ['gte', 'lte'],
        }
        ordering_fields = ['price', ]


class ProductViewSet(viewsets.ReadOnlyModelViewSet):
    queryset = Product.objects.all()
    serializer_class = ProductSerializer
    filterset_class = ProductFilter

    @action(methods=['get'], detail=False)
    def get_products(self, request):
        products = self.get_queryset().order_by('-created')
        serializer = self.get_serializer_class()(products, many=True)
        print('SHOW IT')
        if len(products) == 0:
            return Response(status=status.HTTP_204_NO_CONTENT)

        return Response(serializer.data, status=status.HTTP_200_OK)

我的问题是 get_products 中的 print 不起作用,但代码使用过滤器对象给出了很好的结果。我的网址:

router = routers.DefaultRouter()
router.register('', views.ProductViewSet)

urlpatterns = [
    path('shop/', include(router.urls))

]

测试:

class TestViews(TestCase):

    def setUp(self):
        self.client = Client()
        self.url = "/api/shop/"
        self.search_url = "/api/shop/?price__lte={}&price__gte={}&meat_type={}&category={}"

        self.category1 = Category.objects.create(name='cattest1',
                                                 slug='cattest1')
        self.category2 = Category.objects.create(name='cattest2',
                                                 slug='cattest2')
        self.meat_type1 = MeatType.objects.create(name='meattest1',
                                                  slug='meattest1')
        self.meat_type2 = MeatType.objects.create(name='meattest2',
                                                  slug='meattest2')
        self.product1 = Product.objects.create(category=self.category1,
                                               meat_type=self.meat_type2,
                                               name='prodtest1',
                                               slug='prodtest1',
                                               price=50)
        self.product2 = Product.objects.create(category=self.category1,
                                               meat_type=self.meat_type1,
                                               name='prodtest2',
                                               slug='prodtest2',
                                               price=75)
        self.product3 = Product.objects.create(category=self.category2,
                                               meat_type=self.meat_type2,
                                               name='prodtest3',
                                               slug='prodtest3',
                                               price=20)
        self.product4 = Product.objects.create(category=self.category2,
                                               meat_type=self.meat_type1,
                                               name='prodtest4',
                                               slug='prodtest4',
                                               price=150)

    def test_get_products_all(self):
        response = self.client.get(self.url)
        self.assertEqual(200, response.status_code)
        self.assertEqual(4, len(response.data))

    def test_get_products_no_content(self):
        Product.objects.all().delete()
        response = self.client.get(self.url)
        self.assertEqual(204, response.status_code)

    def test_product_greater_than(self):
        response = self.client.get(self.search_url.format(
            "", "55", "", ""
        ))
        self.assertEqual(200, response.status_code)
        self.assertEqual(2, len(response.data))

测试test_get_products_no_content 失败并出现错误: assertionError: 204 != 200
有人知道吗? 感谢您的任何回答
马格努斯

编辑
创建此函数,是将好的数据传递给过滤器。
DICT {'price__lte': '50', 'price__gte': '100', 'meat_type': 'wieprzowina'}
但是当我把它作为过滤参数时我有问题。出现错误:
int() 以 10 为底的无效文字:'wieprzowina'。它尝试将字符串更改为数字,但我不知道为什么。

    def get_queryset(self):

        filter_params = self.request.query_params
        filter_params_dict = {k: str(v) for (k, v) in filter_params.dict().items()
                              if v is not None and str(v) != ""}
        print('DICT', filter_params_dict)
        queryset = Product.objects.filter(**filter_params_dict)
        return queryset

编辑2:

class Product(models.Model):
    category = models.ForeignKey(Category,
                                 related_name='products',
                                 on_delete=models.CASCADE)
    meat_type = models.ForeignKey(MeatType,
                                  on_delete=models.CASCADE)
    name = models.CharField(max_length=150,
                            db_index=True)
    slug = models.SlugField(max_length=150,
                            db_index=True)
    image = models.ImageField(upload_to='products/%Y/%m/%d',
                              default='no-image.png')
    description = models.TextField(blank=True)
    price = models.DecimalField(max_digits=10, decimal_places=2)
    available = models.BooleanField(default=True)
    created = models.DateTimeField(auto_now_add=True)
    updated = models.DateTimeField(auto_now=True)

    class Meta:
        ordering = ('price',)
        index_together = (('id', 'slug'),)

    def __str__(self):
        return self.name

    def get_absolute_url(self):
        return reverse('shop:detail',
                       args=[self.category.slug, self.id, self.slug])

【问题讨论】:

  • 您使用的是哪个TestCase?来自django?这可能是因为之前的测试已经删除了所有产品,所以test_product_greater_than 找不到任何产品,然后返回 204 代码而不是 200
  • from django.test import TestCase,但这不是问题。
  • 我虽然您的过滤器工作正常,但在您更新问题后,我认为您应该检查您的过滤器集而不是创建一个新函数。您可以打印 sql 查询,以便我们现在可能会导致问题,如果您可以将模型包含到问题中,那就太好了。现在我认为问题是您的过滤器没有返回任何数据,这个问题与ReadOnlyModelViewSet无关,我认为

标签: django rest filter django-rest-framework


【解决方案1】:

您使用的网址不正确,您应该使用此网址进行自定义操作:

/api/shop/get_products/

您使用的网址,即 /api/shop/ 将调用视图集的默认列表操作而不是您的自定义操作,这就是为什么您总是会收到 200 个状态代码

您可以在此处阅读有关视图集的更多信息: ViewSets

【讨论】:

  • 好的,现在调用get_products函数,但它不过滤数据。我该如何解决?我尝试覆盖get_queryset。我可以通过self.request.query_params获取过滤器参数这是Query dict,我怎样才能将它传递给Product.objects.filter?
  • 我尝试这样做:[coderwall.com/p/gtwm1q/pass-a-querydict-to-a-django-queryset],但出现错误:ValueError at /api/shop/get_products/
  • 更新了我的帖子,你能看看吗?
  • 你的肉类型字段的数据类型是什么?是char还是int?
  • 我把我的产品模型放到了帖子里。
猜你喜欢
  • 2016-02-20
  • 2017-11-09
  • 2017-10-12
  • 2017-11-05
  • 2020-08-09
  • 2015-02-06
  • 2019-11-17
  • 1970-01-01
  • 2012-11-12
相关资源
最近更新 更多