Django 1.7: Lazy evaluation to avoid “App registry isn't ready yet” in models.py

落花浮王杯 提交于 2019-12-11 22:24:55

问题


I have a query in a model's method definition:

'content_type_id': ContentType.objects.get_for_model(model).pk,

https://github.com/seperman/django-tagging/blob/develop/tagging/models.py#L107

And it raises "App registry is not ready yet".

Putting the line inside another independent function doesn't help either since it still gets called.

Django docs:

Executing database queries with the ORM at import time in models modules will also trigger this exception. The ORM cannot function properly until all models are available.

How can I make it lazy evaluate this line? I thought about caching its results manually in a file by making a management command. And then reading the cached result but there should be a much better/cleaner solution(?)

./manage.py shell
Traceback (most recent call last):
File "./manage.py", line 10, in <module>
  execute_from_command_line(sys.argv)
File "/var/www/something.com/something/shared/env/local/lib/python2.7/site-packages/django/core/management/__init__.py", line 385, in execute_from_command_line
  utility.execute()
File "/var/www/something.com/something/shared/env/local/lib/python2.7/site-packages/django/core/management/__init__.py", line 354, in execute
  django.setup()
File "/var/www/something.com/something/shared/env/local/lib/python2.7/site-packages/django/__init__.py", line 21, in setup
  apps.populate(settings.INSTALLED_APPS)
File "/var/www/something.com/something/shared/env/local/lib/python2.7/site-packages/django/apps/registry.py", line 108, in populate
  app_config.import_models(all_models)
File "/var/www/something.com/something/shared/env/local/lib/python2.7/site-packages/django/apps/config.py", line 202, in import_models
  self.models_module = import_module(models_module_name)
File "/usr/lib/python2.7/importlib/__init__.py", line 37, in import_module
  __import__(name)
File "/var/www/something.com/something/current/apps/riding/models.py", line 32, in <module>
  class RidingSection(CategoryBase):
File "/var/www/something.com/something/shared/env/local/lib/python2.7/site-packages/mptt/models.py", line 244, in __new__
  cls = meta.register(cls)
File "/var/www/something.com/something/shared/env/local/lib/python2.7/site-packages/mptt/models.py", line 325, in register
  obj = getattr(cls, attr)
File "/var/www/something.com/something/current/apps/tagging/fields.py", line 54, in __get__
  return edit_string_for_tags(Tag.objects.usage_for_model(owner))
File "/var/www/something.com/something/current/apps/tagging/models.py", line 148, in usage_for_model
  usage = self.usage_for_queryset(queryset, counts, min_count)
File "/var/www/something.com/something/current/apps/tagging/models.py", line 185, in usage_for_queryset
  return self._get_usage(queryset.model, counts, min_count, extra_joins, extra_criteria, params)
File "/var/www/something.com/something/current/apps/tagging/models.py", line 107, in _get_usage
  'content_type_id': ContentType.objects.get_for_model(model).pk,
File "/var/www/something.com/something/shared/env/local/lib/python2.7/site-packages/django/contrib/contenttypes/models.py", line 50, in get_for_model
  defaults={'name': smart_text(opts.verbose_name_raw)},
File "/var/www/something.com/something/shared/env/local/lib/python2.7/site-packages/django/db/models/manager.py", line 92, in manager_method
  return getattr(self.get_queryset(), name)(*args, **kwargs)
File "/var/www/something.com/something/shared/env/local/lib/python2.7/site-packages/django/db/models/query.py", line 422, in get_or_create
  return self.get(**lookup), False
File "/var/www/something.com/something/shared/env/local/lib/python2.7/site-packages/django/db/models/query.py", line 345, in get
  clone = self.filter(*args, **kwargs)
File "/var/www/something.com/something/shared/env/local/lib/python2.7/site-packages/django/db/models/query.py", line 691, in filter
  return self._filter_or_exclude(False, *args, **kwargs)
File "/var/www/something.com/something/shared/env/local/lib/python2.7/site-packages/django/db/models/query.py", line 709, in _filter_or_exclude
  clone.query.add_q(Q(*args, **kwargs))
File "/var/www/something.com/something/shared/env/local/lib/python2.7/site-packages/django/db/models/sql/query.py", line 1287, in add_q
  clause, require_inner = self._add_q(where_part, self.used_aliases)
File "/var/www/something.com/something/shared/env/local/lib/python2.7/site-packages/django/db/models/sql/query.py", line 1314, in _add_q
  current_negated=current_negated, connector=connector)
File "/var/www/something.com/something/shared/env/local/lib/python2.7/site-packages/django/db/models/sql/query.py", line 1138, in build_filter
  lookups, parts, reffed_aggregate = self.solve_lookup_type(arg)
File "/var/www/something.com/something/shared/env/local/lib/python2.7/site-packages/django/db/models/sql/query.py", line 1076, in solve_lookup_type
  _, field, _, lookup_parts = self.names_to_path(lookup_splitted, self.get_meta())
File "/var/www/something.com/something/shared/env/local/lib/python2.7/site-packages/django/db/models/sql/query.py", line 1339, in names_to_path
  field, model, direct, m2m = opts.get_field_by_name(name)
File "/var/www/something.com/something/shared/env/local/lib/python2.7/site-packages/django/db/models/options.py", line 416, in get_field_by_name
  cache = self.init_name_map()
File "/var/www/something.com/something/shared/env/local/lib/python2.7/site-packages/django/db/models/options.py", line 445, in init_name_map
  for f, model in self.get_all_related_m2m_objects_with_model():
File "/var/www/something.com/something/shared/env/local/lib/python2.7/site-packages/django/db/models/options.py", line 563, in get_all_related_m2m_objects_with_model
  cache = self._fill_related_many_to_many_cache()
File "/var/www/something.com/something/shared/env/local/lib/python2.7/site-packages/django/db/models/options.py", line 577, in _fill_related_many_to_many_cache
  for klass in self.apps.get_models():
File "/var/www/something.com/something/shared/env/local/lib/python2.7/site-packages/django/utils/lru_cache.py", line 101, in wrapper
  result = user_function(*args, **kwds)
File "/var/www/something.com/something/shared/env/local/lib/python2.7/site-packages/django/apps/registry.py", line 168, in get_models
  self.check_models_ready()
File "/var/www/something.com/something/shared/env/local/lib/python2.7/site-packages/django/apps/registry.py", line 131, in check_models_ready
  raise AppRegistryNotReady("Models aren't loaded yet.")

django.core.exceptions.AppRegistryNotReady: Models aren't loaded yet.


回答1:


django-tagging is being a little inconsiderate here.

TagField is a descriptor, meaning if you access YourModel.tags, it runs code which executes a database query.

It just so happens that django-mptt iterates over all the attributes of your MPTTModel classes during startup (before the app cache has loaded), so it happens to trigger this exception.

I don't know how you'd prevent that in django-tagging while maintaining the API (YourModel.tags has to get tags from somewhere). Issues like this are probably the reason why django-tagging is no longer maintained.

However, I'm the maintainer of django-mptt and I've committed a workaround. If you upgrade to the master version of mptt you should find it works now.




回答2:


You are calling _get_usage before the app has been registered. Wherever you are calling it needs to be changed to a point where the app has been configured. Basically, if you need a model at import time you should use ready().

For example, if you had a signals.py you could do:

# in apps.py
class SomeAppConfig(AppConfig):
    def ready(self):
        from . import signals

or in your case:

# in apps.py
class SomeAppConfig(AppConfig):
    def ready(self):
        mgr = TagManager()
        mgr._get_usage(#some_args)

As the docs state: ready() ... is called as soon as the registry is fully populated



来源:https://stackoverflow.com/questions/27790344/django-1-7-lazy-evaluation-to-avoid-app-registry-isnt-ready-yet-in-models-py

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!