首页 > 解决方案 > Django REST api 和 django_filter 问题

问题描述

我有问题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)

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

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
有人知道吗?
感谢马格努斯的任何回答

EDIT
创建了这个函数,就是将好的数据传递给过滤器。
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])

标签: djangorestfilterdjango-rest-framework

解决方案


您使用的 url 不正确,您应该将此 url 用于您的自定义操作:

/api/shop/get_products/

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

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


推荐阅读