【问题标题】:Models and inheritance模型和继承
【发布时间】:2014-10-04 14:24:31
【问题描述】:

今天偶然发现了一件很奇怪的事情。

我创建了一个可以显示问题的最小项目/应用程序。我就是这样做的:

virtualenv venv
. ./ven/bin/activate
pip install django==1.6 # That's the one we're using
django-admin.py startproject bla
cd bla
chmod +x manage.py
./manage.py startapp bla_app

bla/settings.py:

INSTALLED_APPS = (
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',

    'bla_app',
)

AUTH_USER_MODEL = 'bla_app.MyUser'

bla_app/models.py:

from django.db import models

from django.contrib.auth.models import AbstractUser

# Create your models here.


class MyUser(AbstractUser):
    super_name = models.CharField(max_length=254, unique=True)

然后,我运行syncdb 命令:

./manage.py syncdb

它已按预期创建。

现在是棘手的部分。如果我将 models.py 替换为名为 models 的文件夹,并创建一个 __init__.py 文件,其中包含:

from my_user import MyUser

(之前的models.py 被移动到models/my_user.py

然后我得到这些错误:

$ ./manage.py syncdb
CommandError: One or more models did not validate:
admin.logentry: 'user' has a relation with model bla_app.MyUser, which has either not been installed or is abstract.
auth.user: Model has been swapped out for 'bla_app.MyUser' which has not been installed or is abstract.

你知道这里发生了什么吗?

我找到了that,但我不确定它们是否相关

【问题讨论】:

  • 不支持模型到子模块的分区(仅适用于模型)因为 django 的工作方式,这将在 1.7 中改变:code.djangoproject.com/ticket/4470 最后检查如何执行的“技巧”那个。

标签: python django django-models python-import


【解决方案1】:

Django 期望您的模型类在models.py 本身中定义,而不是在子模块中。它将尝试创建一个 models.MyUser 的实例,在您的情况下,即使您在 my_user.py 中定义了它,但它在 Django 的世界中并不存在

如果您希望在单独的 Python 文件中定义每个模型,则需要创建一个 models.py 文件来手动导入它们。如果您开始在该应用中创建大量模型,这可能很难维护。

app/
    __init__.py
    models.py
    _models/
        __init__.py
        my_user.py

models.py

from ._models.my_user import MyUser

【讨论】:

  • 我很确定它会起作用,但我仍然更喜欢@renan-ivo 建议的Meta 类中的app_label
【解决方案2】:

要将您的模型拆分为模块,您必须提供app_label 元选项。例如:

my_user.py

from django.db import models
from django.contrib.auth.models import AbstractUser


class MyUser(AbstractUser):
    super_name = models.CharField(max_length=254, unique=True)
    class Meta:
        app_label = 'bla_app'

正如@petkostas 所说,在 Django 1.7 (issue 4470) 中不需要它

看看this answer,它描述了这个过程。

【讨论】:

  • 谢谢,就这样。记住,如果我们出于某种原因重命名应用程序,我们需要编辑 all app_label 值,这很痛苦。但现在就可以了。
猜你喜欢
  • 2010-11-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-27
  • 2010-11-10
  • 2013-04-20
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多