Удалить поле из стандартной модели Django

ПРИМЕЧАНИЕ: этот вопрос задавался до 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

Поэтому мне любопытно, почему это не работает; что это за поля модели?

Еще одна вещь, которую я пробовал, - перезаписать электронную почту, создав электронную почту = None в MyUser, но это тоже не сработало (и было бы немного более уродливым).

Заранее спасибо!

P.S. Если вам интересно, почему; это больше для любопытства, чем то, что это действительно необходимо для приложения ... Но я думаю, что хорошо не иметь неиспользуемых столбцов в базе данных. P.P.S. Я не хочу изменять файлы Django, чтобы вручную удалить «электронную почту» от пользователя.

EDIT: Дополнительный вопрос здесь (для тех, кто хочет сделать то же самое) Перед syncdb удалить поле из стандартной модели Django


person Mark    schedule 23.11.2011    source источник


Ответы (2)


Как вы уже поняли, поля модели на самом деле не являются атрибутами класса, хотя и кажутся таковыми.

Модели создаются путем очень умного, но сложного обхода метаклассов. Когда выполняется определение класса модели (при первом импорте его models.py), метакласс проходит через все определения полей для этой модели и вызывает метод contribute_to_class для каждого из них. Это приводит к тому, что фактические поля помещаются в свойство _meta.fields нового класса. Таким образом, сам класс модели не имеет полей в качестве прямых свойств.

Затем, когда экземпляр модели фактически создается, Django берет этот список и напрямую устанавливает атрибуты нового экземпляра, используя либо аргументы конструктора, либо значения по умолчанию, предоставленные полями. Таким образом, значение, доступ к которому осуществляется через экземпляр, не имеет фактического кода поля: это простой атрибут экземпляра.

В любом случае, результатом всего этого является то, что для удаления поля из определения модели вам просто нужно удалить его из списка Model._meta.fields.

person Daniel Roseman    schedule 23.11.2011
comment
Вот интересно, а зачем им весь этот взлом? - person Timmy O'Mahony; 24.11.2011
comment
Чтобы включить хороший декларативный синтаксис. В противном случае поля действительно были бы атрибутами класса, поэтому, если вы установите значение для одного экземпляра, оно будет перенесено на все из них - не очень полезно. - person Daniel Roseman; 24.11.2011
comment
Небольшой дополнительный вопрос: если я удалю поле из класса A() перед созданием класса B(A), B все равно получит удаленные поля A... Есть идеи, почему? Заранее спасибо! - person Mark; 11.12.2011
comment
Я не уверен, связано ли это с изменениями с 2011 года или потому, что это поле many2many, но в качестве предупреждения для других, это не работает в 1.8 для полей m2m. - person Mark; 02.09.2015

Поскольку 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")
person user2468842    schedule 02.07.2020