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

发布于 2024-09-07 20:02:52 字数 2247 浏览 3 评论 0原文

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

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 bill 时,我需要将 BillHeader 显示为普通字段集,但 BillBody 和 < code>BillFooter 需要是 TabularInline

如果我将它们作为 TabularInline 放入 admin.py 中,则会出现错误,指出它们需要相关模型的 ForeignKey 。当然,我不能放置那些外键,因为它们是在底部声明的。我想你们称之为“向后外键”。

我的问题是:如何才能在管理中显示 TabularInlines 而不会造成混乱?我可以在没有抽象基类的情况下做到这一点,但另一个问题来了,它在 TabularInline 中显示另一个外键(如果您在 EmmitedBills 上,它会在 TabularInline 中显示到 ReceivedBills 的 FK,反之亦然),我无法排除他们。

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


我会更好地解释:

我有两种类型的账单,已发送已接收,并且它们都显示在管理主页上(这就是为什么我没有使用>BooleanField 来标记它们)。两种类型都具有相同的字段,但帐单号除外,该帐单号在已发送中将自动生成。每份帐单包含 1 个包含编号、客户和日期的标题、1 个或多个包含说明、金额、价格等的正文内嵌条目以及 1 个内嵌页脚,显示不含税、适用税等的总价格。


更新

我已经完成了所有操作,但有一个问题,在我的新模型中 BillBody 有两个 FK(EmmitedBill 和 ReceivedBill),并且它们显示在 TabularInline 中。我怎样才能隐藏它们?field.exclude()给出一个错误。

Let's see if I can explain myself, I have this models:

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

When the user adds an Emmited or Received bill I need to show BillHeader as a normal fieldset, but BillBody and BillFooter need to be TabularInline.

If I put those as TabularInline in admin.py, an error rises saying that they need a ForeignKey to the related models. Of course, I can't put those foreign keys, because they are declared at the bottom. I think you guys call this "backwards foreign keys".

My question is this: how can I do this to show TabularInlines in the admin without making a mess?. I can do it without abstract base classes, but then another problem comes, it shows the other ForeignKey in the TabularInline (if you are on EmmitedBills it shows the FK to ReceivedBills in the TabularInline and viceversa) and I couldn't been able to exclude them.

Sorry if this is a stupid question, but I'm not a programmer (it's just a hobby) and I'm really making myself a mess with data models.


I'll explain better:

I have two types of bills, Emitted and Received and both of them show on the admin home (that's why I didn't use a BooleanField to mark them). Both types have the same fields except one, the bill number, which in Emmitted will be autogenerated. Each bill consists on 1 header with number, client and date, 1 or more body inline entries with a description, amount, price, etc. and 1 inline footer, showing the total price without taxes, applied taxes, etc.


Update

I have done everything, but I have a problem, in my new model BillBody has two FK's (EmmitedBill and ReceivedBill) and they show up in the TabularInline. How can I hide them?field.exclude() gives an error.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

回心转意 2024-09-14 20:02:52

我不完全理解您的问题,但

ForeignKey('ModelName')

您可以使用代替

ForeignKey(ModelName)

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

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

但是,我认为您的数据模型是错误的。看来您确实想存储账单。账单有两种类型:发出收到 账单。 发出收到账单确实具有相同的字段。此外,您希望每个账单都包含一个包含编号、客户和日期的标题、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 的用法,所以我忽略了这一点。

价格计算

如果您的价格应始终等于金额*unitaryprice - 折扣金额*(unitaryprice-discount) 那么你不应该把它放在一个字段中,而是在需要时计算它,无论是在 Python 中还是在数据库中。如果您想在 Python 中执行此操作,可以使用类似于 get_total_price 的方法。如果你想在查询数据库时计算它们,那么在 Django 中使用它会有点困难。

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

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

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

更新

如果您为发出和收到的账单添加两个子类并使用 多表继承则可以使用从BillEntryBill的一个外键。

class EmittedBill(Bill):
    pass

class ReceivedBill(Bill):
    pass

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

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

I don't fully understand your question, but you can use

ForeignKey('ModelName')

instead of

ForeignKey(ModelName)

if the ModelName model isn't already declared. Maybe this solves your problem.

Inline admins (like TabularInline) are only used when you have a one-to-many relation, which is created by a ForeignKey on the many side. If you don't have such a foreign key, then you cannot use a inline admin. Inheritance is definitely different from a ForeignKey.

However, I think your data model is wrong. It seems like you do want to store bills. There are two types of bills, emitted and received bills. Both emitted and received bills do have the same fields. Furthermore, you want that each bill consists of a header with number, client and date, 1 or more body entries, where each entry stores the information you store in BillBody and 1 or more decimals base_number.


A probably better data model for you

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)

I have left out the __unicode__ methods.

Now you have a foreign key from BillEntry to Bill and you can use a tabular inline. I didn't understand your usage of base_import so I left this out.

Price computation

If your price should always equal something like amount*unitaryprice - discount or amount*(unitaryprice-discount) then you shouldn't put this in a field but either compute it when it is needed, either in Python or in the database. If you want to do this in Python you can use a method similar to get_total_price. If you want to compute them when querying the database then it is a little bit more difficult to get it working with Django.

In the last case, you can have a look at SQL views, but I think this is a little bit too difficult for a beginner. Another option is to use a custom SQL expression:

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

This will compute the price for all entries during selection.

Update

If you add two subclasses for emitted and received bills and use multi table inheritance then you can use one foreign key from BillEntry to Bill.

class EmittedBill(Bill):
    pass

class ReceivedBill(Bill):
    pass

You probably also have to think about the database model generated by Django. Usually, you only want to store elementary data in the database, and not computed data (like you want to do in your footer). So, if prices are computed using some formula and using the unitaryprice, amount etc. you shouldn't store the result of this formula but recompute it when necessary (and eventually cache to avoid re-computations). If you don't do this, chances are that you at some moment update something (for example the amount) and forget to update the computed values (the price) which leads to inconsistencies in your database (and thus bugs in your application). A good database does have constraints so that it is impossible to store inconsistent database without breaking at least one constraint.

I also don't see why you want a separate header and footer per bill. A model isn't the real bill, it stores the information for a bill. If you want to have a visible header and footer, then you should do this in your view layer (the template) and not in the model itself.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文