通过OrderingFilter过滤平均和总和

huangapple go评论65阅读模式
英文:

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(&#39;productinfo__price&#39;) -
                      F(&#39;productinfo__cost_price&#39;) - 
                      F(&#39;productinfo__vat&#39;)
            )
        )
        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 = &quot;ordering&quot;
    ordering = OrderingFilter(
        fields=(
            (&quot;name&quot;, &quot;name&quot;),
            (&quot;profit&quot;, &quot;profit&quot;),
            (&quot;productinfo__price&quot;, &quot;price&quot;),
            (&quot;productinfo__barcode&quot;, &quot;barcode&quot;)
        )
    )

    class Meta:
        model = Product
        fields = &#39;__all__&#39;

huangapple
  • 本文由 发表于 2023年7月4日 20:31:20
  • 转载请务必保留本文链接:https://go.coder-hub.com/76612661.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定