Как получить дополнительную информацию о том, какие различия между полями были найдены с помощью управления makemigrations
Иногда при выполнении manage makemigrations
в моем проекте Django я получаю неожиданную запись migrations.AlterField()
в файле миграций.
Я знаю, что это происходит из-за того, что Django видит различия между определением поля в моей модели и определением поля после применения всех миграций.
Есть ли способ узнать, какую разницу он видит? Я могу посмотреть на свои поля в моделях и использовать _meta
для получения параметров поля, которые я не указал явно, но есть ли способ получить информацию о том, как выглядит поле на стороне миграции? Так сказать, сравнить целевое и фактическое состояние?
Я ищу информацию о том, есть ли, например, AlterField()
в IntegerField, который был подхвачен, потому что max value
изменился, или он имеет другой verbose_name
.
На данный момент я просто вручную копаюсь в файлах миграции в поисках упоминаний соответствующего поля, но я работаю с устаревшим проектом, в котором их очень много. Поэтому мне интересно, сталкивался ли кто-нибудь с такой же проблемой и нашел ли лучшее решение.
Вы можете использовать python manage.py makemigrations app_name --dry-run -v 3
для проверки изменений в моделях приложений перед запуском реальных makemigrations
.
Django has no means to print this, or at least not without patching the Django package. But the good news is, we can: you can look to the virtual environment for the location where Django is installed, and patch the django/db/migrations/autodetector.py
file. Django uses this to detect changes. Indeed, in the source code, we see [GitHub]:
old_field_dec = self.deep_deconstruct(old_field) new_field_dec = self.deep_deconstruct(new_field) # ... if old_field_dec != new_field_dec and old_field_name == field_name: # ...
Мы можем заменить это чем-то, что регистрирует изменения, например, какой-нибудь функцией для регистрации разницы:
MISSING = object()
def show_dict_diff(old, new):
for k, v1 in new.items():
v2 = old.get(k, MISSING)
if v2 is MISSING:
yield f" Added: {k} = {v1}"
elif v1 != v2:
yield f" Changed: {k} = {v2} -> {v1}"
for k, v in old.items():
if k not in new:
yield f" Removed: {k} = {v}"
и адаптируйте файл к:
old_field_dec = self.deep_deconstruct(old_field)
new_field_dec = self.deep_deconstruct(new_field)
# …
if old_field_dec != new_field_dec and old_field_name == field_name:
print(f'change detected for {field_name}')
show_dict_diff(old_field_dec[2], new_field_dec[2])
# …
или как патч:
Index: django/db/migrations/autodetector.py
<+>UTF-8
===================================================================
diff --git a/django/db/migrations/autodetector.py b/django/db/migrations/autodetector.py
--- a/django/db/migrations/autodetector.py (revision 9dfcb719558c21dbc92754739cc8f4b6e6fdfa62)
+++ b/django/db/migrations/autodetector.py (date 1726125682049)
@@ -19,6 +19,20 @@
)
from django.utils.functional import cached_property
+MISSING = object()
+
+
+def show_dict_diff(old, new):
+ for k, v1 in new.items():
+ v2 = old.get(k, MISSING)
+ if v2 is MISSING:
+ yield f" Added: {k} = {v1}"
+ elif v1 != v2:
+ yield f" Changed: {k} = {v2} -> {v1}"
+ for k, v in old.items():
+ if k not in new:
+ yield f" Removed: {k} = {v}"
+
class OperationDependency(
namedtuple("OperationDependency", "app_label model_name field_name type")
@@ -1284,6 +1298,8 @@
# db_column was allowed to change which generate_renamed_fields()
# already accounts for by adding an AlterField operation.
if old_field_dec != new_field_dec and old_field_name == field_name:
+ print(f'change detected for {field_name}')
+ show_dict_diff(old_field_dec[2], new_field_dec[2])
both_m2m = old_field.many_to_many and new_field.many_to_many
neither_m2m = not old_field.many_to_many and not new_field.many_to_many
if both_m2m or neither_m2m: