在shell中出现错误:没有声明明确的app_label并且不在INSTALLED_APPS应用程序中。

3

我第一次尝试Django,读了书《Two scoops of Django 1.11》,感觉不错。虽然只有编写脚本的经验,且对Python还很陌生,但我尽最大努力按照书中标准进行。

使用"cookiecutter-django"启动项目。创建了一个简单的Address app和一个TimeStampedModel以供实验。

使用makemigrations、migrate、admin和runserver工具时一切都很好,没有问题,非常顺畅。

但是,当我想用shell测试书中关于csv导入和绑定到表单的示例时,出现了错误。

以下内容可能有点啰嗦,但我不确定该如何继续操作。

python manage.py shell --settings=config.settings.local

当导入所需代码(任何其他表单或模型均会产生相同结果)时出现错误:

In [1]: from address.forms import add_csv_postarea
---------------------------------------------------------------------------
RuntimeError                              Traceback (most recent call last)
<ipython-input-1-f253686866ed> in <module>()
----> 1 from address.forms import add_csv_postarea

~/projects/myproject/myproject/address/forms.py in <module>()
      5 from django import forms
      6 
----> 7 from .models import PostArea, Address
      8 
      9 

~/projects/myproject/myproject/address/models.py in <module>()
      7 
      8 
----> 9 class Country(TimeStampedModel):
     10     """ ISO 3166 Country codes
     11         https://en.wikipedia.org/wiki/ISO_3166-1

~/.virtualenvs/myproject/lib/python3.6/site-packages/django/db/models/base.py in __new__(cls, name, bases, attrs)
    116                         "Model class %s.%s doesn't declare an explicit "
    117                         "app_label and isn't in an application in "
--> 118                         "INSTALLED_APPS." % (module, name)
    119                     )
    120 

RuntimeError: Model class address.models.Country doesn't declare an explicit app_label and isn't in an application in INSTALLED_APPS.

上述提及的模型尚未实施,但如果我注释掉该模型,下一个模型PostArea仍然会遇到相同的问题。
以下是我的相关设置:
config/settings/base.py
...
# Apps specific for this project go here.
LOCAL_APPS = [
    # custom users app
    'myproject.users.apps.UsersConfig',

    # Your stuff: custom apps go here
    'myproject.core', # Containing the abstract class TimeStampedModel
    'myproject.address', # including the address and PostArea models
]
...

config/urls.py

urlpatterns = [
    ...
    # Your stuff: custom urls includes go here
    url(r'^address/', include('myproject.address.urls', namespace='address')),

myproject/address/forms.py

import csv

from django.utils.six import StringIO

from django import forms

from .models import PostArea, Address


class AddressForm(forms.ModelForm):

    class Meta:

        model = Address
        fields = ['line1', 'line2', 'post_area']


class PostAreaForm(forms.ModelForm):

    class Meta:

        model = PostArea
        fields = ['code', 'name']


def add_csv_postarea(rows):
    """ Two Scoops of Django 1.11 - page 167
        Importing Postal addresses from a CSV file

        Data source: https://data.norge.no/data/posten-norge/postnummer-i-norge
    """

    rows = StringIO(rows)

    records_added = 0
    errors = []

    # Generate a dict per row, overriding the first CSV row missing keys
    for row in csv.DictReader(rows, fieldnames=('code', 'name')):

        # Bind the row to PostAreaForm
        form = PostAreaForm(row)
        # Check to see if the row is valid
        if form.is_valid():
            # Row data is valid so save the record.
            form.save()
            records_added += 1
        else:
            errors.append(form.errors)

    return records_added, errors

myproject/address/models.py

import uuid as uuid_lib

from django.db import models
from django.urls import reverse

from core.models import TimeStampedModel


class Country(TimeStampedModel):
    """ ISO 3166 Country codes
        https://en.wikipedia.org/wiki/ISO_3166-1
    """
    iso_2 = models.CharField(max_length=2, null=False)
    iso_3 = models.CharField(max_length=3, null=False)
    iso_numeric = models.CharField(max_length=3, null=False)
    name_gb = models.CharField(max_length=30)
    name_no = models.CharField(max_length=30)

    def __str__(self):
        return self.iso_2

    class Meta:
        verbose_name = "Country"
        verbose_name_plural = "Countries"


class PostArea(TimeStampedModel):
    """ Norwegian PostArea code and are
        Foreign keys linking connected municipals
    """

    code = models.CharField(max_length=12)
    name = models.CharField(max_length=200)

    def __str__(self):
        return self.code

    class Meta:
        verbose_name = "Postal area"
        verbose_name_plural = "Postal Areas"


class Address(TimeStampedModel):
    """ Reusable Entities Addresses with relations to
            - PostArea
            - Country
    """

    uuid = models.UUIDField(
        primary_key=True,
        default=uuid_lib.uuid4(),
        editable=False
    )
    line1 = models.CharField(max_length=100)
    line2 = models.CharField(max_length=100, blank=True)
    post_area = models.ForeignKey(
        PostArea,
        on_delete=models.PROTECT,
        null=True,
    )

    def __str__(self):
        return self.line1

    def post_name_callable(self):
        return self.post_area.name

    def get_absolute_url(self):
        return reverse('address:detail', kwargs={'pk': self.uuid})

    class Meta:
        verbose_name = "Address"
        verbose_name_plural = "Addresses"

你的导入似乎不一致。你同时使用了 myproject.addressfrom address.forms。如果你在所有地方都使用 myproject.address,可能会解决这个问题。 - Alasdair
谢谢@Alasdair,在shell中使用from myproject.address.forms import add_csv_postarea解决了问题。我是新手 - 我该如何给你致谢? - henningb
@henningb,你只能为答案给出积分。由于他的是评论,您可以点赞。您也可以回答自己的问题并接受它,这样下一个来访者就可以轻松找到它。或者您可以要求Alasdair将他的评论发布为答案,并接受该答案。 - Bono
@henningb 我已将其添加为答案,如果它解决了您的问题,请接受它。 - Alasdair
1个回答

9
在您的INSTALLED_APPS中包含了myproject.address,因此在导入时应使用myproject.address而不是address
例如,更改以下内容:
from address.forms import add_csv_postarea

为了

from myproject.address.forms import add_csv_postarea

我不确定为什么您的项目布局允许您导入与myprojectmyproject.address相同的模块。在Django早期,这很容易导致奇怪的错误,但默认的项目布局已经在Django 1.4中更改以避免此问题。


谢谢!@alasdair 我差点把头发都拔光了。这么简单,但是很难搞明白 :-) - henningb

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接