英文:
Filtering avg sum via OrderingFilter
问题
需要通过OrderingFilter来筛选avg(非模型)字段。
我的models.py
class Product(models.Model):
    store = models.ForeignKey(Store, on_delete=models.CASCADE, null=True, verbose_name="store")
    sku = models.CharField(max_length=255, blank=True, default="", verbose_name="SKU")
    name = models.CharField(max_length=255, blank=True, default="", verbose_name="name")
class ProductInfo(models.Model):
    default_related_name = "productinfo"
    product = models.OneToOneField("Product", on_delete=models.CASCADE, null=True, verbose_name="product")
    barcode = models.CharField(max_length=255, null=True, verbose_name="barcode")
    price = models.DecimalField(max_digits=7, decimal_places=2, default=Decimal(0), verbose_name="price")
    cost_price = models.DecimalField(max_digits=7, decimal_places=2, default=Decimal(0), verbose_name="cost price")
    vat = models.DecimalField(max_digits=3, decimal_places=1, default=Decimal(0), verbose_name="% tax")
我通过OrderingFilter来筛选Product。
我的filters.py
from products.models import Product
from django_filters import OrderingFilter
from django_filters.rest_framework import FilterSet
class ProductFilter(FilterSet):
    order_by_field = "ordering"
    ordering = OrderingFilter(
        fields=(
            "name",
            (("productinfo__price"), ("price")),
            (("productinfo__barcode"), ("barcode")),
        )
    )
    class Meta:
        model = Product
我需要计算销售利润。这可以通过一个单独的函数或者使用注释来完成。
price-cost_price-taxes_sum=profit
但这个参数不是一个模型字段。我是否可以将它添加到过滤器中?目标是通过排序来获取利润更多的商品。
英文:
I need to filter avg (non-model) field via OrderingFilter.
My models.py
class Product(models.Model):
    store = models.ForeignKey(Store, on_delete=models.CASCADE, null=True, verbose_name="store")
    sku = models.CharField(max_length=255, blank=True, default="", verbose_name="SKU")
    name = models.CharField(max_length=255, blank=True, default="", verbose_name="name")
class ProductInfo(models.Model):
    default_related_name = "productinfo"
    product = models.OneToOneField("Product", on_delete=models.CASCADE, null=True, verbose_name="product")
    barcode = models.CharField(max_length=255, null=True, verbose_name="barcode")
    price = models.DecimalField(max_digits=7, decimal_places=2, default=Decimal(0), verbose_name="price")
    cost_price = models.DecimalField(max_digits=7, decimal_places=2, default=Decimal(0), verbose_name="cost price")
    vat = models.DecimalField(max_digits=3, decimal_places=1, default=Decimal(0), verbose_name="% tax")
I filter Product via OrderingFilter
My filters.py
from products.models import Product
from django_filters import OrderingFilter
from django_filters.rest_framework import FilterSet
class ProductFilter(FilterSet):
    order_by_field = "ordering"
    ordering = OrderingFilter(
        fields=(
            "name",
            (("productinfo__price"), ("price")),
            (("productinfo__barcode"), ("barcode")),
        )
    )
    class Meta:
        model = Product
I need to calculate the profit from the sales. This can be done in a separate function or I can use an annotation.
price-cost_price-taxes_sum=profit
But this parameter is not a model field. Can I somehow add it to the filter? The goal is to get goods that bring more profit by sorting.
答案1
得分: 2
你可以像这样向你的过滤器集添加字段:
import django_filters
class ProductFilter(FilterSet):
    profit = django_filters.CharFilter(method='profit_filter', label='profit')
    class Meta:
        model = Product
        fields = [
            'profit'
        ]
    def profit(self, queryset, name, value):
        return queryset.annotate().filter()
英文:
you can add fields to your filterset like this :
import django_filters
class ProductFilter(FilterSet):
    profit = django_filters.CharFilter(method='profit_filter', label='profit')
    class Meta:
        model = Product
        fields = [
            'profit'
            ]
    def profit(self, queryset, name, value):
        return queryset.annotate().filter()
答案2
得分: 0
你可以使用F expressions在QuerySet中进行<code>profit</code>的注释,然后将其简单地添加到你的<code>filter</code>中。
<h4>一个例子:</h4>
views.py
from rest_framework.viewsets import ModelViewSet
from django.db.models import F
from myapp.models import Product
from myapp.filters import ProductFilter
from myapp.serializers import ProductSerializer
from django_filters import rest_framework as filters
class ProductViewSet(ModelViewSet):
    queryset = Product.objects.all()
    serializer_class = ProductSerializer
    filter_backends = [filters.DjangoFilterBackend]
    filterset_class = ProductFilter
    def get_queryset(self):
        qs = ( 
            super()
            .get_queryset()
            .annotate(profit= F('productinfo__price') - F('productinfo__cost_price') - F('productinfo__vat'))
        )
        return qs
filters.py
from .models import Product
from django_filters import OrderingFilter
from django_filters.rest_framework import FilterSet
class ProductFilter(FilterSet):
    order_by_field = "ordering"
    ordering = OrderingFilter(
        fields=(
            ("name", "name"),
            ("profit", "profit"),
            ("productinfo__price", "price"),
            ("productinfo__barcode", "barcode")
        )
    )
    class Meta:
        model = Product
        fields = '__all__'
英文:
You can annotate the QuerySet with <code>profit</code> using <code>F expressions</code> and simply add it to your <code>filter</code>.
<h4>An example:</h4>
views.py
from rest_framework.viewsets import ModelViewSet
from django.db.models import F
from myapp.models import Product
from myapp.filters import ProductFilter
from myapp.serializers import ProductSerializer
from django_filters import rest_framework as filters
class ProductViewSet(ModelViewSet):
    queryset = Product.objects.all()
    serializer_class = ProductSerializer
    filter_backends = [filters.DjangoFilterBackend]
    filterset_class = ProductFilter
    def get_queryset(self):
        qs = ( 
            super()
            .get_queryset()
            .annotate(profit=
                      F('productinfo__price') -
                      F('productinfo__cost_price') - 
                      F('productinfo__vat')
            )
        )
        return qs
filters.py
from .models import Product
from django_filters import OrderingFilter
from django_filters.rest_framework import FilterSet
class ProductFilter(FilterSet):
    order_by_field = "ordering"
    ordering = OrderingFilter(
        fields=(
            ("name", "name"),
            ("profit", "profit"),
            ("productinfo__price", "price"),
            ("productinfo__barcode", "barcode")
        )
    )
    class Meta:
        model = Product
        fields = '__all__'
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论