英文:
Django how get all invoices containing item
问题
I spent over two days looking in docs and internet and cannot find a solution. I have models:
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)
How to get a list of all invoices containing one product? I want to create a search engine.
I tried to define in InvoicedItems:
def get_invoices_by_article(article):
inv_obj = InvoicedItems.objects.filter(article=article)
inv = inv_obj.invoice
return inv
But all the time I get an error: QuerySet object has no attribute 'invoice'
. I know that I am close but I need your help. Thanks in advance!
英文:
I spent over two days looking in docs and internet and cannont find solution. I have models:
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)
How to get list of all invoices containing one product? I want to make search engine.
I tried to define in InvoicedItems:
def get_invoices_by_article(article):
inv_obj = InvoicedItems.objects.filter(article=article)
inv = inv_obj.invoice
return inv
But all the time I get error:
'QuerySet' object has no attribute 'invoice'
I know that I am close but I need your help.
Thanks in advance!
答案1
得分: 1
以下是翻译的内容:
你的问题是:'QuerySet' object has no attribute 'invoice'
。
当你使用任何 .filter()
调用时,它始终返回一个 QuerySet 对象,或者说是一个精巧的列表/数组。
在 python manage.py shell
中输出如下所示:
inv_obj = InvoicedItems.objects.filter(article=article_obj)
print(inv_obj)
# <QuerySet [<Article Object (1)>]>
# ^ 不是 Article 对象
因此,你的方法将需要进行一些小的更改(以及变量名称的更改):
def get_invoices_by_article(article):
inv_list = InvoicedItems.objects.filter(article=article)
inv = inv_list.first().invoice
return inv
但是!这引发了两个主要问题:
- 如果没有匹配的文章会怎样?
- 如果有多个怎么办?
示例解决方案:
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 [i.invoice for i in inv_list]
# 隐含情况:等于 1
# 返回单个发票
return inv_list.first().invoice
# 也许始终返回一个列表可能更容易,这样它始终是同一类型的!
# 无论是空的还是非空的!
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 对象 -> 额外的工作!
模型管理器方式:
my_return = InvoicedItems.objects.get_invoices_by_article(article_obj)
你减少了数据库查询!
基本模型管理器:
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.
添加任意数量的方法。
但也许模型方法或管理器方法有点过于复杂,这取决于你。
英文:
Your problem is this: 'QuerySet' object has no attribute 'invoice'
When you do any .filter()
call it always returns a QuerySet Obj.. or a fancy list/array
Outputting in python manage.py shell
demonstrates this:
inv_obj = InvoicedItems.objects.filter(article=article_obj)
print(inv_obj)
# <QuerySet [<Article Object (1)>]>
# ^ Not an Article Object
So your method will work with some minor changes (and a variable name change)
def get_invoices_by_article(article):
inv_list = InvoicedItems.objects.filter(article=article)
inv = inv_list.first().invoice
return inv
but! this raises 2 major issues:
- What if there's no matching articles?
- What if there's multiple?
Example Solutions:
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)]
After you figure out which path you want to take with the method, I'd recommend
making it into a Model Manager function instead.
Current way:
invoice_item = InvoicedItems.objects.all().first()
my_return = invoice_item.get_invoices_by_article(article_obj)
You must fetch an InvoiceItem Obj before you can use it -> Extra work!
Model Manager way:
my_return = InvoicedItems.objects.get_invoices_by_article(article_obj)
You cut out that 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()
Simple as that! Now you can add any number of methods you want for InvoicedItems.objects.
But maybe a Model Method or a Manager Method is overkill- idk! It's up to you
答案2
得分: 0
首先,让我们回答你的问题,进行一些编辑以使一切更简单:
在你的模型中为字段添加 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 的信息,请参考文档。
英文:
So first let answer your question, let's do some edit to make everything simplier:
in your model add the related_name to your fields:
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')
Then your query will look like this:
invoices = Invoice.objects.filter(invoiced_items__article=your_article)
Now let's make it simplier again removing your custom class which right now is useless:
class Product(models.Model):
[...]
class Invoice(models.Model):
[...]
products = models.ManyToManyField(to=Product, related_name='invoices')
And remove your model InvoicedItems.
Then your request become:
invoices = Invoice.objects.filter(products=product)
more info on ManyToManyFields on the documentation
答案3
得分: 0
我按照以下方式完成了它:
def get_invoices_by_article(article):
inv_obj = InvoicedItems.objects.filter(article=article)
return Invoice.objects.filter(invoiceditems__in=inv_obj)
英文:
I made it in this way:
def get_invoices_by_article(article):
inv_obj = InvoicedItems.objects.filter(article=article)
return Invoice.objects.filter(invoiceditems__in=inv_obj)
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论