django.db.utils.DatabaseError:ORA-00904:无效的标识符

时间:2019-02-05 15:34:00

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

我正在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 Oracle

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 );

3 个答案:

答案 0 :(得分:0)

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

  

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

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

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

答案 1 :(得分:0)

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

with concurrent.futures.ProcessPoolExecutor(big_number) as executor:
        par_results = executor.map(fnc, (param1, param2, counter))

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

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

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

Django将创建主键列,并将其命名为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,它会给您一个与Django非常相似的错误)。

Django还将通过./manage.py makemigrations # creates the files that create the DB structure ./manage.py migrate. # actually accesses the DB and creates the tables ID设置ForeignKey约束,并使用模型中的字段名称对其进行适当命名。

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

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

答案 2 :(得分:0)

您似乎正在手动创建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.