ListView Django中的Floor Division和Modulo

时间:2018-05-16 01:40:28

标签: django django-views

使用Django Listview,是否可以显示包含楼层划分和模数值的新列?

我有以下两种模式:

models.py

class Model_Item(models.Model):
    item_name = models.CharField(max_length = 100, null = False, blank = False, unique = True)
    item_bottleperpack = models.FloatField(null = True, blank = False) # e.g. 100 bottles per pack

    def __unicode__(self):
        return self.item_name

class Model_ItemTransaction(models.Model):
    item = models.ForeignKey(Model_Item, to_field = "item_name")
    item_sold = models.FloatField(null = True, blank = True) # in terms of bottle

    def __unicode__(self):
        return self.item 

使用此列表视图:

views.py

class View_Item(ListView):
    def get_queryset(self):
        queryset = Model_Item.objects.all()
        queryset = queryset.annotate(
            sum_ = Sum("model_itemtransaction__item_sold")
            )
        queryset = queryset.annotate(
            floor_division_ = F("sum_") // F("item_bottleperpack"),
            module_ = F("sum_") %% F("item_bottleperpack")
            )
        return queryset

基本上,如果我已售出650瓶,每包装100瓶,我希望列表视图显示:

  • 6 包装在"地板部门"列,和
  • 50 >"模数"列。

目前,我的当前代码

收到以下错误
unsupported operand type(s) for //: 'F' and 'F'
and
unsupported operand type(s) for %%: 'F' and 'F'

并希望有人可以帮我找到任何解决方案(而且不一定是conditional expression)。

3 个答案:

答案 0 :(得分:0)

您可以在Model_Item中创建一个新的floor_division和module_字段,然后使用post save receiver更新floor_division和module_字段

from django.db.models.signals import pre_save
class Model_Item(models.Model):
  item_name = models.CharField(max_length = 100, null = False, blank = False, unique = True)
  item_bottleperpack = models.FloatField(null = True, blank = False) # e.g. 100 bottles per pack
  floor_division = models.IntegerField(null=True, blank=True)
  module_ = models.IntegerField(null=True, blank=True)
  def __unicode__(self):
    return self.item_name

def model_item_pre_save(sender, instance, created):
   item = Model_Item.objects.get(id=instance.id)
   item_transaction = Model_Transaction.objects.get(item_id=instance.id)
   item.floor_division = item_transaction.item_sold // item.item_bottleperpack
   item.module_ = item_transaction.item_sold %% item.item_bottleperpack


pre_save.connect(model_item_pre_save, sender=Model_Item)

答案 1 :(得分:0)

根据https://docs.djangoproject.com/en/2.0/_modules/django/db/models/expressions/

课程F或其父Combinable都未实施__floordiv__,因此//未实施。 Combinable确实实施了__truediv__,即/运营商。

我还没有听说过Python中的运算符%%,但%会有效,因为__mod__中已实现Combinable

尝试对models.IntegerFieldmodels.PositiveIntegerField使用item_bottleperpackitem_sold,并在views.py中更新此行:

queryset = queryset.annotate(
        floor_division_ = F("sum_") / F("item_bottleperpack"),
        module_ = F("sum_") % F("item_bottleperpack")
        )

我假设Combinable将返回一个整数作为除以两个整数的输出 - 这可能不是这种情况。如果是这样,您可能想要舍入结果。

答案 2 :(得分:0)

所以我找到了解决这个问题的方法,感谢这个post

首先我清理了views.py,

中的代码

views.py

class View_Item(ListView):
    def get_queryset(self):
        queryset = Model_Item.objects.all()
        queryset = queryset.annotate(
            sum_ = Sum("model_itemtransaction__item_sold")
            )
        return queryset

然后将此代码文件添加到templatetags文件夹中,

app_filters.py

from django import template

register = template.Library()

@register.filter(name = "func_floor_division")
def func_floor_division(num, val):
    if num:
        floor_division = num // val
        return floor_division
    else:
        return None

@register.filter(name = "func_modulo")
def func_modulo(num, val):
    if num:
        modulo = num % val
        return modulo
    else:
        return None

最后修改了html文件中的标签。

的HTML

{% load app_filters %}
<table>
    <tr>
        <th>Floor Division</th>
        <th>Modulo</th>
    </tr>

    {% for obj_ in object_list %}
        <tr>
            <td>{{ obj_.sum_|func_floor_division:obj_.item_bottleperpack }}</td>
            <td>{{ obj_.sum_|func_modulo:obj_.item_bottleperpack }}</td>
        </tr>
    {% endfor %}
</table>

希望这对遇到同样问题的人有所帮助。