Jas*_*nTS 5 python django django-models django-migrations
我从昨天开始第二次遇到一个令人困惑的错误.上次我只是把我的整个迁移弄平了,但我从来没有真正找到导致问题的原因.
所以当我尝试为我的python项目制作移动时会出现这种情况.我应该在哪里寻找错误?我觉得它实际上并不是关于迁移,而是关于views.py或models.py中的错误,即使我完全不明白为什么这会影响数据库迁移.
无论如何,这些错误都没有指向我编写的代码.这一切都在Django.那么如何找到导致该错误的错误呢?
(testenv1) C:\Users\user\eclipse_workspace\test1\test1>python manage.py makemigrations --trace
Traceback (most recent call last):
File "manage.py", line 22, in <module>
execute_from_command_line(sys.argv)
File "C:\Python27\testenv1\lib\site-packages\django\core\management\__init__.py", line 363, in execute_from_command_line
utility.execute()
File "C:\Python27\testenv1\lib\site-packages\django\core\management\__init__.py", line 355, in execute
self.fetch_command(subcommand).run_from_argv(self.argv)
File "C:\Python27\testenv1\lib\site-packages\django\core\management\base.py", line 283, in run_from_argv
self.execute(*args, **cmd_options)
File "C:\Python27\testenv1\lib\site-packages\django\core\management\base.py", line 330, in execute
output = self.handle(*args, **options)
File "C:\Python27\testenv1\lib\site-packages\django\core\management\commands\makemigrations.py", line 150, in handle
loader.project_state(),
File "C:\Python27\testenv1\lib\site-packages\django\db\migrations\loader.py", line 323, in project_state
return self.graph.make_state(nodes=nodes, at_end=at_end, real_apps=list(self.unmigrated_apps))
File "C:\Python27\testenv1\lib\site-packages\django\db\migrations\graph.py", line 409, in make_state
project_state = self.nodes[node].mutate_state(project_state, preserve=False)
File "C:\Python27\testenv1\lib\site-packages\django\db\migrations\migration.py", line 92, in mutate_state
operation.state_forwards(self.app_label, new_state)
File "C:\Python27\testenv1\lib\site-packages\django\db\migrations\operations\fields.py", line 148, in state_forwards
delay = not old_field.is_relation
AttributeError: 'NoneType' object has no attribute 'is_relation'
(testenv1) C:\Users\user\eclipse_workspace\test1\test1>
Run Code Online (Sandbox Code Playgroud)
这是我的models.py.它目前是WIP:
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models
#from wheel.metadata import unique
from datetime import datetime
from django.urls import reverse
# Create your models here.
from django.shortcuts import redirect
class Task(models.Model):
name = models.CharField(max_length=255,blank=True)
code = models.SlugField(max_length=255, unique=True)
sender = models.ForeignKey("Sender", default=0)
client = models.ForeignKey("Client", null=True,blank=True)
datetime = models.DateTimeField(default=datetime.now)
duration = models.IntegerField(default=0,blank=True)
photo = models.ImageField(null=True, blank=True)
route = models.TextField(blank=True)
km = models.FloatField(default=0, blank=True)
notes = models.TextField(blank=True)
milage_receipt = models.ForeignKey("MilageReceipt", null=True, blank=True, on_delete=models.SET_NULL)
def date(self):
return self.datetime.date()
def status(self):
try:
if self.receipt and self.milage_receipt:
return "done"
elif not self.receipt:
return "new"
elif not self.milage_receipt:
return "ok"
except Receipt.DoesNotExist:
return "new"
except MilageReceipt.DoesNotExist:
return "processing"
return str(self.receipt)
def save(self, *args, **kwargs):
if self.duration == None:
self.duration = 0
if self.km == None:
self.km = 0
super(Task, self).save(*args, **kwargs) # Call the "real" save() method.
def get_absolute_url(self):
return reverse('task_update', args=[str(self.id)])
def __unicode__(self):
return self.code
class Client(models.Model):
name = models.CharField(max_length=255)
name2 = models.CharField(max_length=255, blank=True)
slug = models.SlugField(unique=True, max_length=255)
email = models.EmailField()
handle = models.CharField(max_length=255, blank=True)
contact_name = models.CharField(max_length=255, blank=True)
street = models.CharField(max_length=255)
zip = models.IntegerField()
city = models.CharField(max_length=255)
street2 = models.CharField(max_length=255,blank=True)
zip2 = models.CharField(max_length=255,blank=True)
city2 = models.CharField(max_length=255,blank=True)
default_vat = models.IntegerField(default=7)
km_price = models.FloatField(default=0)
active = models.BooleanField(default=False)
def __unicode__(self):
return self.slug
class Sender(models.Model):
name = models.CharField(max_length=255)
slug = models.SlugField(max_length=255)
email = models.EmailField()
street = models.CharField(max_length=255)
zip = models.IntegerField()
city = models.CharField(max_length=255)
phone = models.CharField(max_length=255)
website = models.URLField()
tax_id = models.CharField(max_length=255)
vat_id = models.CharField(max_length=255)
bank = models.ForeignKey("BankAccount")
def __unicode__(self):
return self.slug
class BankAccount(models.Model):
name = models.CharField(max_length=255)
iban = models.CharField(max_length=255)
bic = models.CharField(max_length=255)
holder = models.CharField(max_length=255)
class ReceiptNumber(models.Model):
id = models.AutoField(primary_key=True, unique=True)
number = models.IntegerField(blank=True)
def __unicode__(self):
return str(self.id)
class MyQuerySet(models.query.QuerySet):
def delete(self):
print self
raise
class SingleDeleteManager(models.Manager):
def get_query_set(self):
return MyQuerySet(self.model, using=self._db)
class Receipt(models.Model):
number = models.OneToOneField("ReceiptNumber", blank=True, related_name="receipt", null=True)
vat = models.IntegerField(blank=True)
amount = models.DecimalField(max_digits=10, decimal_places=2, blank=True)
body = models.TextField(blank=True)
date = models.DateField(default=datetime.now, blank=True)
task = models.OneToOneField("Task", related_name="receipt")
objects = SingleDeleteManager()
def total(self):
a = float(self.amount) * (self.vat / 100.0) + float(self.amount)
return "%.2f" % round(a,2)
def vat_amount(self):
a = float(self.amount) * (self.vat / 100.0)
return "%.2f" % round(a,2)
def save(self,*args, **kwargs):
if self.date == None:
self.date = datetime.now()
if self.amount == None:
self.amount = 0
if self.vat == None:
self.vat = self.task.client.default_vat
super(Receipt, self).save(*args, **kwargs)
#if not hasattr(self, "number") or self.number == None:
# new_number = ReceiptNumber.objects.create()
# new_number.number = ReceiptNumber.objects.filter(Q(receipt__task__sender_id=self.sender.id) | Q(milage_receipt__task__sender_id=self.sender.id)).latest('id').number+1
# new_number.save()
# self.number = new_number
# super(Receipt, self).save(*args, **kwargs)
def delete(self, *args, **kwargs):
if hasattr(self,"number") and self.number.id:
self.number.delete()
return super(self.__class__, self).delete(*args, **kwargs)
def get_absolute_url(self):
return reverse('receipt_create_for_task', args=[str(self.task.id)])
def __unicode__(self):
try:
return str(self.number) + ": " + self.task.code
except Task.DoesNotExist:
return "should be gone"
class ReceiptTemplate(models.Model):
name = models.CharField(max_length=255)
vat = models.IntegerField()
amount = models.FloatField()
body = models.TextField()
class MilageReceipt(models.Model):
number = models.OneToOneField("ReceiptNumber", null=True)
sender = models.ForeignKey("Sender")
client = models.ForeignKey("Client")
Run Code Online (Sandbox Code Playgroud)
这是版本1.11!
我找到了一个非常有用的方法来调试这个关于Django由Radek的票.
如果您觉得自己很勇敢,可以在第一行添加调试打印时编辑state_forwards()方法django/db/migrations/operations/fields.py.
def state_forwards(self, app_label, state):
# THIS IS THE LINE TO ADD
print app_label + " " + self.model_name_lower + " " + self.name
# END OF THE LINE TO ADD
new_fields = []
old_field = None
for name, instance in state.models[app_label, self.model_name_lower].fields:
if name != self.name:
new_fields.append((name, instance))
else:
old_field = instance
state.models[app_label, self.model_name_lower].fields = new_fields
# Delay rendering of relationships if it's not a relational field
delay = not old_field.is_relation
state.reload_model(app_label, self.model_name_lower, delay=delay)
Run Code Online (Sandbox Code Playgroud)
然后又跑了./manage.py makemigrations.在崩溃之前,您应该看到使迁移失败的模型的名称.
请注意下面的示例,在崩溃之前要处理的最后一个模型是adsummary在core应用程序上,更具体地说是 account字段.顺便说一句,在找到这个之后我刚刚搜索了应用程序adsummary上的migrations文件夹core,然后发现在其中一个迁移文件中有一个删除此列的命令,尽管该列不再在数据库中,删除了命令并makemigrations重新开始工作.
Felipes-MacBook-Air:backend felipe$ ./manage.py makemigrations -v 3
contenttypes contenttype name
core adsummary account
Traceback (most recent call last):
File "./manage.py", line 22, in <module>
execute_from_command_line(sys.argv)
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/django/core/management/__init__.py", line 363, in execute_from_command_line
utility.execute()
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/django/core/management/__init__.py", line 355, in execute
self.fetch_command(subcommand).run_from_argv(self.argv)
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/django/core/management/base.py", line 283, in run_from_argv
self.execute(*args, **cmd_options)
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/django/core/management/base.py", line 330, in execute
output = self.handle(*args, **options)
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/django/core/management/commands/makemigrations.py", line 150, in handle
loader.project_state(),
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/django/db/migrations/loader.py", line 323, in project_state
return self.graph.make_state(nodes=nodes, at_end=at_end, real_apps=list(self.unmigrated_apps))
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/django/db/migrations/graph.py", line 409, in make_state
project_state = self.nodes[node].mutate_state(project_state, preserve=False)
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/django/db/migrations/migration.py", line 92, in mutate_state
operation.state_forwards(self.app_label, new_state)
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/django/db/migrations/operations/fields.py", line 149, in state_forwards
delay = not old_field.is_relation
AttributeError: 'NoneType' object has no attribute 'is_relation'
Run Code Online (Sandbox Code Playgroud)
这样的事情我也经历过。我认为 Django 1.11 中存在一个错误。我降级到 Django 1.10.7 并顺利运行我的迁移,然后再次升级到 1.11。有 一张开票:
编辑:这确实是一个错误,它仍然存在于 Django 2.1.4 中
找到了解决方法:
打开
/django/db/migrations/operations/fields.py并转到 state_forwards 方法中异常中指示的行delay = not old_field.is_relation,并将行更改为delay = old_field is None or not old_field.is_relation在https://code.djangoproject.com/ticket/28073上找到了 Markus Holtermann 答案的修复 :
我不完全相信你是如何得到该行
delay = not old_field.is_relation与old_field作为None,因为这意味着有与该名称的领域state.models[app_label, self.model_name_lower].fields,但我认为它是安全一起去delay = old_field is None or not old_field.is_relation。
小智 5
正如FamousJameous所说,问题出在RemoveField可能用于迁移的方法上。就我而言,当我试图删除一个未定义的字段时,问题就出现了(例如:我试图删除field_id由关系创建的 ,但定义是 ,正确的是field)。
小智 2
同样的迁移错误也发生在我身上。就我而言,这是由于底层 MySQL 表模式与 models.py 中的模型规范不同步造成的。具体来说,我的表有一列是先前失败的迁移留下的。
我通过手动删除 MySQL 中的列并确保表架构与 models.py 匹配来修复该问题。我删除了导致错误的失败迁移,然后重新执行了已删除的迁移。因为在我运行迁移之前,基础表和 models.py 架构现在已同步,因此迁移过程顺利进行。
我希望这有帮助!
| 归档时间: |
|
| 查看次数: |
7375 次 |
| 最近记录: |