【问题标题】:Why can't I save my model instances after editing them?为什么我在编辑模型实例后无法保存它们?
【发布时间】:2011-09-06 07:36:38
【问题描述】:

我有一个模型,我可以很好地实例化它,但是一旦创建,如果我尝试保存它,我会收到一个 IntegrityError,说主键必须是唯一的。这是什么原因造成的?

还有其他从 Node 继承的模型,它们给我带来了同样的问题。

这是我的模型:

class Node(MPTTModel):
    title = models.CharField(max_length=255)
    parent = models.ForeignKey('self', null=True, blank=True,
                               related_name='children')

class Book(Node):
    isbn13 = models.CharField(max_length=14)
    description = models.TextField()

这是它生成的 SQL:

CREATE TABLE "main_node" (
    "id" integer NOT NULL PRIMARY KEY,
    "title" varchar(255) NOT NULL,
    "parent_id" integer,
    "type" varchar(1) NOT NULL,
    "lft" integer unsigned NOT NULL,
    "rght" integer unsigned NOT NULL,
    "tree_id" integer unsigned NOT NULL,
    "level" integer unsigned NOT NULL
)
;
CREATE TABLE "main_book" (
    "node_ptr_id" integer NOT NULL PRIMARY KEY REFERENCES "main_node" ("id"),
    "isbn13" varchar(14) NOT NULL,
    "description" text NOT NULL
)
;

当我尝试保存预先存在的模型实例时会发生什么:

>>> b = Book.objects.create(title='c+ for dummies', isbn13='111-1111111111', description='nt')
>>> b.title='c++ for dummies'
>>> b.save()
Traceback (most recent call last):
  File "<console>", line 1, in <module>
  File "C:\Users\Jackie\Desktop\Code\ProjectName\main\models.py", line 56, in save
    super(Book, self).save(self, *args)
  File "C:\Python27\lib\site-packages\django\db\models\base.py", line 460, in save
    self.save_base(using=using, force_insert=force_insert, force_update=force_update)
  File "C:\Python27\lib\site-packages\django\db\models\base.py", line 553, in save_base
    result = manager._insert(values, return_id=update_pk, using=using)
  File "C:\Python27\lib\site-packages\django\db\models\manager.py", line 195, in _insert
    return insert_query(self.model, values, **kwargs)
  File "C:\Python27\lib\site-packages\django\db\models\query.py", line 1436, in insert_query
    return query.get_compiler(using=using).execute_sql(return_id)
  File "C:\Python27\lib\site-packages\django\db\models\sql\compiler.py", line 791, in execute_sql
    cursor = super(SQLInsertCompiler, self).execute_sql(None)
  File "C:\Python27\lib\site-packages\django\db\models\sql\compiler.py", line 735, in execute_sql
    cursor.execute(sql, params)
  File "C:\Python27\lib\site-packages\django\db\backends\util.py", line 34, in execute
    return self.cursor.execute(sql, params)
  File "C:\Python27\lib\site-packages\django\db\backends\sqlite3\base.py", line 234, in execute
    return Database.Cursor.execute(self, query, params)
IntegrityError: PRIMARY KEY must be unique

这是运行的查询:

>>> for q in connection.queries:
...   print q['sql'] + "\n\n"
...
SELECT MAX("main_node"."tree_id") AS "tree_id__max" FROM "main_node"


INSERT INTO "main_node" ("title", "parent_id", "type", "lft", "rght", "tree_id", "level") VALUES (c+
 for dummies, None, B, 1, 2, 1, 0)


INSERT INTO "main_book" ("node_ptr_id", "isbn13", "description") VALUES (1, 111-1111111111, nt)




SELECT (1) AS "a" FROM "main_node" WHERE "main_node"."id" = 1  LIMIT 1


UPDATE "main_node" SET "title" = c++ for dummies, "parent_id" = NULL, "type" = B, "lft" = 1, "rght"
= 2, "tree_id" = 1, "level" = 0 WHERE "main_node"."id" = 1


INSERT INTO "main_book" ("node_ptr_id", "isbn13", "description") VALUES (1, 111-1111111111, nt)

当我重新保存已经创建的实例时,为什么它试图插入到 main_book 中?

【问题讨论】:

    标签: django django-models django-orm django-mptt


    【解决方案1】:

    您是否在您的任何模型中覆盖了“save()”方法?我有一个类似的问题,经过大量挖掘,发现这是因为我覆盖的“save()”中的一个小错误。

    您能否发布您的全部模型定义? (从生成的SQL来看,你发的好像不完整)

    【讨论】:

    • 我犯了一个错误,即从覆盖的“save()”中将参数“self”传递给对 super.save() 方法的调用,即,我做了类似的事情: super(Tag, self).save(self, *args, **kwargs) // This is wrong 而我需要这样做:super(Tag, self).save(*args, **kwargs) 是的,愚蠢的错误 - 但它让我绊倒了好几个小时!
    【解决方案2】:

    我无法回答您的情况为何不起作用,但我可以建议一种解决方法。

    我对 MPTT 不熟悉,但这是否有效或会导致同样的问题?

    b = Book(title='C+ for Dummies', isbn13='111-1111111111')
    b.save()
    b.title = "C++ for Dummies"
    b.save()
    

    【讨论】:

      【解决方案3】:

      您必须对数据库有一些您不知道的唯一约束,或者您的数据库表的自动增量计数器已重置为某个无效值。

      这个链接似乎很有价值: http://old.nabble.com/Reset-auto-increment---truncate-td16494119.html

      这样想,自动增量计数器正在为您已经存在的主键选择值,因为计数器的值设置为低于表中最后一个条目的值,因此当它选择下一个值时,它选择一个已经存在的值。

      更新:发生了一些奇怪的事情。从您问题中的 SQL 查询来看,它似乎试图再次插入。试试:

      b.save(force_update=True)
      

      这种特殊情况似乎需要force_update=True,但可能是 MPTT 或 Django 代码中的错误。

      【讨论】:

      • 我的数据库是通过 syncdb 新创建的。唯一的限制来自我的模型中的内容以及从 MPTTModel 继承的内容。 Books.object.create 工作正常,所以我真的不知道为什么会出现这个错误。再次保存模型实例应该只更新列(实际上是两个,由于模型继承的工作方式)。
      【解决方案4】:

      尝试比较以下对象,看看是否能发现任何差异:

      b = Book(title='C+ for Dummies', isbn13='111-1111111111')
      

      b = Book.objects.create(title='c+ for dummies', isbn13='111-1111111111', description='nt')
      

      【讨论】:

        猜你喜欢
        • 2022-01-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-03-29
        • 2015-11-21
        • 2017-02-01
        • 2011-09-22
        相关资源
        最近更新 更多