2

我这里有一些疑问...

想象一下,我有 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。

EDITED-IMPORTANT:我为 MotoSpec 添加了powered_weels属性,为CarSpec添加number_of_doors属性,因为我为这两个规范中的每一个都有一些特定的字段

再次编辑:在我看来,我想避免每次我弄乱 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,但后来我想我发现了一些与循环导入相关的问题.. OMG .. 这让我很生气。我有 .NET 背景,python 在这些方面对我来说并不容易:S

4

4 回答 4

1

为 Spec 类添加底盘、品牌和型号属性,然后为 CarSpec 和 MotoSpec 类使用代理模型,可能添加 car_brand()、motor_brand() 等方法...

于 2013-02-07T16:59:29.080 回答
0

尽管您可以删除class Meta该类Spec(以便您拥有Spec对象)。我不认为你可以重写__init__类上的方法来实例化CarSpecMotoSpec对象。这会给你一个循环依赖;对象的定义CarSpec依赖于对象的定义Spec(因为CarSpec是 的后代Spec)。您不能使对象的定义Spec依赖于CarSpec对象(如果CarSpec出现在Spec__init__定义中就会如此)。

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

更新

假设您将所有字段添加到Specblank=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这应该从所有表单(inc admin)中隐藏该字段,同时需要powered_wheels.

于 2013-02-07T16:59:51.160 回答
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)
于 2013-02-10T13:22:29.823 回答
-1

您应该使用多表继承,如django 文档中所述

于 2013-02-07T15:59:39.613 回答