简体   繁体   English

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

[英]python SubClasses from a Class that inherits from models.Model

I have some doubts here... 我在这里有一些疑问...

Imagine that I have 3 classes: 想象一下,我有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'))

I was working with this 3 classes, but in my apps I would have to check the chassis type all the time in order to apply some business rules to each situation... I thought this would not be the correct approach.. so I planned this: 我正在使用这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

and have two Subclasses: 并具有两个子类:

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'))

Ok, until here all ok, changed nothing in my apps that worked with previous classes and all objects were being persisted in the database quite nicely as expected.. 好的,直到一切正常,在与以前的类一起使用的我的应用程序中没有进行任何更改,并且所有对象都按预期很好地保存在数据库中。

But, my problem remains.. Because I continue to instantiate CarSpec and MotoSpec and not Spec... but... I want to use Spec all the time instead of the extending classes... being so, what can I do to be able to instantiate a Spec object passing a Chassis to his init method in order to get a CarSpec or a MotoSpec from that (or other) method.. 但是,我的问题仍然存在。.因为我继续实例化CarSpec和MotoSpec而不是Spec ...但是...我想一直使用Spec而不是扩展类...既然如此,我该怎么做?能够实例化将Chassis传递到其init方法的Spec对象,以便从该(或其他)方法获取CarSpec或MotoSpec。

EDITED-IMPORTANT : I've added powered_weels attribute for MotoSpec and number_of_doors for CarSpec because I have some specific fields for each of the two Specs EDITED-IMPORTANT :我为MotoSpec添加了power_weels属性,为CarSpec添加了number_of_doors ,因为我为两个Spec中的每一个都有一些特定的字段

EDITED-YET AGAIN : In my views I wanted to avoid doing a type verification every time I mess around with Specs and leave that to one of the classes involved. 再次编辑 :在我看来,我想避免每次我弄乱Specs并将其留给其中一个涉及的类时进行类型验证。 Resuming, I want to be able to add a new Spec Object and not have to worry about changing my views.. only the objects related to Specs.. 继续,我希望能够添加一个新的Spec对象,而不必担心更改我的视图。

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

EDITED : I've added a restore_state on my Spec class, but then I think I find some problems related to circular imports.. OMG.. this is killing me. 编辑 :我在我的Spec类上添加了restore_state,但是随后我认为我发现了一些与循环导入有关的问题。OMG ..这使我丧命。 I have a .NET background, and python is not getting easy on me in this kinds of stuff :S 我有.NET背景,而python在这些方面对我来说并不容易:

将底架,品牌和模型属性添加到Spec类,然后对CarSpec和MotoSpec类使用代理模型 ,也许添加诸如car_brand(),motor_brand()等方法。

Although you could remove the class Meta on the Spec class (so that you have Spec objects). 尽管您可以删除Spec类上的class Meta类(以便拥有Spec对象)。 I don't think you can override the __init__ method on the class to instantiate CarSpec or MotoSpec objects. 我认为您无法重写类上的__init__方法以实例化CarSpecMotoSpec对象。 That would give you a circular dependancy; 那会给你循环依赖; The definition of CarSpec objects relies on the definition of Spec objects (because CarSpec is a descendant of Spec ). CarSpec对象的定义依赖于Spec对象的定义(因为CarSpecSpec的后代)。 You can't make the definition of Spec objects dependant on CarSpec objects (which it would be if CarSpec appeared in Spec 's __init__ definition). 您不能使Spec对象的定义依赖于CarSpec对象(如果CarSpec出现在Spec__init__定义中,则将是这样)。

Personally I think you should use proxy models as suggested by lysergia25, and hide/require the additional fields in the proxy. 我个人认为您应该使用lysergia25建议的代理模型,并隐藏/要求代理中的其他字段。

UPDATE 更新

Assuming you add all fields to Spec (with blank=True, null=True on the fields that only appear in one subclass), then you can do something like - 假设您将所有字段都添加到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

This should hide the field number_of_doors from all forms (inc admin), whilst requiring powered_wheels . 这应该从所有表格(inc admin)中隐藏number_of_doors字段,同时需要powered_wheels

Propose: 提出:

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")

OR you can put verbose name in forms.py 或者,您可以在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)

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM