起きたこと
djangoのソース(docstring)をsphinx-buildすると以下のエラーが起こりました。
WARNING: autodoc: failed to import module 'views' from module 'blogs'; the following exception was raised: Traceback (most recent call last): File "/usr/local/python/lib/python3.8/site-packages/sphinx/ext/autodoc/importer.py", line 32, in import_module return importlib.import_module(modname) File "/usr/local/python/lib/python3.8/importlib/__init__.py", line 127, in import_module return _bootstrap._gcd_import(name[level:], package, level) File "<frozen importlib._bootstrap>", line 1014, in _gcd_import File "<frozen importlib._bootstrap>", line 991, in _find_and_load File "<frozen importlib._bootstrap>", line 975, in _find_and_load_unlocked File "<frozen importlib._bootstrap>", line 671, in _load_unlocked File "<frozen importlib._bootstrap_external>", line 783, in exec_module File "<frozen importlib._bootstrap>", line 219, in _call_with_frames_removed File "/opt/myblog/blogs/views.py", line 3, in <module> from .models import * File "/opt/myblog/blogs/models.py", line 8, in <module> class TopicsTr(models.Model): File "/usr/local/python/lib/python3.8/site-packages/django/db/models/base.py", line 112, in __new__ raise RuntimeError( RuntimeError: Model class blogs.models.TopicsTr doesn't declare an explicit app_label and isn't in an application in INSTALLED_APPS.
Djangoでsphinx-buildする場合
前提として、conf.pyに以下を記載します。
import os import sys sys.path.insert(0, '/path/to/source') import django from django.conf import settings settings.configure() django.setup()
エラーの原因
エラーメッセージを見ると
RuntimeError: Model class blogs.models.TopicsTr doesn't declare an explicit app_label and isn't in an application in INSTALLED_APPS.
「blogs.models.TopicsTr」というモデルクラスのapp_labelがINSTALLED_APPSの中に定義されてない、といったところでしょうか。
ちなみにsettings.pyとmodels.pyは以下のようになっています。
settings.py
: INSTALLED_APPS = [ 'blogs', 'myauth', 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'django_extensions', 'widget_tweaks', ] :
models.py
class TopicsTr(models.Model): id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) title = models.CharField(max_length=128, default='no title', null=False) created_at = models.DateTimeField(default=timezone.now, null=False) last_update = models.DateTimeField(default=timezone.now, null=False) isdraft = models.BooleanField(default=False, null=False) thumbnail = models.BigIntegerField(default=0, null=False) text = models.TextField(null=True) likes = models.IntegerField(default=0, null=False)
「blogs.models.TopicsTr」のパッケージ名であるblogsはDjangoアプリケーション名としてINSTALLED_APPSに定義されているのに、
なぜ認識されないのでしょうか。
ちなみにマニュアルには以下のように記載されています。
If a model is defined outside of an application in INSTALLED_APPS, it must declare which app it belongs to:
app_label = 'myapp'
If you want to represent a model with the format app_label.object_name or app_label.model_name you can use model._meta.label or model._meta.label_lower respectively.
Model Meta options | Django ドキュメント | Django
INSTALLED_APPSのアプリケーション以外でモデルを宣言する場合は
明示的にapp_labelを定義しないといけませんよー。と。
今回はblogsというアプリの中にあるモデルなので上記には該当しないはずなのですが・・・。
エラーメッセージから見るにそうとは認識されていないようです。
裏を返せばapp_labelを宣言してしまえば解決するのでは?
ということでmodels.pyを以下のように変更
models.py
class TopicsTr(models.Model): + class Meta: + abstract = True # specify this model as an Abstract Model + app_label = 'blogs' id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) title = models.CharField(max_length=128, default='no title', null=False) created_at = models.DateTimeField(default=timezone.now, null=False) last_update = models.DateTimeField(default=timezone.now, null=False) isdraft = models.BooleanField(default=False, null=False) thumbnail = models.BigIntegerField(default=0, null=False) text = models.TextField(null=True) likes = models.IntegerField(default=0, null=False)
前述のマニュアルにもあるとおり、app_labelはMetaクラス内で宣言します。
abstractを有効にするのも忘れずに。
これでINSTALLED_APPSのアプリに所属することを明示的に宣言しました。
sphinx-buildしてみます。
# sphinx-build -a -b html ./docs ./docs/html Running Sphinx v3.1.1 loading translations [en]... done loading pickled environment... done building [mo]: all of 0 po files building [html]: all source files updating environment: 0 added, 1 changed, 0 removed reading sources... [100%] blogs looking for now-outdated files... none found pickling environment... done checking consistency... done preparing documents... done writing output... [100%] modules generating indices... genindex py-modindexdone highlighting module code... [100%] functools writing additional pages... searchdone copying static files... ... done copying extra files... done dumping search index in English (code: en)... done dumping object inventory... done build succeeded, 3 warnings. The HTML pages are in docs/html.
うまくいきました。うーん。。。
ちなみにdjnago自体はapp_labelを宣言しなくても正常に動きます。
そりゃそうですよね、blogsアプリの中でモデル定義してるんだから。
ちなみにできたドキュメントはこんな感じです。
見にくいです。もっとちゃんとdocstring書かないとだめですね。
スタイルも工夫したいと思います。
結論
models.pyでapp_labelを明示的に宣言する。