Skip to main content
 首页 » 编程设计

python之解决 Django 模型不同验证的设计模式

2025年05月04日11linjiqin

我正尝试在 Django 1.6.4 中为我的客户编写应用程序

我对 Django 有丰富的经验,但这个案例对我来说很难解决。

我正在使用 Substituting a custom user model功能和我的 Member 类看起来像(这只是简单的代码片段):

class Member(AbstractBaseUser): 
    ... 
    date_of_birth = models.DateField() 
    height = models.FloatField() 
    ... 
    REQUIRED_FIELDS = ['date_of_birth', 'height'] 

My Member 可以定义多个不同国家的地址。每个国家都有自己特定的地址验证或额外的字段,所以我定义了主要的抽象地址和一些子地址:

class COUNTRIES(object): 
    POLAND = 'pl' 
    GERMANY = 'de' 
    @classmethod 
    def to_choices(cls): 
        return ((cls.POLAND, 'Poland'), (cls.GERMANY, 'Germany')) 
 
class BaseAddress(models.Model): 
    class Meta: 
        abstract = True 
    member = models.ForeignKet(settings.AUTH_USER_MODEL, related_name='+') 
    country = models.CharField(max_length=2, choices=COUNTRIES.to_choices) 
 
class AddressPL(BaseAddress): 
    street = models.CharField(max_length=80) 
    city = models.CharField(max_length=20) 
    postal_code = models.CharField(max_length=6, validators=[RegexValidator('^\d{2}-\d{3}$'),]) 
    def save(self, *args, **kwargs): 
        self.country = COUNTRIES.POLAND 
        super(AddressPL, self).save(*args, **kwargs) 
 
class AddressDE(BaseAddress): 
    street = models.CharField(max_length=80) 
    city = models.CharField(max_length=20) 
    postal_code = models.CharField(max_length=6, validators=[RegexValidator('^\d{5}$'),]) 
    def save(self, *args, **kwargs): 
        self.country = COUNTRIES.GERMANY 
        super(AddressPL, self).save(*args, **kwargs) 

如您所见,唯一的变化是 validators 部分的 postal_code 字段。唯一的问题是,在 Member 中,我需要添加如下内容:

class Member(AbstractBaseUser): 
    ... 
    @property 
    def addresses(self): 
        from itertools import chain 
        addresses_pl = AddressPL.objects.filter(member=self) 
        addresses_de = AddressDE.objects.filter(member=self) 
        return list(chain(addresses_pl, addresses_de)) 

基于 431628-how to combine 2 or more querysets

我的问题是。你有什么其他的想法来设计这个吗? 我需要提供简单、可扩展的解决方案。 也许有使用代理的想法?

请您参考如下方法:

我认为concrete inheritance可能是您的问题的候选人:

class Member(AbstractBaseUser): 
    ... 
    date_of_birth = models.DateField() 
    height = models.FloatField() 
    ... 
    REQUIRED_FIELDS = ['date_of_birth', 'height'] 
 
class BaseAddress(models.Model): 
    # no abstract = True 
    member = models.ForeignKey(settings.AUTH_USER_MODEL, related_name='adresses') 
    country = models.CharField(max_length=2, choices=COUNTRIES.to_choices) 
 
class AddressPL(BaseAddress): 
    # your custom logic here 
 
class AddressDE(BaseAddress): 
    # your custom logic here 

然后,如果你想添加一些数据:

m = Member(yourargs) 
m.save() 
 
adress1 = AdressPL(yourargs) 
adress1.member = m 
adress1.save() 
 
adress2 = AdressPL(yourargs) 
adress2.member = m 
adress2.save() 
 
m = Member.objects.get(pk=m.pk) 
 
m.adresses.all() # will output a list of BaseAdresse instances 

这样,添加一种新的地址只是子类化 BaseAdress 的问题。无需更改您的用户模型。

具体继承的缺点是它会在继承模型的数据库查询中添加一个连接。

另外,如果你走这条路,看看django-polymorphic ,它是一个 Django 应用程序,提供了处理具体继承的有用方法。