Python 如何使用distinct()为Django ListView中的每个标题项仅显示子模型中的一条记录
我在Django应用程序中使用了两个相关的模型。在模型中创建的对象将使用listview类显示。在子模型中,我可以基于某个关键日期创建多行。当我尝试显示两个模型中的值时,将显示相应FK字段的所有子对象(如果存在多条记录) 让我把情况说清楚如下: models.py views.py 现在,物料价格会定期变化,并且每个关键日期的每种物料都会有多个价格项(Python 如何使用distinct()为Django ListView中的每个标题项仅显示子模型中的一条记录,python,django,sqlite,django-views,Python,Django,Sqlite,Django Views,我在Django应用程序中使用了两个相关的模型。在模型中创建的对象将使用listview类显示。在子模型中,我可以基于某个关键日期创建多行。当我尝试显示两个模型中的值时,将显示相应FK字段的所有子对象(如果存在多条记录) 让我把情况说清楚如下: models.py views.py 现在,物料价格会定期变化,并且每个关键日期的每种物料都会有多个价格项(price\u valid\u from\u date)。我的目标是显示存在价格文件的所有材料的最新价格。我的困境是如何为同一材料/文件组合选择多
price\u valid\u from\u date
)。我的目标是显示存在价格文件的所有材料的最新价格。我的困境是如何为同一材料/文件组合选择多个价格项目中的一个。我的代码行'mat\u price\u item\u list':MatPriceItems.objects.distinct().order\u by('price\u doc\u header'),
当然不会产生任何结果(所有价格项都显示在连续的列中)
是否有办法在列表视图中只显示一个价格项目?
编辑
下图显示了材料不同日期的价格。我想得到的只是显示某一特定材料的最新(有效)日期的价格。因此,在即时情况下(如图所示),应仅显示2020年3月4日每种商品的价格MS和HSD
编辑2
这就是标题文档编号(此处编号为32)实例的子模型数据的外观(使用数据浏览器从子表中获取图像):
列为:子对象。物料编号/价格/有效期自/有效期至/Hdr文件编号/子Obj行编号
我的想法是:我不能只从文档编号集合中提取第一个对象(子集)吗?在即时情况下(参考图片),文件编号32有三个子项(轴承编号148、149和156)。是否不可能只拾取项目编号156并丢弃其余项目
我试过:
MatPriceItems.objects.order\u by('-price\u valid\u to\u date')。first()
但引发错误“MatPriceItems”对象不可编辑
什么使我能够获取标题项目的唯一项目并显示它?我相信您需要以下内容:
class MatPriceListView(ListView):
template_name = "mat_price_list.html"
context_object_name = 'matprice'
model = MatPriceDoc
def get_context_data(self, **kwargs):
context = super(MatPriceListView, self).get_context_data(**kwargs)
context.update({
'mat_price_item_list': MatPriceItems.objects.all().('-price_doc_header').first(),
})
return context
def get_queryset(self):
return MatPriceDoc.objects.order_by('mat_num')
关键的变化是:
MatPriceItems.objects.all().order_by('-price_doc_header').first()
这样,您就可以按price\u doc\u标题
降序订购(因此该值的前面是负数)。然后在返回的
对象中获取.first()
同样,以下内容也是有效的:
MatPriceItems.objects.all().order_by('price_doc_header').last()
您还可以在ORM中使用Django的内置聚合:
from django.db.models import Max
MatPriceItems.objects.all().aggregate(Max('price_doc_header'))
综上所述,我认为代码可读性的最佳解决方案是使用Django的内置Max
函数:
from django.db.models import Max
class MatPriceListView(ListView):
template_name = "mat_price_list.html"
context_object_name = 'matprice'
model = MatPriceDoc
def get_context_data(self, **kwargs):
context = super(MatPriceListView, self).get_context_data(**kwargs)
context.update({
'mat_price_item_list': MatPriceItems.objects.all().aggregate(Max('price_doc_header'))
})
return context
def get_queryset(self):
return MatPriceDoc.objects.order_by('mat_num')
因为它准确地告诉任何同事你在做什么:取最大值
更新:再看一眼你的问题-我相信你可能还需要做一些
.filter()
…然后为Max
做一个.annotate()
。我相信你需要以下几点:
class MatPriceListView(ListView):
template_name = "mat_price_list.html"
context_object_name = 'matprice'
model = MatPriceDoc
def get_context_data(self, **kwargs):
context = super(MatPriceListView, self).get_context_data(**kwargs)
context.update({
'mat_price_item_list': MatPriceItems.objects.all().('-price_doc_header').first(),
})
return context
def get_queryset(self):
return MatPriceDoc.objects.order_by('mat_num')
关键的变化是:
MatPriceItems.objects.all().order_by('-price_doc_header').first()
这样,您就可以按price\u doc\u标题
降序订购(因此该值的前面是负数)。然后在返回的
对象中获取.first()
同样,以下内容也是有效的:
MatPriceItems.objects.all().order_by('price_doc_header').last()
您还可以在ORM中使用Django的内置聚合:
from django.db.models import Max
MatPriceItems.objects.all().aggregate(Max('price_doc_header'))
综上所述,我认为代码可读性的最佳解决方案是使用Django的内置Max
函数:
from django.db.models import Max
class MatPriceListView(ListView):
template_name = "mat_price_list.html"
context_object_name = 'matprice'
model = MatPriceDoc
def get_context_data(self, **kwargs):
context = super(MatPriceListView, self).get_context_data(**kwargs)
context.update({
'mat_price_item_list': MatPriceItems.objects.all().aggregate(Max('price_doc_header'))
})
return context
def get_queryset(self):
return MatPriceDoc.objects.order_by('mat_num')
因为它准确地告诉任何同事你在做什么:取最大值
更新:再看一眼你的问题-我相信你可能还需要做一些
.filter()
…然后为Max
做一个.annotate()
。我还添加了我现在认为正确的答案,基于对你问题的重读
我觉得这个问题需要简化为:
MatPriceItems.objects.all().select_related(
'mat_price_docs'
).order_by(
'price_doc_header__mat_num'
)
i、 e
为了实现这一点,您还可以将相关的\u name
参数添加到价格\u单据头
ForeignKey
字段中
class MatPriceItems(models.Model):
price_doc_header = models.ForeignKey(MatPriceDoc, related_name='mat_price_docs', on_delete=...)
price_item_num = models.CharField(max_length=3, default=10,...)
price_valid_from_date = models.DateField(null=True, verbose_name='From date')
price_valid_to_date = models.DateField(null=True, verbose_name='To date')
mat_price = models.DecimalField(max_digits=7, decimal_places=2, null=True, blank=True,...)
一如既往,对模型的任何更改-请重新运行makemigarations
和migrate
管理命令
编辑:您甚至可以使用注释链接到ForeignKey来定义新的查询集:
def get_queryset(self):
return MatPriceItems.objects.all().order_by(
'price_doc_header__mat_num'
).annotate(
mat_price_doc_number = F('price_doc_header__mat_price_doc_number')
...
)
注意:您可以从django.db.models import F导入F()表达式,根据对您的问题的重读,我现在还添加了我认为正确的答案 我觉得这个问题需要简化为:
MatPriceItems.objects.all().select_related(
'mat_price_docs'
).order_by(
'price_doc_header__mat_num'
)
i、 e
为了实现这一点,您还可以将相关的\u name
参数添加到价格\u单据头
ForeignKey
字段中
class MatPriceItems(models.Model):
price_doc_header = models.ForeignKey(MatPriceDoc, related_name='mat_price_docs', on_delete=...)
price_item_num = models.CharField(max_length=3, default=10,...)
price_valid_from_date = models.DateField(null=True, verbose_name='From date')
price_valid_to_date = models.DateField(null=True, verbose_name='To date')
mat_price = models.DecimalField(max_digits=7, decimal_places=2, null=True, blank=True,...)
一如既往,对模型的任何更改-请重新运行makemigarations
和migrate
管理命令
编辑:您甚至可以使用注释链接到ForeignKey来定义新的查询集:
def get_queryset(self):
return MatPriceItems.objects.all().order_by(
'price_doc_header__mat_num'
).annotate(
mat_price_doc_number = F('price_doc_header__mat_price_doc_number')
...
)
注意:您可以从django.db导入F()表达式,作为
。models import F
您使用的是什么数据库?@WillemVanOnsem:我使用sqlite3进行测试。Distinct将返回表中所有的Distinct记录,而不是一条……也许您需要按对u进行排序,然后使用。first()
,以获得“最大值”你能澄清一下是什么吗