在Django中显示部分表格内联模型

时间:2010-06-30 14:12:31

标签: django django-admin abstract-class tabular

让我们看看我是否可以解释自己,我有这个模型:

class BillHeader(models.Model):
    number = models.CharField(_('Bill number'), max_length=10, unique=True, \
    default=__number)
    client = models.ForeignKey(ClienteYProveedor, verbose_name=_('Client'))
    date = models.DateTimeField(_('Date'), default=datetime.now)

    def __unicode__(self):
        return str(self.number)

    class Meta:
        abstract = True

class BillFooter(models.Model):           
    base_import = models.DecimalField(_('Base import'), max_digits=12, \
    decimal_places=2)

    class Meta:
        abstract = True

class BillBody(models.Model):        
    description = models.CharField(_('Description'), max_length=200)
    amount = models.DecimalField(_('Amount'), max_digits=6, decimal_places=2)
    discount = models.DecimalField(_('Discount'), max_digits=4, \
    decimal_places=2)
    price = models.DecimalField(_('Price'), max_digits=12, decimal_places=2)
    unitaryprice = models.DecimalField(_('Unitary Price'), max_digits=12, \
    decimal_places=2)

    def __unicode__(self):
        return self.description
    class Meta:
        abstract = True

class EmittedBill(BillHeader, BillBody, BillFooter):
    pass

class ReceivedBill(BillHeader, BillBody, BillFooter):
    pass

当用户添加Emmited或Received帐单时,我需要将BillHeader显示为普通字段集,但BillBodyBillFooter必须为TabularInline

如果我将这些作为TabularInline放在admin.py中,则会出现错误,表示他们需要ForeignKey相关模型。当然,我不能把那些外键,因为它们是在底部声明的。我想你们都称之为“倒退的外键”。

我的问题是:我怎么能这样做才能在管理员中显示TabularInlines而不会弄得一团糟?我可以在没有抽象基类的情况下做到这一点,但随后又出现了另一个问题,它显示了TabularInline中的其他ForeignKey(如果你在EmmitedBills上它显示了TabularInline中的FK到ReceivedBills,反之亦然)我无法排除它们。

很抱歉,如果这是一个愚蠢的问题,但我不是程序员(这只是一个爱好)而且我真的让自己陷入数据模型混乱。


我会更好地解释:

我有两种类型的帐单EmittedReceived,它们都显示在管理员家中(这就是为什么我没有使用BooleanField来标记它们)。这两种类型都有相同的字段,除了一个,即帐号,在Emmitted中将自动生成。每个账单包括1个标题,包括数字,客户和日期,1个或多个主体内联条目,包含描述,金额,价格等,以及1个内联页脚,显示不含税的总价,应用税等。


更新

我已经完成了所有工作,但我有一个问题,在我的新模型中,BillBody有两个FK(EmmitedBill和ReceivedBill),它们出现在TabularInline中。如何隐藏它们?field.exclude()给出错误。

1 个答案:

答案 0 :(得分:2)

我不完全理解你的问题,但你可以使用

ForeignKey('ModelName')

而不是

ForeignKey(ModelName)

如果尚未声明ModelName模型。也许这解决了你的问题。

内联管理员(例如TabularInline)仅在您具有一对多关系时使用,该关系由许多侧的ForeignKey创建。如果您没有这样的外键,则无法使用内联管理员。继承绝对不同于ForeignKey

但是,我认为您的数据模型是错误的。看起来你确实想存钱。有两种类型的账单,emittedreceived账单。 emittedreceived帐单都有相同的字段。此外,您希望每个帐单包含一个带有数字,客户和日期,一个或多个正文条目的标题,其中每个条目都存储您存储在BillBody中的信息以及一个或多个小数base_number


可能更适合您的数据模型

class Bill(models.Model):
    number = models.CharField(_('Bill number'), max_length=10, unique=True, default=__number)
    client = models.ForeignKey(ClienteYProveedor, verbose_name=_('Client'))
    date = models.DateTimeField(_('Date'), default=datetime.now)

    def get_total_price(self):
        return sum([entry.price for entry in self.entries])

class BillEntry(models.Model):
    bill = models.ForeignKey(Bill, related_name='entries')

    description = models.CharField(_('Description'), max_length=200)
    amount = models.DecimalField(_('Amount'), max_digits=6, decimal_places=2)
    discount = models.DecimalField(_('Discount'), max_digits=4, decimal_places=2)
    price = models.DecimalField(_('Price'), max_digits=12, decimal_places=2)
    unitaryprice = models.DecimalField(_('Unitary Price'), max_digits=12, decimal_places=2)

我遗漏了__unicode__方法。

现在您有一个从BillEntryBill的外键,您可以使用表格内联。我不明白你对base_import的使用情况,所以我把它留了出来。

价格计算

如果您的price应该总是等于amount*unitaryprice - discountamount*(unitaryprice-discount),那么您不应该将其放在字段中,而是在需要时计算它,无论是在Python中还是在数据库。如果要在Python中执行此操作,可以使用类似于get_total_price的方法。如果你想在查询数据库时计算它们,那么让它与Django一起使用会有点困难。

在最后一种情况下,您可以查看SQL视图,但我认为这对于初学者来说有点太难了。另一种选择是使用自定义SQL表达式:

BillEntry.objects.extra(select={'price': 'amount*unitaryprice-discount'})

这将计算选择期间所有条目的价格。

<强>更新

如果为已发出和已接收的帐单添加两个子类并使用multi table inheritance,则可以使用从BillEntryBill的一个外键。

class EmittedBill(Bill):
    pass

class ReceivedBill(Bill):
    pass

您可能还需要考虑Django生成的数据库模型。通常,您只想在数据库中存储基本数据,而不是计算数据(就像您想要在页脚中一样)。因此,如果使用某个公式计算价格并使用unitarypriceamount等,则不应存储此公式的结果,而是在必要时重新计算(最终缓存以避免重新计算) 。如果你不这样做,可能会在某些时候更新某些内容(例如amount)并忘记更新计算值(price),这会导致数据库中的不一致(因此你的应用程序中的错误)。一个好的数据库确实有约束,因此在不破坏至少一个约束的情况下不可能存储不一致的数据库。

我也不明白为什么你需要为每个账单单独的页眉和页脚。模型不是真正的账单,它存储账单的信息。如果您想要一个可见的页眉和页脚,那么您应该在视图层(模板)而不是模型本身中执行此操作。