来自继承自models.Model的Class的python子类

时间:2013-02-07 15:55:14

标签: python django class subclass abstract

我在这里有些疑惑......

想象一下,我有3个班级:

class CarSpec(models.Model):
    x = models.IntegerField(default=20)
    y = models.CharField(max_length=100, blank=True)
    z = models.CharField(max_length=50, blank=True)
    chassis = models.ForeignKey(Chassis, unique=True, limit_choices_to={'type':'A'})
    car_brand = models.CharField(max_length=100, blank=True)
    car_model = models.CharField(max_length=50, blank=True)
    number_of_doors = models.IntegerField(default=2)

class MotoSpec(models.Model):
    x = models.IntegerField(default=20)
    y = models.CharField(max_length=100, blank=True)
    z = models.CharField(max_length=50, blank=True)
    chassis = models.ForeignKey(Chassis, unique=True, limit_choices_to={'type':'C'})
    motor_brand = models.CharField(max_length=100, blank=True)
    motor_model = models.CharField(max_length=50, blank=True)
    powered_weels = models.IntegerField(default=1)

class Chassis(models.Model):
    name = models.CharField(max_length=50, blank=False)
    type = models.CharField(max_length=2, choices = GAME_TYPES, default="A")

GAME_TYPES = (('A', 'Car'),('B', 'Truck'),('C', 'Motorcycle'))

我正在使用这3个课程,但在我的应用程序中,我必须始终检查机箱类型,以便为每种情况应用一些业务规则... 我认为这不是正确的做法..所以我计划了这个:

class Spec(models.Model):
    x = models.IntegerField(default=20)
    y = models.CharField(max_length=100, blank=True)
    z = models.CharField(max_length=50, blank=True)

    class Meta:
        abstract = True

并有两个子类:

class CarSpec(Spec):
    chassis = models.ForeignKey(Chassis, unique=True, limit_choices_to={'type':'A'})
    car_brand = models.CharField(max_length=100, blank=True)
    car_model = models.CharField(max_length=50, blank=True)
    number_of_doors = models.IntegerField(default=2)

class MotoSpec(Spec):
    chassis = models.ForeignKey(Chassis, unique=True, limit_choices_to={'type':'C'})
    motor_brand = models.CharField(max_length=100, blank=True)
    motor_model = models.CharField(max_length=50, blank=True)
    powered_weels = models.IntegerField(default=1)

class Chassis(models.Model):
    name = models.CharField(max_length=50, blank=False)
    type = models.CharField(max_length=2, choices = GAME_TYPES, default="A")

GAME_TYPES = (('A', 'Car'),('B', 'Truck'),('C', 'Motorcycle'))

好的,直到这里一切都好,在我的应用程序中没有更改任何与之前的类一起工作,并且所有对象都按照预期很好地保存在数据库中..

但是,我的问题仍然存在..因为我继续实例化CarSpec和MotoSpec而不是Spec ...但是...我想一直使用Spec而不是扩展类...就这样,我能做什么?能够实例化一个Spec对象,将一个Chassis传递给他的 init 方法,以便从该(或其他)方法获得CarSpec或MotoSpec ..

已编辑 - 重要:我已为 MotSpec 添加了 Powered_weels 属性,为 CarSpec添加了 number_of_doors 因为我为两个规格中的每一个都有一些特定的字段

EDITED-YET AGAIN :在我的观点中,我希望每次使用Specs时都避免进行类型验证,并将其留给其中一个类。恢复,我希望能够添加一个新的Spec对象,而不必担心改变我的视图..只有与Specs相关的对象..

# CarSpec
if game_type == "A":
    stuff = CarSpec.restore_state(request, game_session)
# MotoSpec
elif game_type == "C":
    stuff = MotoSpec.restore_state(request, game_session)

已编辑:我在我的Spec类上添加了restore_state,但后来我觉得我发现了一些与循环导入有关的问题..天啊......这让我很伤心。我有一个.NET背景,而python对我来说并不容易:S

4 个答案:

答案 0 :(得分:1)

将chasis,品牌和模型属性添加到Spec类,然后将proxy models用于CarSpec和MotoSpec类,也可以添加car_brand(),motor_brand()等方法......

答案 1 :(得分:0)

虽然您可以删除class Meta类上的Spec(以便拥有Spec个对象)。我不认为您可以覆盖类上的__init__方法来实例化CarSpecMotoSpec个对象。这会给你一个循环的依赖; CarSpec对象的定义依赖于Spec个对象的定义(因为CarSpecSpec的后代)。您无法定义Spec个对象取决于CarSpec个对象(如果CarSpec Spec出现__init__ Spec blank=True, null=True class MotoSpec(Spec): class Meta: proxy = True def __init__(self, *args, **kwargs): super(MotoSpec, self).__init__(*args, **kwargs) self.fields['number_of_doors'].editable = False self.feilds['powered_wheels'].blank = False number_of_doors powered_wheels定义)。

我个人认为你应该使用lysergia25建议的代理模型,并隐藏/要求代理中的其他字段。

更新

假设您将所有字段添加到{{1}}({{1}}只显示在一个子类中的字段上),那么您可以执行类似的操作 -

{{1}}

这应隐藏所有表单(包含管理员)中的字段{{1}},同时需要{{1}}。

答案 2 :(得分:0)

提出:

class Spec(models.Model):
    x = models.IntegerField(default=20)
    y = models.CharField(max_length=100, blank=True)
    z = models.CharField(max_length=50, blank=True)
    brand = models.CharField(max_length=100, blank=True)
    model = models.CharField(max_length=50, blank=True)


class CarSpec(Spec):
    chassis = models.ForeignKey(Chassis, unique=True, limit_choices_to={'type':'A'})
    number_of_doors = models.IntegerField(default=2)
CarSpec._meta.get_field('brand').verbose_name = 'Car Brand'
CarSpec._meta.get_field('model').verbose_name = 'Car Model'


class MotoSpec(Spec):
    chassis = models.ForeignKey(Chassis, unique=True, limit_choices_to={'type':'C'})
    powered_weels = models.IntegerField(default=1)
MotoSpec._meta.get_field('brand').verbose_name = 'Motor Brand'
MotoSpec._meta.get_field('model').verbose_name = 'Motor Model'


class Chassis(models.Model):
    GAME_TYPES = (
        ('A', 'Car'),
        ('B', 'Truck'),
        ('C', 'Motorcycle')
    )

    name = models.CharField(max_length=50, blank=False)
    type = models.CharField(max_length=2, choices = GAME_TYPES, default="A")

或者你可以在forms.py中加上详细的名称

class CarSpec(Spec):
    chassis = models.ForeignKey(Chassis, unique=True, limit_choices_to={'type':'A'})
    number_of_doors = models.IntegerField(default=2)


class MotoSpec(Spec):
    chassis = models.ForeignKey(Chassis, unique=True, limit_choices_to={'type':'C'})
    powered_weels = models.IntegerField(default=1)

答案 3 :(得分:-1)

您应该使用多重继承,如django documentation

中所述