Python Django自定义用户字段与AbstractBaseUser冲突

Python Django自定义用户字段与AbstractBaseUser冲突,python,django,django-models,django-orm,Python,Django,Django Models,Django Orm,我正在从现有数据库构建一个Django项目。该数据库正在被其他系统使用,因此我无法更改其架构。这是我当前的自定义用户模型: class Users(AbstractBaseUser): id_user = models.IntegerField(primary_key=True) role = models.IntegerField() username = models.CharField(max_length=50, unique=True) last_log

我正在从现有数据库构建一个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_登录中使用该列:

但是,Django会抛出Django.core.exceptions.FieldError:类“Users”中的本地字段“last_login”与基类“AbstractBaseUser”中类似名称的字段冲突,因为Django不允许重写父字段


如何设置字段?

我想不出一个好办法,所以我给你两个不太令人满意但可行的解决方案:

与其从AbstractBaseUser继承,不如利用Django的开源特性,复制他们的AbstractBaseUser代码,它位于lib/python3.4/site-packages/Django/contrib/auth/models.py,并在last\u login字段中使用列_name='last\u login\u date'直接实现它。AbstractBaseUser类也是1.7版

编辑lib/python3.4/site-packages/django/contrib/auth/models.py,直接生成不可移植的代码,如果不对另一个django安装进行黑客攻击,这些代码将无法在另一个django安装上工作


我想不出一个好的方法来做这件事,所以我给你两个不太令人满意但可行的解决方案:

与其从AbstractBaseUser继承,不如利用Django的开源特性,复制他们的AbstractBaseUser代码,它位于lib/python3.4/site-packages/Django/contrib/auth/models.py,并在last\u login字段中使用列_name='last\u login\u date'直接实现它。AbstractBaseUser类也是1.7版

编辑lib/python3.4/site-packages/django/contrib/auth/models.py,直接生成不可移植的代码,如果不对另一个django安装进行黑客攻击,这些代码将无法在另一个django安装上工作


虽然有一个答案已经满足了这个问题,但我想用另一种方法,以更稳健的方式完成同样的任务

正如您已经知道的,Django AbstractBaseUser是应该用来替代Django用户类的基类。这样的类继承自models。Model with是实际创建模型的类

这个类利用python数据模型的元类来改变创建过程

这正是我们应该做的。正如您所看到的,您可以使用元类特殊属性来改变创建过程。在您的情况下,您可以执行以下操作:

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

虽然有一个答案已经满足了这个问题,但我想用另一种方法,以更稳健的方式完成同样的任务

正如您已经知道的,Django AbstractBaseUser是应该用来替代Django用户类的基类。这样的类继承自models。Model with是实际创建模型的类

这个类利用python数据模型的元类来改变创建过程

这正是我们应该做的。正如您所看到的,您可以使用元类特殊属性来改变创建过程。在您的情况下,您可以执行以下操作:

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

如果没有其他人能找到更好的解决方案,那么您可能希望在Django项目中提交一份bug报告,看看他们是否可以允许在AbstractBaseUser类中重写列名,以符合遗留数据库的要求。谢谢。ATM我在等待另一个答案时使用了您的第一个建议。如果没有其他人能找到更好的解决方案,您可能希望提交Django项目的错误报告,看看他们是否可以允许在AbstractBaseUser类中重写列名,以符合遗留数据库的要求。谢谢。在等待另一个答案时,我使用你的第一个建议。