【问题标题】:Associate child object with parent object per instance in Django?Django中每个实例的子对象与父对象相关联?
【发布时间】:2020-08-05 18:30:33
【问题描述】:

我有两个模型,一个 Invoice 模型和一个 Expense 模型。创建发票后,用户应该能够添加发票的所有费用。一旦创建了发票 - 这些费用应该以某种方式“检查”,因此新发票不会添加相同的费用。我需要对费用实例进行某种形式的检查,说“已开具发票”或其他内容。不完全确定如何仅使用 ..set.filter(...) 查询集我的两个模型如下所示:

费用模型


class Expense(Model):
    cost = DecimalField(blank=True, null=True, max_digits=10, decimal_places=2)
    project = ForeignKey(Project, on_delete=CASCADE)
    user = ForeignKey(User, on_delete=CASCADE) 
    billable = BooleanField(default=False)
    expense_date = DateField()
    date_created = DateTimeField(auto_now_add=True)
    invoice = ForeignKey("finances.Invoice", blank=True, null=True, on_delete=SET_NULL, help_text="Optionally link this to an existing invoice")


发票模型

class Invoice(Model):
    issue_date = DateField(default=now)
    due_date = DateField()
    project = ForeignKey(Project, on_delete=CASCADE)
    amount = DecimalField(blank=True, null=True, max_digits=100, decimal_places=2)
    include_expenses = BooleanField(default=False, help_text='Check this box to include all expenses that are within the invoice billable date range')
    billable_start = DateField(help_text="Logged hours start date")
    billable_end = DateField(help_text="Logged hours end date")

我尝试在 Expense 模型上添加一个查询集:

    def get_billable_expenses(self):
        """Getting all expenses for selected billable period"""
        start_week = self.get_start_isoweek()
        end_week = self.get_end_isoweek()
        return self.project.expense_set.filter(
            expense_date__gte=self.billable_start, 
            expense_date__lte=self.billable_end,
            billable=True,
            invoice=self.id
        )

然后添加一个在保存发票时触发的信号:

@receiver(post_save, sender=Invoice)
def prepare_calculation_data(sender, instance=None, created=False, **kwargs):
    if created:
        expenses_to_add = []
        for expense in instance.get_billable_expenses():
            expense.invoice = instance
            expenses_to_add.append(expense)
        Expense.objects.bulk_update(expenses_to_add, ['invoice'])
    

不知道如何处理这个问题 - 我想我会通过检查费用是否已经有与之相关的发票来解决它 - 如果没有 - 将其包含在新创建的发票中(如上面的 get_billable_expenses() 所示)但是这意味着不会添加任何新费用,因为 invoicefield 不会为空

有什么解决方法的建议吗?

【问题讨论】:

  • 我认为您已经使用 Expense.invoice 字段解决了这个问题。我怀疑真正的问题是阻碍您继续进行该设计选择的因素。你能详细解释一下你在上一段中提到的场景吗?
  • 当然。看到 get_billable_expenses() 中有一个过滤器。我应该如何进行?如果有“invoice=self.id”,每当我创建新费用时,都不会因为该过滤器而添加任何费用。没有它,所有的费用都会加起来。你看到“悖论”了吗?
  • 您对get_billable_expenses 的导入说这是收费的,但有invoice=self.id 的过滤器。
  • 您何时尝试使用get_billable_expenses?是要查找未开票的费用还是与发票相关的费用?还是两者兼而有之?
  • 什么类型的费用,未开票、已开票或全部?

标签: django django-models django-forms


【解决方案1】:

我通过在我的 Invoice 模型上使用两种方法解决了这个问题。一种查询未开票的费用:

    def get_billable_expenses(self):
        """Getting all expenses for selected billable period"""
        start_week = self.get_start_isoweek()
        end_week = self.get_end_isoweek()
        return self.project.expense_set.filter(
            expense_date__gte=self.billable_start, 
            expense_date__lte=self.billable_end,
            status='approved',
            billable=True,
            invoice__isnull=True
        )

然后在我的模板中显示这些费用:

    def get_linked_expenses(self):
        return self.project.expense_set.filter(
            invoice=self.id
        )

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-04-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多