Joh*_*y 5 87 python django django-inheritance
我希望这样做:
class Place(models.Model):
name = models.CharField(max_length=20)
rating = models.DecimalField()
class LongNamedRestaurant(Place): # Subclassing `Place`.
name = models.CharField(max_length=255) # Notice, I'm overriding `Place.name` to give it a longer length.
food_type = models.CharField(max_length=25)
Run Code Online (Sandbox Code Playgroud)
这是我想要使用的版本(虽然我对任何建议持开放态度):http: //docs.djangoproject.com/en/dev/topics/db/models/#id7
这是Django支持吗?如果没有,有没有办法取得类似的结果?
小智 58
不,它不是:
字段名称"隐藏"是不允许的
在普通的Python类继承中,子类允许覆盖父类的任何属性.在Django中,对于作为
Field实例的属性(至少目前不是),不允许这样做.如果基类具有调用的字段author,则无法创建author在从该基类继承的任何类中调用的另一个模型字段.
qma*_*ats 56
更新的答案:正如人们在评论中指出的那样,原始答案没有正确回答问题.实际上,只有LongNamedRestaurant模型是在数据库中创建的,Place而不是.
解决方案是创建表示"地点"的抽象模型,例如.AbstractPlace,并从中继承:
class AbstractPlace(models.Model):
name = models.CharField(max_length=20)
rating = models.DecimalField()
class Meta:
abstract = True
class Place(AbstractPlace):
pass
class LongNamedRestaurant(AbstractPlace):
name = models.CharField(max_length=255)
food_type = models.CharField(max_length=25)
Run Code Online (Sandbox Code Playgroud)
还请阅读@Mark 答案,他给出了一个很好的解释,为什么你不能改变从非抽象类继承的属性.
(注意,这只能在Django 1.10之后:在Django 1.10之前,修改从抽象类继承的属性是不可能的.)
原始答案
从Django 1.10开始,它是可能的!你只需要做你要求的:
Run Code Online (Sandbox Code Playgroud)class Place(models.Model): name = models.CharField(max_length=20) rating = models.DecimalField() class Meta: abstract = True class LongNamedRestaurant(Place): # Subclassing `Place`. name = models.CharField(max_length=255) # Notice, I'm overriding `Place.name` to give it a longer length. food_type = models.CharField(max_length=25)
Mar*_*ark 27
除非抽象,否则这是不可能的,这就是为什么:LongNamedRestaurant也是一个Place,不仅是一个类,而且还在数据库中.地方表包含每个纯净Place和每个的条目LongNamedRestaurant.LongNamedRestaurant只需创建一个额外的表,其中food_type包含对place表的引用.
如果你这样做Place.objects.all(),你也会获得每个地方LongNamedRestaurant,而且它将是Place(没有food_type)的实例.因此Place.name,LongNamedRestaurant.name共享相同的数据库列,因此必须属于同一类型.
我认为这对于普通模型来说是有意义的:每个餐馆都是一个地方,至少应该拥有所有的地方.也许这种一致性也是为什么1.10之前的抽象模型不可能,尽管它不会给那里的数据库问题.正如@lampslave所言,它在1.10中成为可能.我个人建议小心:如果Sub.x覆盖了Super.x,请确保Sub.x是Super.x的子类,否则Sub不能代替Super使用.
解决方法:AUTH_USER_MODEL如果您只需要更改电子邮件字段,则可以创建自定义用户模型(),其中涉及相当多的代码重复.或者,您可以保留电子邮件,并确保所有表格都需要.如果其他应用程序使用它,则不保证数据库完整性,并且不能以相反的方式工作(如果您不想要用户名).
blu*_*yed 19
class BaseMessage(models.Model):
is_public = models.BooleanField(default=False)
# some more fields...
class Meta:
abstract = True
class Message(BaseMessage):
# some fields...
Message._meta.get_field('is_public').default = True
Run Code Online (Sandbox Code Playgroud)
将您的代码粘贴到一个全新的应用程序中,将应用程序添加到INSTALLED_APPS并运行syncdb:
django.core.exceptions.FieldError: Local field 'name' in class 'LongNamedRestaurant' clashes with field of similar name from base class 'Place'
Run Code Online (Sandbox Code Playgroud)
看起来像Django不支持.
也许你可以处理contrib_to_class:
class LongNamedRestaurant(Place):
food_type = models.CharField(max_length=25)
def __init__(self, *args, **kwargs):
super(LongNamedRestaurant, self).__init__(*args, **kwargs)
name = models.CharField(max_length=255)
name.contribute_to_class(self, 'name')
Run Code Online (Sandbox Code Playgroud)
Syncdb工作正常.我没试过这个例子,在我的情况下,我只是覆盖一个约束参数,所以......等等看!
这个超酷的代码片段允许您"覆盖"抽象父类中的字段.
def AbstractClassWithoutFieldsNamed(cls, *excl):
"""
Removes unwanted fields from abstract base classes.
Usage::
>>> from oscar.apps.address.abstract_models import AbstractBillingAddress
>>> from koe.meta import AbstractClassWithoutFieldsNamed as without
>>> class BillingAddress(without(AbstractBillingAddress, 'phone_number')):
... pass
"""
if cls._meta.abstract:
remove_fields = [f for f in cls._meta.local_fields if f.name in excl]
for f in remove_fields:
cls._meta.local_fields.remove(f)
return cls
else:
raise Exception("Not an abstract model")
Run Code Online (Sandbox Code Playgroud)
从抽象父类中删除字段后,您可以根据需要自由重新定义它们.
这不是我自己的工作.来自此处的原始代码:https://gist.github.com/specialunderwear/9d917ddacf3547b646ba
我的解决方案和 next 一样简单monkey patching,请注意我如何更改模型中max_length的name字段属性LongNamedRestaurant:
class Place(models.Model):
name = models.CharField(max_length=20)
class LongNamedRestaurant(Place):
food_type = models.CharField(max_length=25)
Place._meta.get_field('name').max_length = 255
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
48305 次 |
| 最近记录: |