从标准Django模型中删除字段

3

注意:这个问题是在AbstractUser出现之前提出的,而这可能是您现在想要使用的东西。

基本上,我想从默认的Django用户类中删除默认的电子邮件字段...

class MyUser(User):
    field = models.CharField(max_length = 10)
    a = 'hello'
    def b(self):
        print 'world'

del User.email
del MyUser.email
del Myuser.field

所有这些都会导致AttributeError。但是以以下方式删除方法或属性却可以正常工作:
del MyUser.a
del MyUser.b

我很好奇为什么这个不起作用; 这些模型字段是什么类型的?
我尝试的另一件事是通过在MyUser中创建 email = None 来覆盖电子邮件,但那也没有起作用(而且会有点丑陋)。
谢谢您提前!
顺便说一句,如果你想知道为什么; 这更多是出于好奇而不是对应用程序真正必要的... 但我认为在数据库中不要有未使用的列是很好的。
P.S. 我不想更改Django文件以手动删除用户中的'email'。
编辑:如要执行相同操作,请参阅后续问题 Before syncdb, delete field from standard Django model
2个回答

7

正如您所发现的那样,模型字段实际上并不是类属性,尽管它们看起来像是。

模型是通过元类进行一些非常聪明但复杂的黑客技巧构建的。当执行模型类定义时(第一次导入其models.py),元类会遍历该模型的所有字段定义,并调用每个字段的contribute_to_class方法。这最终将实际的字段放入新类的_meta.fields属性中。因此,模型类本身没有直接的字段属性。

然后,当实际实例化模型实例时,Django会取出该列表,并使用构造函数的参数或字段提供的默认值直接设置新实例的属性。因此,通过实例访问的值没有实际的字段代码支持:它是一个简单的实例属性。

无论如何,所有这些的结果是,要从模型定义中删除字段,只需从Model._meta.fields列表中删除即可。


这很有趣,他们为什么要进行所有这些黑客攻击? - Timmy O'Mahony
2
为了启用漂亮的声明语法。否则,这些字段实际上将成为类属性,因此如果您在一个实例上设置值,它将传递到所有实例 - 这并不是非常有用的。 - Daniel Roseman
1
小的后续问题:如果我在创建类B(A)之前从类A()中删除一个字段,则B仍然会获得已删除的A字段...有任何想法吗?提前致谢! - Mark
我不确定是因为2011年以来的更改还是因为它是一个many2many字段,但作为对其他人的警告,在1.8中这在m2m字段上不起作用。 - Mark

0

由于Model._meta.fields是一个不可变列表,因此您无法直接更改它。

但是,您可以像这样修改local_fields

def remove_field(model_cls, field_name):
    for field in model_cls._meta.local_fields:
        if field.name == field_name:
            model_cls._meta.local_fields.remove(field)

remove_field(User, "email")

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接