首页 > 解决方案 > 如何解决管理站点中的这个奇怪错误?

问题描述

我正在与国家、地区、县、市和城市开展一个项目。每个都有自己的模型,并且模型是使用 ModelAdmin 注册的。

这是我的admin.py

from django.contrib import admin
from .models import Country, Region, County, Municipality, City


@admin.register(Country)
class CountryAdmin(admin.ModelAdmin):
    model = Country
    list_display = ["name", "continent", "capital", "area", "population", "regions"]
    list_filter = ["continent", "area", "population"]
    search_fields = ["name", "capital", "description"]


@admin.register(Region)
class RegionAdmin(admin.ModelAdmin):
    model = Region
    list_display = ["name", "country", "area", "population"]
    list_filter = ["country", "area", "population"]
    search_fields = ["name", "description"]


@admin.register(County)
class CountyAdmin(admin.ModelAdmin):
    model = County
    list_display = ["name", "capital", "area", "population", "abbreviation", "verbose_neighbours"]
    list_filter = ["region", "area", "population"]
    search_fields = ["name", "capital", "description", "abbreviation"]


@admin.register(Municipality)
class MunicipalityAdmin(admin.ModelAdmin):
    model = Municipality
    list_display = ["name", "county", "area", "population"]
    list_filter = ["county", "area", "population"]
    search_fields = ["name", "county", "description"]


@admin.register(City)
class CityAdmin(admin.ModelAdmin):
    model = City
    list_display = ["name", "county", "area", "population"]
    list_filter = ["county", "area", "population"]
    search_fields = ["name", "description"]

这是我的模型。

from django.db import models
from django.forms.models import model_to_dict
from django.dispatch import receiver
from django.db.models.signals import pre_save, post_save
from django.utils.translation import gettext_lazy as _


class ModelDiffMixin(object):
    """
    A model mixin that tracks model fields' values and provide some useful api
    to know what fields have been changed.
    """

    def __init__(self, *args, **kwargs):
        super(ModelDiffMixin, self).__init__(*args, **kwargs)
        self.__initial = self._dict

    @property
    def fields(self):
        return self._meta.fields

    @property
    def values(self):
        field_values = {}
        for f in self.fields:
            if hasattr(self, f.name) and getattr(self, f.name) not in [None, ""]:
                field_values[f.name] = getattr(self, f.name)
        return field_values

    @property
    def local_values(self):
        field_values = {}
        for f in self.fields:
            if hasattr(self, f.name) and getattr(self, f.name) not in [None, ""]:
                field_values[f.verbose_name] = getattr(self, f.name)
        return field_values

    @property
    def diff(self):
        d1 = self.__initial
        d2 = self._dict
        diffs = [[k, [v, d2[k]]] for k, v in d1.items() if v != d2[k]]
        return dict(diffs)

    @property
    def has_changed(self):
        return bool(self.diff)

    @property
    def changed_fields(self):
        return self.diff.keys()

    def get_field_diff(self, field_name):
        """Returns a diff for field if it's changed and None otherwise."""
        return self.diff.get(field_name, None)

    def save(self, *args, **kwargs):
        """Saves model and set initial state."""
        super(ModelDiffMixin, self).save(*args, **kwargs)
        self.__initial = self._dict

    def update(self, field, new_value):
        print(f"{field}: {new_value}")
        setattr(self, field, new_value)
        self.save()

    @property
    def _dict(self):
        return model_to_dict(self, fields=[field.name for field in self._meta.fields])


class Country(models.Model, ModelDiffMixin):
    name = models.CharField(max_length=50, verbose_name=_("numele țării"))
    continent = models.CharField(max_length=20, verbose_name=_("continentul"))
    capital = models.OneToOneField("Municipality", models.CASCADE, null=True, blank=True, related_name="capital_of_country", verbose_name=_("Capitala"))
    description = models.TextField(verbose_name=_("descrierea"))
    area = models.IntegerField(verbose_name=_("Suprafața"))
    population = models.IntegerField(verbose_name=_("Populația"))
    coat_of_arms = models.URLField(verbose_name=_("stema țării"))

    class Meta:
        verbose_name = _("Țara")
        verbose_name_plural = _("Țări")

    def __str__(self):
        return self.name


class Region(models.Model, ModelDiffMixin):
    name = models.CharField(max_length=50, verbose_name=_("Numele regiunei"))
    country = models.ForeignKey(Country, on_delete=models.CASCADE, related_name="regions", verbose_name=_("Țara"))
    description = models.TextField(verbose_name=_("Descrierea"))
    area = models.IntegerField(verbose_name=_("Suprafața"))
    population = models.IntegerField(verbose_name=_("Populația"))
    coat_of_arms = models.URLField(verbose_name=_("Stema regiunei"))

    class Meta:
        verbose_name = _("Regiune")
        verbose_name_plural = _("Regiuni")

    def __str__(self):
        return self.name


class County(models.Model, ModelDiffMixin):
    name = models.CharField(max_length=50, verbose_name=_("Numele județului"))
    capital = models.OneToOneField("Municipality", on_delete=models.PROTECT, null=True, blank=True, related_name="capital_of", verbose_name=_("Reședința"))
    region = models.ManyToManyField(Region, related_name="counties", verbose_name=_("Regiunea"))
    area = models.IntegerField(verbose_name=_("Suprafața"))
    population = models.IntegerField(verbose_name=_("Populația"))
    description = models.TextField(verbose_name=_("Descrierea"))
    abbreviation = models.CharField(max_length=2, verbose_name=_("Prescurtătura"))
    coat_of_arms = models.URLField(verbose_name=_("Stema județului"))
    north = models.OneToOneField("self", on_delete=models.SET_NULL, null=True, blank=True, related_name="to_south", verbose_name=_("Către nord"))
    northeast = models.OneToOneField("self", on_delete=models.SET_NULL, null=True, blank=True, related_name="to_southwest", verbose_name=_("Către nord-est"))
    east = models.OneToOneField("self", on_delete=models.SET_NULL, null=True, blank=True, related_name="to_west", verbose_name=_("Către est"))
    southeast = models.OneToOneField("self", on_delete=models.SET_NULL, null=True, blank=True, related_name="to_northwest", verbose_name=_("Către sud-est"))
    south = models.OneToOneField("self", on_delete=models.SET_NULL, null=True, blank=True, related_name="to_north", verbose_name=_("Către sud"))
    southwest = models.OneToOneField("self", on_delete=models.SET_NULL, null=True, blank=True, related_name="to_northeast", verbose_name=_("Către sud-vest"))
    west = models.OneToOneField("self", on_delete=models.SET_NULL, null=True, blank=True, related_name="to_east", verbose_name=_("Către vest"))
    northwest = models.OneToOneField("self", on_delete=models.SET_NULL, null=True, blank=True, related_name="to_southeast", verbose_name=_("Către nord-vest"))

    class Meta:
        verbose_name = _("Județ")
        verbose_name_plural = _("Județe")

    def __str__(self):
        return self.name

    @property
    def neighbours(self):
        directions = ["north", "northeast", "east", "southeast", "south", "southwest", "west", "northwest"]
        return directions

    @property
    def secondary_neighbours(self):
        secondary_directions = ["to_north", "to_northeast", "to_east", "to_southeast", "to_south", "to_southwest", "to_west", "to_northwest"] # ["to_south", "to_southwest", "to_west", "to_northwest", "to_north", "to_northeast", "to_east", "to_southeast"]
        return secondary_directions

    @property
    def verbose_neighbours(self):
        v_neighbours = {}
        for f in self.fields:
            if hasattr(self, f.name) and getattr(self, f.name) not in [None, ""] and f.name in self.neighbours:
                v_neighbours[f.verbose_name] = getattr(self, f.name)
        return v_neighbours
    verbose_neighbours.fget.short_description = _("Vecinii")


class Municipality(models.Model, ModelDiffMixin):
    name = models.CharField(max_length=50, verbose_name=_("Numele municipiului"))
    county = models.ForeignKey(County, on_delete=models.CASCADE, related_name="municipalities", verbose_name=_("Județul"))
    area = models.IntegerField(verbose_name=_("Suprafața"))
    population = models.IntegerField(verbose_name=_("Populația"))
    description = models.TextField(verbose_name=_("Descrierea"))
    coat_of_arms = models.URLField(verbose_name=_("Stema orașului"))

    class Meta:
        verbose_name = _("Municipiu")
        verbose_name_plural = _("Municipii")

    def __str__(self):
        return self.name


class City(models.Model, ModelDiffMixin):
    name = models.CharField(max_length=50, verbose_name=_("Numele orașului"))
    county = models.ForeignKey(County, on_delete=models.CASCADE, related_name="cities", verbose_name=_("Județul"))
    area = models.IntegerField(null=True, blank=True, verbose_name=_("Suprafața"))
    population = models.IntegerField(verbose_name=_("Populația"))
    description = models.TextField(null=True, blank=True, verbose_name=_("Descrierea"))

    class Meta:
        verbose_name = _("Oraș")
        verbose_name_plural = _("Orașe")

    def __str__(self):
        return f"{self.name} ({self.county})"

最后,这是当我尝试使用管理站点创建 Country 模型的新实例或查看创建的国家/地区列表时出现的错误。

Environment:


Request Method: GET
Request URL: http://localhost:1944/admin/counties/country/

Django Version: 3.2.5
Python Version: 3.9.6
Installed Applications:
['django.contrib.admin',
 'django.contrib.auth',
 'django.contrib.contenttypes',
 'django.contrib.sessions',
 'django.contrib.messages',
 'django.contrib.staticfiles',
 'counties',
 'rest_framework',
 'rest_framework.authtoken',
 'djoser',
 'django_extensions']
Installed Middleware:
['django.middleware.security.SecurityMiddleware',
 'django.contrib.sessions.middleware.SessionMiddleware',
 'django.middleware.common.CommonMiddleware',
 'django.middleware.csrf.CsrfViewMiddleware',
 'django.contrib.auth.middleware.AuthenticationMiddleware',
 'django.contrib.messages.middleware.MessageMiddleware',
 'django.middleware.clickjacking.XFrameOptionsMiddleware']


Template error:
In template D:\dev\py\RO\venv\lib\site-packages\django\contrib\admin\templates\admin\base.html, error at line 53
   __call__() missing 1 required keyword-only argument: 'manager'
   43 :                 {% if site_url %}
   44 :                     <a href="{{ site_url }}">{% translate 'View site' %}</a> /
   45 :                 {% endif %}
   46 :                 {% if user.is_active and user.is_staff %}
   47 :                     {% url 'django-admindocs-docroot' as docsroot %}
   48 :                     {% if docsroot %}
   49 :                         <a href="{{ docsroot }}">{% translate 'Documentation' %}</a> /
   50 :                     {% endif %}
   51 :                 {% endif %}
   52 :                 {% if user.has_usable_password %}
   53 :                  <a href="{% url 'adm in:password_change' %}">{% translate 'Change password' %}</a> /
   54 :                 {% endif %}
   55 :                 <a href="{% url 'admin:logout' %}">{% translate 'Log out' %}</a>
   56 :             {% endblock %}
   57 :         </div>
   58 :         {% endif %}
   59 :         {% endblock %}
   60 :         {% block nav-global %}{% endblock %}
   61 :     </div>
   62 :     <!-- END Header -->
   63 :     {% block breadcrumbs %}


Traceback (most recent call last):
  File "D:\dev\py\RO\venv\lib\site-packages\django\contrib\admin\utils.py", line 265, in lookup_field
    f = _get_non_gfk_field(opts, name)
  File "D:\dev\py\RO\venv\lib\site-packages\django\contrib\admin\utils.py", line 300, in _get_non_gfk_field
    raise FieldDoesNotExist()

During handling of the above exception (), another exception occurred:
  File "D:\dev\py\RO\venv\lib\site-packages\django\core\handlers\exception.py", line 47, in inner
    response = get_response(request)
  File "D:\dev\py\RO\venv\lib\site-packages\django\core\handlers\base.py", line 204, in _get_response
    response = response.render()
  File "D:\dev\py\RO\venv\lib\site-packages\django\template\response.py", line 105, in render
    self.content = self.rendered_content
  File "D:\dev\py\RO\venv\lib\site-packages\django\template\response.py", line 83, in rendered_content
    return template.render(context, self._request)
  File "D:\dev\py\RO\venv\lib\site-packages\django\template\backends\django.py", line 61, in render
    return self.template.render(context)
  File "D:\dev\py\RO\venv\lib\site-packages\django\template\base.py", line 170, in render
    return self._render(context)
  File "D:\dev\py\RO\venv\lib\site-packages\django\template\base.py", line 162, in _render
    return self.nodelist.render(context)
  File "D:\dev\py\RO\venv\lib\site-packages\django\template\base.py", line 938, in render
    bit = node.render_annotated(context)
  File "D:\dev\py\RO\venv\lib\site-packages\django\template\base.py", line 905, in render_annotated
    return self.render(context)
  File "D:\dev\py\RO\venv\lib\site-packages\django\template\loader_tags.py", line 150, in render
    return compiled_parent._render(context)
  File "D:\dev\py\RO\venv\lib\site-packages\django\template\base.py", line 162, in _render
    return self.nodelist.render(context)
  File "D:\dev\py\RO\venv\lib\site-packages\django\template\base.py", line 938, in render
    bit = node.render_annotated(context)
  File "D:\dev\py\RO\venv\lib\site-packages\django\template\base.py", line 905, in render_annotated
    return self.render(context)
  File "D:\dev\py\RO\venv\lib\site-packages\django\template\loader_tags.py", line 150, in render
    return compiled_parent._render(context)
  File "D:\dev\py\RO\venv\lib\site-packages\django\template\base.py", line 162, in _render
    return self.nodelist.render(context)
  File "D:\dev\py\RO\venv\lib\site-packages\django\template\base.py", line 938, in render
    bit = node.render_annotated(context)
  File "D:\dev\py\RO\venv\lib\site-packages\django\template\base.py", line 905, in render_annotated
    return self.render(context)
  File "D:\dev\py\RO\venv\lib\site-packages\django\template\loader_tags.py", line 62, in render
    result = block.nodelist.render(context)
  File "D:\dev\py\RO\venv\lib\site-packages\django\template\base.py", line 938, in render
    bit = node.render_annotated(context)
  File "D:\dev\py\RO\venv\lib\site-packages\django\template\base.py", line 905, in render_annotated
    return self.render(context)
  File "D:\dev\py\RO\venv\lib\site-packages\django\template\loader_tags.py", line 62, in render
    result = block.nodelist.render(context)
  File "D:\dev\py\RO\venv\lib\site-packages\django\template\base.py", line 938, in render
    bit = node.render_annotated(context)
  File "D:\dev\py\RO\venv\lib\site-packages\django\template\base.py", line 905, in render_annotated
    return self.render(context)
  File "D:\dev\py\RO\venv\lib\site-packages\django\contrib\admin\templatetags\base.py", line 33, in render
    return super().render(context)
  File "D:\dev\py\RO\venv\lib\site-packages\django\template\library.py", line 214, in render
    _dict = self.func(*resolved_args, **resolved_kwargs)
  File "D:\dev\py\RO\venv\lib\site-packages\django\contrib\admin\templatetags\admin_list.py", line 308, in result_list
    'results': list(results(cl)),
  File "D:\dev\py\RO\venv\lib\site-packages\django\contrib\admin\templatetags\admin_list.py", line 284, in results
    yield ResultList(None, items_for_result(cl, res, None))
  File "D:\dev\py\RO\venv\lib\site-packages\django\contrib\admin\templatetags\admin_list.py", line 275, in __init__
    super().__init__(*items)
  File "D:\dev\py\RO\venv\lib\site-packages\django\contrib\admin\templatetags\admin_list.py", line 200, in items_for_result
    f, attr, value = lookup_field(field_name, result, cl.model_admin)
  File "D:\dev\py\RO\venv\lib\site-packages\django\contrib\admin\utils.py", line 278, in lookup_field
    value = attr()

Exception Type: TypeError at /admin/counties/country/
Exception Value: __call__() missing 1 required keyword-only argument: 'manager'

我一遍又一遍地查看这些文件,但我不明白是什么导致了这个错误以及如何摆脱它。请对此有所了解。:)

也许值得注意的是 Country 的实例实际上是创建的。

标签: djangodjango-admin

解决方案


我认为,放置类实例时您的问题是错误的。ModelDiffMixin应该放在前面models.Model

尝试改变:

class Country(models.Model, ModelDiffMixin):
     ....

# and other models

进入:

class Country(ModelDiffMixin, models.Model):
    ....

# apply the same think to other models

建议:删除所有model = <ModelName>在您的管理类。afaik 它不需要变量,因为您已经在上面注册了它的模型。例如:

@admin.register(Country)
class CountryAdmin(admin.ModelAdmin):
    # model = Country   <== no-needed
    ....

推荐阅读