В ходе разработки нашего текущего django-проекта (django 1.7.1) мы столкнулись с задачей пометить некоторые записи базы данных как удаленные и удалить их из поля зрения пользователя, но не полностью из базы данных.
Я нашел быстрое и простое решение django-logicaldelete (именно то, что мы хотим сделать!)
Следуя инструкциям django-logicaldelete, я установил logicaldelete с помощью pip и добавил его как INSTALLED_APP в settings.py.
Осталось только добавить logicaldelete в models.py и admin.py, унаследованный от него.
...
import logicaldelete
class MyModel(logicaldelete.models.Model){...}
...
...
import logicaldelete
class MyModelAdmin(logicaldelete.admin.ModelAdmin){...}
...
Пока все хорошо :) Попытка запустить проект теперь вызывает «AppRegistryNotReady: модели еще не загружены». - Ошибка:
Traceback (most recent call last):
File "C:\Python34\lib\site-packages\django\db\models\options.py", line 414, in get_field_by_name
return self._name_map[name]
AttributeError: 'Options' object has no attribute '_name_map'
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "C:\Python34\lib\site-packages\django\db\models\options.py", line 561, in get_all_related_m2m_objects_with_model
cache = self._related_many_to_many_cache
AttributeError: 'Options' object has no attribute '_related_many_to_many_cache'
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "C:\eclipse\workspacePraxis\promotionsdatenbank\manage.py", line 10, in <module>
execute_from_command_line(sys.argv)
File "C:\Python34\lib\site-packages\django\core\management\__init__.py", line 385, in execute_from_command_line
utility.execute()
File "C:\Python34\lib\site-packages\django\core\management\__init__.py", line 354, in execute
django.setup()
File "C:\Python34\lib\site-packages\django\__init__.py", line 21, in setup
apps.populate(settings.INSTALLED_APPS)
File "C:\Python34\lib\site-packages\django\apps\registry.py", line 108, in populate
app_config.import_models(all_models)
File "C:\Python34\lib\site-packages\django\apps\config.py", line 202, in import_models
self.models_module = import_module(models_module_name)
File "C:\Python34\lib\importlib\__init__.py", line 109, in import_module
return _bootstrap._gcd_import(name[level:], package, level)
File "<frozen importlib._bootstrap>", line 2254, in _gcd_import
File "<frozen importlib._bootstrap>", line 2237, in _find_and_load
File "<frozen importlib._bootstrap>", line 2226, in _find_and_load_unlocked
File "<frozen importlib._bootstrap>", line 1200, in _load_unlocked
File "<frozen importlib._bootstrap>", line 1129, in _exec
File "<frozen importlib._bootstrap>", line 1471, in exec_module
File "<frozen importlib._bootstrap>", line 321, in _call_with_frames_removed
File "C:\eclipse\workspacePraxis\promotionsdatenbank\personen\models.py", line 144, in <module>
class PromovendChoice(forms.Form):
File "C:\eclipse\workspacePraxis\promotionsdatenbank\personen\models.py", line 149, in PromovendChoice
promovend_choice = forms.ModelChoiceField(queryset=Promovend.objects.all(), to_field_name='nachname', empty_label="Promovend")
File "C:\Python34\lib\site-packages\django\db\models\manager.py", line 191, in all
return self.get_queryset()
File "C:\Python34\lib\site-packages\logicaldelete\managers.py", line 15, in get_queryset
return LogicalDeleteQuerySet(self.model, using=self._db).filter(date_removed__isnull=True)
File "C:\Python34\lib\site-packages\django\db\models\query.py", line 691, in filter
return self._filter_or_exclude(False, *args, **kwargs)
File "C:\Python34\lib\site-packages\django\db\models\query.py", line 709, in _filter_or_exclude
clone.query.add_q(Q(*args, **kwargs))
File "C:\Python34\lib\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 "C:\Python34\lib\site-packages\django\db\models\sql\query.py", line 1314, in _add_q
current_negated=current_negated, connector=connector)
File "C:\Python34\lib\site-packages\django\db\models\sql\query.py", line 1138, in build_filter
lookups, parts, reffed_aggregate = self.solve_lookup_type(arg)
File "C:\Python34\lib\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 "C:\Python34\lib\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 "C:\Python34\lib\site-packages\django\db\models\options.py", line 416, in get_field_by_name
cache = self.init_name_map()
File "C:\Python34\lib\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 "C:\Python34\lib\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 "C:\Python34\lib\site-packages\django\db\models\options.py", line 577, in _fill_related_many_to_many_cache
for klass in self.apps.get_models():
File "C:\Python34\lib\functools.py", line 428, in wrapper
result = user_function(*args, **kwds)
File "C:\Python34\lib\site-packages\django\apps\registry.py", line 168, in get_models
self.check_models_ready()
File "C:\Python34\lib\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.
Я читал об этой проблеме с django 1.7 и как решение
import django
django.setup()
дано. Здесь я не работаю, чтобы добавить эти строки. Пытался добавить его в logicaldelete.managers.py и logicaldelete.query.py.
Кажется, у меня неправильное представление о том, что вызывает проблему.
Единственная часть моего собственного кода, показанная в трассировке ошибок, — это вызов в форме:
promovend_choice = forms.ModelChoiceField(queryset=Promovend.objects.all(), to_field_name='nachname', empty_label="Promovend")
Надеюсь, вы знаете, как решить эту проблему...
Если нет, я просто переопределю метод удаления и добавлю менеджера самостоятельно.
Обновление №. 3
Я сам реализовал BaseModel и подходящий менеджер (он почти не отличается от logicaldelete)
class SoftDeleteBaseModel(models.Model):
deleted = models.BooleanField(default=False)
objects = SoftDeleteManager(False)
objects_deleted = SoftDeleteManager(True)
all_objects = models.Manager()
def delete(self):
related_models = [relation.get_accessor_name() for relation in self._meta.get_all_related_objects()]
for model_objects in rleated_models:
related_objects = getattr(self, model_objects).all()
for related_object in related_objects:
if not issubclass(related_object.__class__, SoftDeleteBaseModel):
break
related_object.delete()
self.deleted= True
self.save()
class Meta:
abstract = True
class SoftDeleteManager(models.Manager):
def __init__(self, show_deleted=False):
super(SoftDeleteManager, self).__init__()
self.show_deleted = show_deleted
def get_queryset(self):
qs = super(SoftDeleteManager, self).get_queryset()
return qs.filter(deleted=self.show_deleted)
К сожалению, возникает та же ошибка. Импорт django и вызов django.setup() в моем файле manager.py также не работает.
Возникла проблема с вызовом (самодельного) менеджера с помощью
objects = SoftDeleteManager(False)
objects_deleted = SoftDeleteManager(True)
all_objects = models.Manager()
Кажется, что SoftDeleteManger не готов (загружен), пока моя модель хочет сослаться на него.
Обновление № 4
Новые выводы:
Предполагать, что ошибка лежит в моей форме, было не так уж и плохо! Мне интересно, что использование queryset = model.objects.all()
со стандартным менеджером работает нормально, замена его на мой SoftDeleteManager вызывает ошибку...
Возникла идея: почему бы не добавить фильтр к этой кодовой строке с помощью стандартного менеджера? queryset = models.objects.all().filter(deleted=False)
Этот код также вызывает ошибку AppRegistryNotReady - поэтому основная причина, по-видимому, заключается в фильтрации наборов запросов в моем самодельном менеджере...
Редактировать
Я обнаружил аналогичную проблему с фильтрацией наборов запросов здесь. Но, как упоминалось выше, я безуспешно пытался использовать import django
и django.setup()
...
Обновление № 5
Прочитав сто раз, вызов django.setup()
решит проблему, которую я назвал в своем models.py, ожидая ошибки или успешного запуска... но ничего не происходит. Запуск проекта создает процесс python, но выходных данных нет, и сервер разработки не запускается...
Привет, Тоби