【问题标题】:Showing partial tabular inline models in Django在 Django 中显示部分表格内联模型
【发布时间】:2010-06-30 14:12:30
【问题描述】:

让我们看看我能不能解释一下,我有这个模型:

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() 会出错。

【问题讨论】:

  • 因此,假设您是一家公司,发出的账单是您发送给您的一位客户的账单(并且客户必须支付账单),而收到的账单是您收到的账单您的供应商之一(您必须支付账单)? In 将使用您可能应该使用的数据模型在下面编辑我的答案。也许你可以通过使用 limit_choices_to 来解决 BillBody 中两个 FK 的问题,请参阅 docs.djangoproject.com/en/1.2/ref/models/fields/#foreignkey

标签: django django-admin abstract-class tabular


【解决方案1】:

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

ForeignKey('ModelName')

而不是

ForeignKey(ModelName)

如果 ModelName 模型尚未声明。也许这可以解决您的问题。

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

但是,我认为您的数据模型是错误的。看来您确实想存储账单。有两种类型的账单,emittedreceived 账单。 emittedreceived 账单都具有相同的字段。此外,您希望每张账单都包含一个带有编号、客户和日期的标题、1 个或多个正文条目,其中每个条目存储您存储在 BillBody 中的信息和 1 个或多个小数 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),这会导致数据库中的不一致(从而导致你的申请)。一个好的数据库确实有约束,因此如果不破坏至少一个约束,就不可能存储不一致的数据库。

我也不明白您为什么要为每张账单单独设置页眉和页脚。模型不是真正的帐单,它存储帐单的信息。如果你想有一个可见的页眉和页脚,那么你应该在你的视图层(模板)而不是模型本身中这样做。

【讨论】:

  • 好吧,base_import 是对基本价格的错误翻译,即不含税的价格。我会更新问题(我需要几分钟)
  • +1 以获得所有解释!我想我现在可以应付了。非常感谢!
猜你喜欢
  • 2012-04-15
  • 2011-01-08
  • 2018-11-19
  • 1970-01-01
  • 2013-07-16
  • 2019-05-10
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多