我花了两天多的时间在文档和互联网上找,找不到解决方案。我有模型:
class Invoice(models.Model):
(...)
class Product(models.Model):
(...)
class InvoicedItems(models.Model):
invoice = models.ForeignKey(Invoice, on_delete=CASCADE)
article = models.ForeignKey(Product, on_delete=CASCADE)
如何获得包含一个产品的所有发票的列表?我想做一个搜索引擎。
我尝试在InvoicedItems中定义:
def get_invoices_by_article(article):
inv_obj = InvoicedItems.objects.filter(article=article)
inv = inv_obj.invoice
return inv
但是我总是得到错误:'QuerySet' object has no attribute 'invoice'
我知道我很接近,但我需要你的帮助。提前感谢!
你的问题是:'QuerySet' object has no attribute 'invoice'
any.filter()
叫它总是返回一个QuerySet对象。或者花哨的list/array
python manage.py shell
中的输出说明了这一点:
inv_obj = InvoicedItems.objects.filter(article=article_obj)
print(inv_obj)
# <QuerySet [<Article Object (1)>]>
# ^ Not an Article Object
所以你的方法将工作与一些小的改变(和一个变量名的改变)
def get_invoices_by_article(article):
inv_list = InvoicedItems.objects.filter(article=article)
inv = inv_list.first().invoice
return inv
但是!这会引发2major问题:
- 如果没有匹配的物品怎么办?
- 如果有多个呢?
示例解决方案:
def get_invoices_by_article(article):
inv_list = InvoicedItems.objects.filter(article=article)
count = inv_list.count()
if count == 0:
return None
if count > 1:
# return list of invoices
return [i.invoice for i in inv_list]
# implied: is 1
# return single invoice
return inv_list.first().invoice
# Maybe it's easier to ALWAYS return a List, so it's always a single type!
# empty or not!
def get_invoices_by_article(article):
return [i.invoice for i in InvoicedItems.objects.filter(article=article)]
在您弄清楚您想要使用该方法的路径之后,我建议把它变成一个模型管理器函数。
当前道:
invoice_item = InvoicedItems.objects.all().first()
my_return = invoice_item.get_invoices_by_article(article_obj)
必须在之前获取一个InvoiceItem Obj你可以用它->额外的工作!
Model Manager方式:
my_return = InvoicedItems.objects.get_invoices_by_article(article_obj)
你剪掉那个db hit!
Basic Model Manager:
from django.db import models
class InvoicedItemsManager(models.Manager):
def get_invoices_by_article(article):
return [i.invoice for i in InvoicedItems.objects.filter(article=article)]
class InvoicedItems(models.Model):
invoice = models.ForeignKey(Invoice, on_delete=CASCADE)
article = models.ForeignKey(Product, on_delete=CASCADE)
objects = InvoicedItemsManager()
就这么简单!现在您可以为InvoicedItems.objects.
添加任意数量的方法
但也许模型方法或管理方法是多余的- idk!由你决定
那么首先让我们来回答你的问题,让我们做一些编辑使一切变得更简单:
将related_name添加到您的字段中:
class InvoicedItems(models.Model):
invoice = models.ForeignKey(Invoice, on_delete=CASCADE, related_name='invoiced_items')
article = models.ForeignKey(Product, on_delete=CASCADE, related_name='invoiced_items')
那么你的查询将看起来像这样:
invoices = Invoice.objects.filter(invoiced_items__article=your_article)
现在让我们让它变得更简单,删除你的自定义类,现在是无用的:
class Product(models.Model):
[...]
class Invoice(models.Model):
[...]
products = models.ManyToManyField(to=Product, related_name='invoices')
并删除你的模型InvoicedItems。
那么你的请求变成:
invoices = Invoice.objects.filter(products=product)
关于ManyToManyFields的更多信息请参见文档
我是这样做的:
def get_invoices_by_article(article):
inv_obj = InvoicedItems.objects.filter(article=article)
return Invoice.objects.filter(invoiceditems__in=inv_obj)