我正面临一个与我的django模型之间的奇怪情况。 我正在使用Django 1.10.3和python 3.5.2。
模型看起来像这样(为简洁起见而简化):
class Report(models.Model):
date = models.FieldDate()
def fieldA_default(self):
return MyObject.objects.filter(date=self.date).count()
fieldA = models.IntegerField(default=fieldA_default)
我有初始迁移创建模型并添加字段,由django使用./manage.py makemigrations
自动生成。
我将此代码提交到我的git repo,并将其部署到我的生产服务器,但实际上并未使用该模型(我的数据库中没有Report
个对象)。
我刚刚发现此代码不正确(django set default value of a model field to a self attribute)并决定改为覆盖save()
。
但是当我将默认值从fieldA_default
更改为0
时,运行./manage.py makemigrations
会失败,因为它会尝试运行旧的默认值函数fieldA_default
。在尝试了几个选项后,我最终决定完全删除该模型。但这不起作用,因为makemigrations
仍在尝试运行相同的功能。
以下是我删除模型时makemigrations
的追溯:
Traceback (most recent call last):
File "./manage.py", line 22, in <module>
execute_from_command_line(sys.argv)
File "venv/lib/python3.5/site-packages/django/core/management/__init__.py", line 367, in execute_from_command_line
utility.execute()
File "venv/lib/python3.5/site-packages/django/core/management/__init__.py", line 359, in execute
self.fetch_command(subcommand).run_from_argv(self.argv)
File "venv/lib/python3.5/site-packages/django/core/management/base.py", line 294, in run_from_argv
self.execute(*args, **cmd_options)
File "venv/lib/python3.5/site-packages/django/core/management/base.py", line 345, in execute
output = self.handle(*args, **options)
File "venv/lib/python3.5/site-packages/django/core/management/commands/makemigrations.py", line 95, in handle
loader = MigrationLoader(None, ignore_no_migrations=True)
File "venv/lib/python3.5/site-packages/django/db/migrations/loader.py", line 52, in __init__
self.build_graph()
File "venv/lib/python3.5/site-packages/django/db/migrations/loader.py", line 197, in build_graph
self.load_disk()
File "venv/lib/python3.5/site-packages/django/db/migrations/loader.py", line 108, in load_disk
migration_module = import_module("%s.%s" % (module_name, migration_name))
File "venv/lib/python3.5/importlib/__init__.py", line 126, in import_module
return _bootstrap._gcd_import(name[level:], package, level)
File "<frozen importlib._bootstrap>", line 986, in _gcd_import
File "<frozen importlib._bootstrap>", line 969, in _find_and_load
File "<frozen importlib._bootstrap>", line 958, in _find_and_load_unlocked
File "<frozen importlib._bootstrap>", line 673, in _load_unlocked
File "<frozen importlib._bootstrap_external>", line 665, in exec_module
File "<frozen importlib._bootstrap>", line 222, in _call_with_frames_removed
File "xxx/reporting/migrations/0001_initial.py", line 9, in <module>
class Migration(migrations.Migration):
File "xxx/reporting/migrations/0001_initial.py", line 22, in Migration
('fieldA', models.IntegerField(default=reporting.models.Report.fieldA_default)),
AttributeError: module 'reporting.models' has no attribute 'Report'
我有几个问题:
答案 0 :(得分:1)
为什么Django运行这个“旧”代码,即使我正在删除该模型?
因为模型及其方法仍在迁移文件0001_initial.py
但是当我将fieldA_default的默认值更改为0时,运行./manage.py makemigrations失败,因为它尝试运行旧的默认值函数fieldA_default。
我假设,在重置字段上的默认值后,您删除了 - 现在已过时 - 方法fieldA_default
。如上所述,此方法在初始迁移中引用,现在必须中断。
如果没有Django对我尖叫,我如何设法将这个无效代码转移到迁移中?
创建迁移时,代码无效。简单的向前迁移无法处理模型上的某些更改。在你的情况下:
在迁移文件中引用和导入模型时删除模型(本身只是另一个不能导入不存在的类的python模块)
同样用于删除默认方法。
当您的模型代码混乱或与您的迁移/ db不同步时,您可以做的一件事makemigrations
在当前状态下不起作用,如下所示:
python manage.py migrate app_name zero # undo all existing migrations of app
从应用中删除所有迁移文件。 (可选)如果您已经在数据库中拥有有价值的数据,则可以逐个撤消它们,看看步骤3是否已经有效
python manage.py makemigrations app_name # new start from clean sheet
这在开发过程中很容易,可以被认为是迁移压缩的替代方案,但如果您已经在数据库中拥有生产数据,那么这显然是最后的选择。但在这种情况下,无论如何都应该谨慎应用模型更改:)
答案 1 :(得分:0)