【问题标题】:django.db.utils.DatabaseError: ORA-00904: invalid identifierdjango.db.utils.DatabaseError: ORA-00904: 标识符无效
【发布时间】:2019-06-29 11:27:27
【问题描述】:

我在 django 1.11 上运行应用程序并作为 Oracle Database 11G XE 数据库引擎。我有 3 个表 producto、catalogo 和 catalogo_producto。 catalogo_producto 表是producto 和catalogo 之间的中间表。迁移表的时候没有问题,但是想创建对象的时候出现如下错误django.db.utils.DatabaseError: ORA-00904: "CATALOGO_PRODUCTO". "ID": invalid identifier.

我知道这个错误是指我没有在模型中分配任何主键,但是遵循 django 文档Extra fields on many-to-many relationships 对于这些情况,主键没有分配给特定字段。我也明白,在这些情况下,django 会创建一个模型中未显示的 PK“ID”。所以我不知道正确的解决方案是简单地在catalogo_producto表中创建一个id字段还是有其他解决方案?

models.py

class Producto(models.Model):
    codigo = models.IntegerField(primary_key=True)
    precio = models.IntegerField()
    nombre = models.CharField(max_length=100)
    tipo = models.CharField(max_length=25)
    cantidad = models.IntegerField()

    class Meta:
        db_table = 'producto'

    def __str__(self):
        return str(self.codigo)

class Catalogo(models.Model):
    codigo = models.AutoField(primary_key=True)
    descripcion = models.CharField(max_length=250)
    fecha = models.DateField()
    productos = models.ManyToManyField(Producto, through='CatalogoProducto')

    class Meta:
        db_table = 'catalogo'

    def __str__(self):
        return str(self.codigo)

class CatalogoProducto(models.Model):
    catalogo_codigo = models.ForeignKey(Catalogo, models.DO_NOTHING, db_column='catalogo_codigo')
    producto_codigo = models.ForeignKey(Producto, models.DO_NOTHING, db_column='producto_codigo')
    posicion = models.IntegerField()
    precio = models.IntegerField()
    imagen_producto = models.ImageField(upload_to="images/", default='')

    class Meta:
        db_table = 'catalogo_producto'
        unique_together = (('catalogo_codigo', 'producto_codigo'),)

DDL 预言机

CREATE TABLE producto (
codigo     NUMBER(6) NOT NULL,
precio     NUMBER(8) NOT NULL,
nombre     VARCHAR2(100) NOT NULL,
tipo       VARCHAR2(25) NOT NULL,
cantidad   NUMBER(6) NOT NULL
);

ALTER TABLE producto ADD CONSTRAINT producto_pk PRIMARY KEY ( codigo );

CREATE TABLE catalogo (
codigo        NUMBER(6) NOT NULL,
descripcion   VARCHAR2(250) NOT NULL,
fecha         DATE NOT NULL);

ALTER TABLE catalogo ADD CONSTRAINT catalogo_pk PRIMARY KEY ( codigo );

CREATE TABLE catalogo_producto (
catalogo_id       NUMBER(6) NOT NULL,
producto_id       NUMBER(6) NOT NULL,
posicion          NUMBER(4) NOT NULL,
precio            NUMBER(8) NOT NULL,
imagen_producto   VARCHAR2(250) NOT NULL
);

ALTER TABLE catalogo_producto ADD CONSTRAINT catálogo_producto_pk PRIMARY KEY(catalogo_id, producto_id);

ALTER TABLE catalogo_producto
ADD CONSTRAINT cat_prod_catalogo_fk FOREIGN KEY ( catalogo_id )
    REFERENCES catalogo ( codigo );

ALTER TABLE catalogo_producto
ADD CONSTRAINT cat_prod_producto_fk FOREIGN KEY ( producto_id )
REFERENCES producto ( codigo );

【问题讨论】:

  • 您如何尝试在 CatalogoProducto 中创建记录?当您使用直通模型时,您必须手动创建对象...
  • 首先我创建了一个产品然后是一个目录,当我尝试在 CatalogoProducto 中创建记录时出现错误。我通过管理员所做的一切。
  • 您能否提供Oracle 中表catalogo_producto 的表描述(所有列和约束的列表)。主键列应由 Django 自动创建,名称为“ID”。您可以覆盖它,但这不是必需的。这个表以前存在吗?你是否运行过 makemigrations/migrate 没有错误?
  • @Risadinha 当我进行迁移时,没有发生错误。仅当我尝试从管理员那里在 CatalogoProducto 中添加记录时。我已经共享了 oracle DDL

标签: python django-models oracle11g many-to-many


【解决方案1】:

我在 django 项目上发现了这个问题,这可能是答案:

这里没有错误。默认情况下,Django 希望模型 Foo 和 Bar 之间的连接表的列名是 foo_id 和 bar_id。中间表的列没有被调用,因此在尝试对中间(连接)表执行 SQL 时会引发错误。 为了解决这个问题,手动构建中间表,指定 db 列的名称,并在 ManyToManyField 上使用新的 through 参数来指定中间模型。

所以,我认为您必须更改中间模型中的列名:

https://code.djangoproject.com/ticket/8339

【讨论】:

  • 问题是当我首先通过脚本从 oracle 创建数据库,然后从 django 执行迁移时。我要解决的是使用 python manage.py inspectdb> models.py 获取模型,然后使用已经为我工作的迁移。我想当脚本已经定义了一些表时发生了一些错误。
【解决方案2】:

您似乎正在手动创建主键和外键。

ALTER TABLE producto ADD CONSTRAINT producto_pk PRIMARY KEY ( codigo );
ALTER TABLE catalogo ADD CONSTRAINT catalogo_pk PRIMARY KEY ( codigo );
ALTER TABLE catalogo_producto
ADD CONSTRAINT cat_prod_catalogo_fk FOREIGN KEY ( catalogo_id )
    REFERENCES catalogo ( codigo );

ALTER TABLE catalogo_producto
ADD CONSTRAINT cat_prod_producto_fk FOREIGN KEY ( producto_id )
REFERENCES producto ( codigo );

您将外键指向不存在的主键。这甚至是由 Oracle 创建的吗? (或者也许我误读了。)

也许您是在自己的 SQL 脚本中创建这些,或者它们已经被创建。

通常,在 Django 中,您不需要自己编写用于创建表的 SQL 脚本,而是编写模型然后运行:

./manage.py makemigrations # creates the files that create the DB structure
./manage.py migrate. # actually accesses the DB and creates the tables

Django 将创建主键列,将它们命名为ID。一般来说,您需要这些列进行连接(您将无法在当前约束下加入 Oracle,它应该会给您一个与您从 Django 获得的错误非常相似的错误)。

Django 还将通过 makemigrationsmigrate 设置 ForeignKey 约束,并使用模型中的字段名称适当地命名它们。

如果允许您创建自己的表,请从您的代码中删除所有db_* 参数并运行makemigrations,因为您不必费心检查重复的表名。让 Django 尽你所能完成工作。

Django 迁移将帮助您跟踪随着时间的推移对模型所做的更改以及需要反映在数据库结构中的更改。使用 Django 的原因之一正是因为您不想手动维护它。见https://docs.djangoproject.com/en/2.1/topics/migrations/

【讨论】:

  • 以前我有那些名为 catalogo 和 producto 的列,但我根据这张票 code.djangoproject.com/ticket/8339 的响应修改了它们,对于这种情况,我使用 python manage.py inspectdb> 模型生成模型。 py
  • 您真的需要自己命名数据库表和列吗?你不能只使用 Django 约定吗?如果您的应用程序增长,您将有很多额外的工作。 (一旦你拥有 50 多个具有数百个字段和交叉关系的模型,你真的不想再自己进行微观管理了,如果没有人推动你这样做。)
  • 问题是当我首先通过脚本从 oracle 创建数据库,然后从 django 执行迁移时。我要解决的是使用 python manage.py inspectdb> models.py 获取模型,然后使用已经为我工作的迁移。我想当脚本已经定义了一些表时发生了一些错误。感谢您的帮助。
  • @alejandrodxf - 如果您是定义表的人(并且您不需要使用与其他非 Django 应用程序共享的现有表),那么:dropdb , createdb ,删除应用程序中所有现有的迁移文件,执行makemigrations,然后执行migrate。不要自己创建任何表格。
  • 我必须同意@Risadinha...如果您打算长时间使用django 应用程序,最好的办法是依赖数据库结构进行迁移。
【解决方案3】:

看起来您是手动创建 DDL 或其他方式,因为如果您深入研究迁移文件,您会看到 django 想要创建 id 字段:

    migrations.CreateModel(
        name='CatalogoProducto',
        fields=[
            ('id', models.AutoField(auto_created=True,                 #<---- here!!!
                                    primary_key=True, serialize=False, 
                                    verbose_name='ID')),
            ('posicion', models.IntegerField()),
            ('precio', models.IntegerField()),
            ('catalogo_codigo', models.ForeignKey(db_c...

检查您是否从迁移创建表两次:

python manage.py makemigrations
python manage.py migrate   #<-------- this one creates the tables.

【讨论】:

  • 是的,问题在于它首先从 oracle 中的脚本创建表,然后执行迁移。
  • Pues la gracia de las migraciones está en no tener que escribir el DDL, ya sabes, DRY(不要重复自己)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-08-08
  • 2022-01-22
  • 2011-08-27
  • 2011-04-21
  • 2013-10-20
  • 2017-12-29
  • 2015-07-25
相关资源
最近更新 更多