[英]Reverse One-to-Many-Relationship in Django
My app links invoices, contracts and services with Many-to-One-Relationships:我的应用程序将发票、合同和服务与多对一关系联系起来:
class Invoice(models.Model):
contract = models.ForeignKey(Contract, on_delete=models.CASCADE)
class Contract(models.Model):
service = models.ForeignKey(Service, on_delete=models.CASCADE)
Whenever a new invoice is registered, it can be linked to a service and split/billed internally.每当注册新发票时,它都可以链接到服务并在内部拆分/计费。 Unfortunately, some contracts/invoices need to be linked to more than one service according to a fixed split (eg 30/70).
不幸的是,一些合同/发票需要根据固定的拆分(例如 30/70)链接到不止一项服务。
For this to work on the surface, I could to reverse the relationship between contracts and services –为了让它在表面上起作用,我可以颠倒合同和服务之间的关系——
class Service(models.Model):
contract = models.ForeignKey(Contract, on_delete=models.CASCADE)
– or change the ForeignKey
field on the Contract
class to a ManyToManyField
. – 或者将
Contract
class 上的ForeignKey
字段更改为ManyToManyField
。
But in both cases, I will not be able to get back from the invoice to the service easily anymore, as with the following statement:但在这两种情况下,我将无法再轻松地从发票返回到服务,如以下声明:
invoices = Invoice.objects.filter(models.Q(contract__service__building=self.tenant.unit.building), models.Q(begin__lte=self.begin, end__gt=self.begin) | models.Q(begin__gt=self.begin, begin__lt=self.end))
Is it wise to insert an intermediate helper model ( ContractService
) with two ForeignKey
fields to keep the current app logic and add the option to link a contract to more than one service?插入一个带有两个
ForeignKey
字段的中间助手 model ( ContractService
) 以保持当前应用程序逻辑并添加将合同链接到多个服务的选项是否明智?
Ok just to clarify one example:好的,只是为了澄清一个例子:
You want a relationship that "Invoice1" can be linked to "Cleaning of first floor" AND "Cleaning of second floor".您想要一种关系,即“发票 1”可以链接到“一楼清洁”和“二楼清洁”。
models.py模型.py
class Contract(models.Model):
"""Can hold multiple Services"""
pass
class Service(models.Model):
"""Is linked to one specific Contract"""
contract = models.ForeignKey(Contract, on_delete=models.CASCADE)
class Invoice(models.Model):
"""Can hold multiple Services and one Service can hold multiple Invoices"""
service = models.ManyToManyField(Service)
Now your question is: "I can easily get the contract when I have the Service object, but how can I get the Service when I have the Contract object?现在你的问题是:“当我有服务object时,我可以很容易地获得合同,但是当我有合同object时,我如何获得服务?
con = Contract.objects.all().first()
queryset = con.service_set.all() # gives you all related Services for that specific Contract
Read more about ManytoOne阅读更多关于ManytoOne 的信息
And: "How can I get the Invoice when I have the Service object?"并且:“当我有服务 object 时,我怎样才能得到发票?”
ser = Service.objects.all().first()
queryset = ser.invoice_set.all() # gives you all related Invoices for that specific Service
Read more about ManyToMany阅读更多关于ManyToMany的内容
Let me know how it goes让我知道事情的后续
Thanks to @Tarquinius for your help – I found a solution based on his suggestion.感谢@Tarquinius 的帮助——我根据他的建议找到了解决方案。 The three models in question are connected as follows:
所讨论的三个模型的连接如下:
class Service(models.Model):
pass
class Contract(models.Model):
services = models.ManyToManyField(Service)
class Invoice(models.Model):
contract = models.ForeignKey(Contract, on_delete=models.CASCADE)
The query quoted above did not even need to be modified (apart from the different fieldname) to reflect the possibility of more than one service per contract, I just had to add the distinct() function:上面引用的查询甚至不需要修改(除了不同的字段名)以反映每个合同有多个服务的可能性,我只需要添加 distinct() function:
invoices = Invoice.objects.filter(models.Q(contract__services__building=self.tenancy_agreement.unit.building), models.Q(begin__lte=self.begin, end__gt=self.begin) | models.Q(begin__gt=self.begin, begin__lt=self.end)).distinct()
In hindsight, this is quite obvious (and simple).事后看来,这是很明显的(也很简单)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.