Django Model关系重构有帮助吗?

时间:2010-08-18 20:18:37

标签: django django-models django-admin

我有点django / db brainfart。

在单词中,我试图想出一种更好的方法来表示我的项目中的Address对象。我有5或6个不同的模型,它们与地址(账单/发货/等)有一个或多个关联,我需要允许创建/修改/删除这些地址。我的第一个想法是使用管理员,因为它看起来很自然。

但是,我似乎无法弄清楚如何告诉管理员将可见的地址集限制为相关的特定模型(帐户/合作伙伴/发票)。我发现了一个非常讨厌,不可行和令人难以置信的可怕方法,我将在下面展示。

如何有效地执行此操作(最好是在管理员中)?我愿意接受m2m关系,这对我来说更自然,并使用自定义视图/表单,但我在我走这条路之前,我想看看我是否错过了一些Admin技巧。如果我走这条路线,我想我将需要使用GenericRelation,这样我就不会有大量的查找表(每个不同的实体都有一个)。

编辑:相同的地址可用于不同的模型,对于特定型号的不同实例,如果地址被重复使用,我们必须跟踪谁正在使用什么保持模型和/或实例之间的独立性。或者换句话说,在m2m关系中,我们可以跟踪谁正在使用中间表的内容。如果我们不使用查找表,那么我们需要始终复制Address实例,以便两个对象都有自己的副本。 (如果有编辑,我们需要确保我们不会改变其他任何人的预先存在的关系。换句话说,编辑实际上是在m2m案例中创建和重新分配。)

这是一个非常适合作为空项目的示例,它可以显示我希望在添加/编辑/删除期间如何隔离地址,但它也显示了解决方案的可怕程度。

models.py

from django.db import models

class Account(models.Model):
    name = models.CharField(max_length=200,blank=True)
    #...
    def __unicode__(self):
        return u"%s - (%s)" %(self.name, self.address_set.all())

class Partner(models.Model):
    name = models.CharField(max_length=200,blank=True) 
    discount = models.DecimalField(max_digits= 3, decimal_places=1, default=0)
    #...
    def __unicode__(self):
        return u"%s - (%s)" %(self.name, self.address_set.all())

class Invoice(models.Model):
    invoice_number = models.IntegerField(default=1)
    #...
    def __unicode__(self):
        return u"%s - (%s)" %(self.invoice_number, self.address_set.all())

class Address(models.Model):
    street = models.CharField(max_length=200,blank=True)
    zip = models.CharField(max_length=10, verbose_name='Zip Code')
    account = models.ForeignKey(Account, blank=True, null=True)
    partner = models.ForeignKey(Partner, blank=True, null=True)
    invoice = models.ForeignKey(Invoice, blank=True, null=True)
    type = models.CharField(max_length=25, choices=(('B','Billing'),('S','Shipping')))

    class Meta:
        unique_together = (('type', 'account' ),
                           ('type', 'partner' ),
                           ('type', 'invoice' ),)

    def __unicode__(self):
        return "(%s) - %s %s" %(self.get_type_display(), self.street, self.zip)

admin.py

from django.contrib import admin
from relationships.rels.models import Partner, Account, Address, Invoice

class AcctAddrInline(admin.TabularInline):
    model = Address
    extra = 1
    max_num =3
    exclude = ('partner', 'invoice')

class PartAddrInline(admin.TabularInline):
    model = Address
    extra = 1
    max_num =3
    exclude = ('account', 'invoice')

class InvAddrInline(admin.TabularInline):
    model = Address
    extra = 1
    max_num =2
    exclude = ('account', 'partner')        

class AccountAdmin(admin.ModelAdmin):
    inlines = [AcctAddrInline,]

class PartnerAdmin(admin.ModelAdmin):
    inlines = [PartAddrInline,]

class InvoiceAdmin(admin.ModelAdmin):
    inlines = [InvAddrInline,]

admin.site.register(Invoice, InvoiceAdmin)         
admin.site.register(Partner, PartnerAdmin)
admin.site.register(Account, AccountAdmin)
admin.site.register(Address)

2 个答案:

答案 0 :(得分:1)

  

编辑:相同的地址可能会用于不同的模型,对于特定型号的不同实例,如果地址被重复使用,我们必须跟踪谁正在使用什么保持模型和/或实例之间的独立性

看起来您希望使用COW模式来表示地址,但我认为它并不符合数据库完整性的整体想法。

如果您只想将帐户地址与发票地址分开,我建议您使用Multi-table model inheritance。这样,您将拥有多组地址,同时能够一次浏览所有地址。

这是一个例子。

models.py

from django.db import models

class Account(models.Model):
    name = models.CharField(max_length=200, blank=True)

    def __unicode__(self):
        return u"%s - (%s)" % (self.name, self.address_set.all())

class Partner(models.Model):
    name = models.CharField(max_length=200, blank=True) 
    discount = models.DecimalField(max_digits= 3, decimal_places=1, default=0)

    def __unicode__(self):
        return u"%s - (%s)" % (self.name, self.address_set.all())

class Invoice(models.Model):
    invoice_number = models.IntegerField(default=1)

    def __unicode__(self):
        return u"%s - (%s)" % (self.invoice_number, self.address_set.all())

class Address(models.Model):
    street = models.CharField(max_length=200, blank=True)
    zip = models.CharField(max_length=10, verbose_name='Zip Code')

    def __unicode__(self):
        return "%s %s" % (self.street, self.zip)

class AccountAddress(Address):
    account = models.ForeignKey(Account, related_name='address_set')

class InvoiceAddress(Address):
    invoice = models.ForeignKey(Invoice, related_name='address_set')

class PartnerAddress(Address):
    partner = models.ForeignKey(Partner, related_name='address_set')

admin.py

from django.contrib import admin
# Wildcard import used for brevity
from relationships.rels.models *

class AccountAddressInline(admin.TabularInline):
    model = AccountAddress
    extra = 1
    max_num = 3

class PartnerAddressInline(admin.TabularInline):
    model = PartnerAddress
    extra = 1
    max_num = 3

class InvoiceAddressInline(admin.TabularInline):
    model = InvoiceAddress
    extra = 1
    max_num = 3

class AccountAdmin(admin.ModelAdmin):
    inlines = [AccountAddressInline,]

class PartnerAdmin(admin.ModelAdmin):
    inlines = [PartnerAddressInline,]

class InvoiceAdmin(admin.ModelAdmin):
    inlines = [InvoiceAddressInline,]

admin.site.register(Account, AccountAdmin)
admin.site.register(Partner, PartnerAdmin)
admin.site.register(Invoice, InvoiceAdmin)

admin.site.register(AccountAddress)
admin.site.register(InvoiceAddress)
admin.site.register(PartnerAddress)

# Uncomment if you want to browse all addresses available at once
# admin.site.register(PartnerAddress)

注意related_name='address_set'黑客攻击。我不知道为什么,但它是使用继承模型中的外键时内联编辑的唯一方法。似乎Django中的一个错误类似于(但反向用例)#11120#11121

答案 1 :(得分:0)

我个人会将外键放在帐户,合作伙伴和发票上的地址模型中,而不是让地址知道它的地址是什么。那,MAY,可以解决你的问题。