Пользовательское поле пользователя Django сталкивается с AbstractBaseUser

58
4

Я создаю проект Django из существующей базы данных. База данных используется другими системами, поэтому я не могу изменить ее схему. Это моя текущая пользовательская модель пользователя:

class Users(AbstractBaseUser):
id_user = models.IntegerField(primary_key=True)
role = models.IntegerField()
username = models.CharField(max_length=50, unique=True)
last_login_date = models.DateTimeField()

AbstractBaseUser нужен столбец с именем last_login, а текущая таблица базы данных имеет столбец last_login_date который используется как AbstractBaseUser.last_login. Теперь мне нужно использовать этот столбец в Users.last_login:

    ...
last_login = models.DateTimeField(_('last login'), default=timezone.now, column_name='last_login_date')
...

Однако Django будет бросать django.core.exceptions.FieldError: Local field 'last_login' in class 'Users' clashes with field of similar name from base class 'AbstractBaseUser' поскольку Django не разрешает переопределять родительские поля.

Как установить поля?

спросил(а) 2014-12-14T12:52:00+03:00 5 лет, 10 месяцев назад
1
Решение
58

Я не могу понять, как это сделать, поэтому я дам вам два довольно неудовлетворительных (но работоспособных) решения :

Вместо того, чтобы наследовать от AbstractBaseUser, используйте Django open-source-ness и скопируйте их код AbstractBaseUser (он находится в <...> lib/python3.4/site-packages/django/contrib/auth/models.py) и используйте прямую реализацию его с column_name='last_login_date' в поле last_login. (здесь также представлен класс AbstractBaseUser (версия 1.7))

Редактируйте <...> lib/python3.4/site-packages/django/contrib/auth/models.py напрямую (в результате чего переносимый код не будет работать с другой установкой django, не взломав его)

ответил(а) 2014-12-14T14:04:00+03:00 5 лет, 10 месяцев назад
80

Хотя есть ответ, который уже удовлетворил вопрос, который я хочу внести другим путем для достижения той же задачи более надежным способом.

Как вы уже знаете, Django AbstractBaseUser является базовым классом, который должен использоваться для замены Django User Class. Такой класс наследуется от моделей. Модел с тем, который фактически создает модель.

Этот класс использует метаклассу модели данных python для изменения процесса создания.


И это именно то, что мы должны делать. Как вы можете прочитать в Python Data Model, вы можете использовать специальный атрибут metaclass, чтобы изменить процесс создания, как вы могли видеть. В вашем случае вы могли бы сделать следующее:

def myoverridenmeta(name, bases, adict):
newClass = type(name, bases, adict)
for field in newClass._meta.fields:
if field.attname == 'last_login':
field.column = 'last_login_date'
field.db_column = 'last_login_date'
return newClass

class Users(AbstractBaseUser):
id_user = models.IntegerField(primary_key=True)
role = models.IntegerField()
username = models.CharField(max_length=50, unique=True)

__metaclass__ = myoverridenmeta

ответил(а) 2015-11-07T00:35:00+03:00 4 года, 11 месяцев назад
Ваш ответ
Введите минимум 50 символов
Чтобы , пожалуйста,
Выберите тему жалобы:

Другая проблема