Django如何获取包含特定物品的所有发票。

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

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

但是!这引发了两个主要问题:

  1. 如果没有匹配的文章会怎样?
  2. 如果有多个怎么办?

示例解决方案:

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:

  1. What if there's no matching articles?
  2. 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)

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

发表评论

匿名网友

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

确定