将任何实例保存到数据库时出现 Django Oracle 完整性错误

发布于 2024-10-16 08:20:02 字数 2800 浏览 4 评论 0原文

我正在从 sqlite 迁移到 oracle 后端。 oracle数据库已经存在并且由其他人维护。其版本是Oracle9i Enterprise Edition Release 9.2.0.1.0。

我有一个简单的模型:

class AliasType(models.Model):
    id = models.AutoField(primary_key=True, db_column="F_ALIAS_ID")
    name = models.CharField(u"Type name", max_length=255, unique=True, db_column="F_ALIAS_NAME")

    class Meta:
        db_table = "ALIAS"

./manage.pysyncdb 不返回任何错误。但是当我尝试创建一个新实例并将其保存到数据库时,出现以下错误:

>>> AliasType.objects.create(name="test")
Traceback (most recent call last):
  File "<console>", line 1, in <module>
  File "/mnt/Data/private/projects/envs/termary-oracle/src/django/django/db/models/manager.py", line 138, in create
    return self.get_query_set().create(**kwargs)
  File "/mnt/Data/private/projects/envs/termary-oracle/src/django/django/db/models/query.py", line 360, in create
    obj.save(force_insert=True, using=self.db)
  File "/mnt/Data/private/projects/envs/termary-oracle/src/django/django/db/models/base.py", line 460, in save
    self.save_base(using=using, force_insert=force_insert, force_update=force_update)
  File "/mnt/Data/private/projects/envs/termary-oracle/src/django/django/db/models/base.py", line 553, in save_base
    result = manager._insert(values, return_id=update_pk, using=using)
  File "/mnt/Data/private/projects/envs/termary-oracle/src/django/django/db/models/manager.py", line 195, in _insert
    return insert_query(self.model, values, **kwargs)
  File "/mnt/Data/private/projects/envs/termary-oracle/src/django/django/db/models/query.py", line 1435, in insert_query
    return query.get_compiler(using=using).execute_sql(return_id)
  File "/mnt/Data/private/projects/envs/termary-oracle/src/django/django/db/models/sql/compiler.py", line 791, in execute_sql
    cursor = super(SQLInsertCompiler, self).execute_sql(None)
  File "/mnt/Data/private/projects/envs/termary-oracle/src/django/django/db/models/sql/compiler.py", line 735, in execute_sql
    cursor.execute(sql, params)
  File "/mnt/Data/private/projects/envs/termary-oracle/src/django/django/db/backends/util.py", line 18, in execute
    return self.cursor.execute(sql, params)
  File "/mnt/Data/private/projects/envs/termary-oracle/src/django/django/db/backends/oracle/base.py", line 630, in execute
    return self.cursor.execute(query, self._param_generator(params))
IntegrityError: ORA-01400: cannot insert NULL into ("SINCE"."ALIAS"."F_ALIAS_ID")

如果我指定 id,例如 AliasType.objects.create(id=5, name="test"),它有效。我认为 django 应该能够自动检索 id 值。我了解到Oracle不支持自动增量,我应该使用触发器和序列。有人告诉我,数据库中有一个现有序列,它返回所有新行的 id,并且我知道它的名称,例如 SEQ_GET_NEW_ID

所以问题是如何以最优雅的方式实现它,即如何告诉 Django 从名为 SEQ_GET_NEW_ID 的序列中获取所有新对象的 id 值,而不需要对其进行太多修改(例如覆盖 save()所有模型的方法)?

I'm doing a migration from sqlite to oracle backend. The oracle database already exists and is maintained by other people. Its version is Oracle9i Enterprise Edition Release 9.2.0.1.0.

I have a simple model:

class AliasType(models.Model):
    id = models.AutoField(primary_key=True, db_column="F_ALIAS_ID")
    name = models.CharField(u"Type name", max_length=255, unique=True, db_column="F_ALIAS_NAME")

    class Meta:
        db_table = "ALIAS"

./manage.py syncdb does not return any errors. But when I try to create a new instance and save it to the database, I get the following error:

>>> AliasType.objects.create(name="test")
Traceback (most recent call last):
  File "<console>", line 1, in <module>
  File "/mnt/Data/private/projects/envs/termary-oracle/src/django/django/db/models/manager.py", line 138, in create
    return self.get_query_set().create(**kwargs)
  File "/mnt/Data/private/projects/envs/termary-oracle/src/django/django/db/models/query.py", line 360, in create
    obj.save(force_insert=True, using=self.db)
  File "/mnt/Data/private/projects/envs/termary-oracle/src/django/django/db/models/base.py", line 460, in save
    self.save_base(using=using, force_insert=force_insert, force_update=force_update)
  File "/mnt/Data/private/projects/envs/termary-oracle/src/django/django/db/models/base.py", line 553, in save_base
    result = manager._insert(values, return_id=update_pk, using=using)
  File "/mnt/Data/private/projects/envs/termary-oracle/src/django/django/db/models/manager.py", line 195, in _insert
    return insert_query(self.model, values, **kwargs)
  File "/mnt/Data/private/projects/envs/termary-oracle/src/django/django/db/models/query.py", line 1435, in insert_query
    return query.get_compiler(using=using).execute_sql(return_id)
  File "/mnt/Data/private/projects/envs/termary-oracle/src/django/django/db/models/sql/compiler.py", line 791, in execute_sql
    cursor = super(SQLInsertCompiler, self).execute_sql(None)
  File "/mnt/Data/private/projects/envs/termary-oracle/src/django/django/db/models/sql/compiler.py", line 735, in execute_sql
    cursor.execute(sql, params)
  File "/mnt/Data/private/projects/envs/termary-oracle/src/django/django/db/backends/util.py", line 18, in execute
    return self.cursor.execute(sql, params)
  File "/mnt/Data/private/projects/envs/termary-oracle/src/django/django/db/backends/oracle/base.py", line 630, in execute
    return self.cursor.execute(query, self._param_generator(params))
IntegrityError: ORA-01400: cannot insert NULL into ("SINCE"."ALIAS"."F_ALIAS_ID")

If I specify id, e.g. AliasType.objects.create(id=5, name="test"), it works. I thought django should be able to retrieve id value automatically. I've learnt that Oracle does not support autoincrement, and I should use triggers and sequences. I was told that there is an existing sequence in the database that returns ids for all new rows, and I know its name, say SEQ_GET_NEW_ID.

So the question is how to implement that in the most elegant way, i.e. how to tell Django to get id values for all new objects from the sequence named SEQ_GET_NEW_ID without hacking it too much (e.g. overriding save() methods for all models)?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

黎夕旧梦 2024-10-23 08:20:02

有一个打开的票证(#1946)完全允许这样做,覆盖默认的序列名称。但由于它还没有关闭,我认为没有办法不黑客攻击。

我以前没有使用过 Oracle,但快速搜索表明可以为序列创建别名/同义词。 manage.py sqlall 应该显示 Django 期望的序列名称。因此,您可能可以将其设为 SEQ_GET_NEW_ID 的别名。

There is a ticket open (#1946) to allow exactly that, overriding the default sequence name. But as it's not closed yet, I don't think there is a way without hacking.

I haven't used Oracle before, but a quick search suggests that it is possible to create aliases/synonyms for sequences. manage.py sqlall <app> should show you the sequence name Django is expecting. So you probably could just make this an alias for SEQ_GET_NEW_ID.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文