python - 如何追踪这个?属性错误 : 'NoneType' object has no attribute 'is_relation' during makemigrations

标签 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>

这是我的 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")

这是 1.11 版!

最佳答案

我在 this ticket on Django 上找到了一种非常有用的调试方法拉德克。

如果你够勇敢,你可以编辑 django/db/migrations/operations/fields.py 上的 state_forwards() 方法,在第一行添加调试打印.

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)

然后再次运行./manage.py makemigrations。在崩溃之前,您应该会看到导致迁移失败的模型的名称。

请注意下面的示例,崩溃前要处理的最后一个模型是 core 应用程序上的 adsummary,更具体地说是 account 字段.顺便说一句,找到这个之后我只是在 core 应用程序的 migrations 文件夹中搜索 adsummary ,然后发现有一个命令为了在其中一个迁移文件中删除此列,尽管该列不再存在于数据库中,删除了此命令并且 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'

关于python - 如何追踪这个?属性错误 : 'NoneType' object has no attribute 'is_relation' during makemigrations,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43765732/

相关文章:

python - Django 子查询先前记录的子集

mysql - Django 中用于 sql join 的等效 ORM 查询是什么

python - Django : NOT NULL constraint failed: mainapp_comment. post_id 中导致此错误的原因是什么

python - 找到最重复的! np.数组!在列表中

python - 求不同年份同一日期的平均值

python - pygame混音器点击声音

django - Django 中是否有与 login_required 等效的 logout_required ?

python - ipython 控制台中的语法高亮显示

python - django 1.8-如果表单条目查询结果与数据库不匹配,则在同一页面上显示警报消息,而不是 "None"或引发异常页面

python - 我正在尝试将我的 Django 应用程序与 Mysql 数据库连接,但是当我尝试迁移负载时,终端中开始弹出错误。