【问题标题】:Django custom user field clashes with AbstractBaseUserDjango 自定义用户字段与 AbstractBaseUser 冲突
【发布时间】:2015-02-12 14:38:21
【问题描述】:

我正在从现有数据库构建一个 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 不允许覆盖父字段。

如何设置字段?

【问题讨论】:

    标签: python django django-models django-orm


    【解决方案1】:

    我想不出一个好的方法来做到这一点,所以我会给你两个相当不满意(但可行)的 解决方案 hack:

    1. 与其继承 AbstractBaseUser,不如利用 Django 的开源性并复制他们的 AbstractBaseUser 代码(它位于 <...>lib/python3.4/site-packages/django/contrib/auth /models.py) 并在 last_login 字段中使用 column_name='last_login_date' 的直接实现。 (AbstractBaseUser 类也是here(1.7 版))

    2. 直接编辑 <...>lib/python3.4/site-packages/django/contrib/auth/models.py (导致不可移植的代码在没有破解的情况下无法在另一个 django 安装上运行也)

    【讨论】:

    • 如果没有人能找到更好的解决方案,您可能需要向 Django 项目提交错误报告,以查看他们是否可以允许在其 AbstractBaseUser 类中覆盖列名以符合要求使用遗留数据库。
    • 谢谢。 ATM 我在等待另一个答案时使用您的第一个建议。
    【解决方案2】:

    虽然有一个答案已经满足了我想以另一种方式以更强大的方式完成相同任务的问题。

    如您所知,Django AbstractBaseUser 是应该用来替代 Django User Class 的基类。这样的类继承自models。Model 是实际创建模型的类。

    这个类利用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
    

    【讨论】:

      猜你喜欢
      • 2013-12-14
      • 2018-05-13
      • 2014-06-13
      • 1970-01-01
      • 2013-02-23
      • 2012-08-08
      • 2013-06-08
      • 2011-08-07
      • 2022-10-24
      相关资源
      最近更新 更多