Django 模型尝试自动创建一个主键字段,即使它已经被指定
Django model tries to auto-create a primary key field even though it is already specified
Django 文档中说明每个模型都需要一个主键。在我的 MySQL 模式中,我的 table 指定主键由多列组成。使用 inspectdb 自动生成模型会创建 unique_together 元信息。
class Connections(models.Model):
router = models.ForeignKey('Routers', models.CASCADE)
src_mac = models.CharField(db_column='src_MAC', max_length=17) # Field name made lowercase.
src_ip = models.CharField(max_length=45, blank=True, null=True)
src_port = models.CharField(max_length=45)
dest_mac = models.CharField(db_column='dest_MAC', max_length=17, blank=True, null=True) # Field name made lowercase.
dest_ip = models.CharField(max_length=45)
dest_port = models.CharField(max_length=45)
first_activity = models.DateTimeField(blank=True, null=True)
last_activity = models.DateTimeField(blank=True, null=True)
hits_counter = models.IntegerField(blank=True, null=True)
def __unicode__(self):
return self.src_ip
class Meta:
db_table = 'Connections'
unique_together = (('router', 'src_mac', 'src_port', 'dest_ip', 'dest_port'),)
当我去运行
> python manage.py shell
>>> Connections.objects.all()
它给我 OperationalError: (1054, "Unknown column 'Connections.id' in 'field list'") 据我了解,这意味着 Django 正在尝试为 Connections 自动创建主键列。
我该如何解决这个问题?
tl;dr:重新创建 table 或手动将 "id" 字段添加到数据库。
我认为不可能在所有数据库中创建主键。
例如,当使用 SQLite 时,如果我创建了您的 table 的简化版本,将其更改为添加 PK returns 错误:
> CREATE TABLE connections(src_MAC CHAR(17) NOT NULL, first_activity DATETIME NULL);
> INSERT INTO connections VALUES ('abcd1234',date('now'));
> ALTER TABLE connections add column id integer NOT NULL PRIMARY KEY AUTOINCREMENT;
Error: Cannot add a PRIMARY KEY column
类似地,运行 使用 SQLite 创建字段的 Django 迁移无法自动添加字段(可能是 Django 问题)。
如果你运气不好,使用的数据库不支持添加主键(如果你不确定,请检查运行 ALTER
命令),最好的办法是转储 table 数据,删除 table,创建一个带有主键的新 table,最后重新加载 table数据。这似乎也是最安全的方式。
另一方面,如果您确实使用了支持添加主键的数据库,您可以尝试进行迁移或手动更改数据库。
在 Postgres 中手动创建 id 字段非常简单:
ALTER TABLE connections ADD COLUMN id SERIAL PRIMARY KEY;
这足以使模型在 Django 中可用。现在进入艰难的道路。
似乎 makemigrations
假定 ID 字段已经存在,因此如果您选择使用迁移,初始迁移将需要修复(删除 id 字段)。您可以这样手动创建 CreateField 迁移:
migrations/0002_connections_id.py
# -*- coding: utf-8 -*-
# Generated by Django 1.9.7 on 2016-07-08 08:56
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('testapp', '0001_initial'),
]
operations = [
migrations.AddField(
model_name='connections',
name='id',
field=models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
),
]
不幸的是,这似乎还不够,因为创建的列不会自动递增(可能 另一个 Django 问题)。现在的解决方案是像这样更改创建的字段:
> ALTER TABLE connections ALTER id SET default nextval('connections_id_seq');
最终这些值对 Django 有意义,您现在可以像往常一样查询和创建 "Connections" 个实例。
以防万一有人以后需要这个,我已经将我用来测试这个的代码推送到 this GitHub repo。
Django 文档中说明每个模型都需要一个主键。在我的 MySQL 模式中,我的 table 指定主键由多列组成。使用 inspectdb 自动生成模型会创建 unique_together 元信息。
class Connections(models.Model):
router = models.ForeignKey('Routers', models.CASCADE)
src_mac = models.CharField(db_column='src_MAC', max_length=17) # Field name made lowercase.
src_ip = models.CharField(max_length=45, blank=True, null=True)
src_port = models.CharField(max_length=45)
dest_mac = models.CharField(db_column='dest_MAC', max_length=17, blank=True, null=True) # Field name made lowercase.
dest_ip = models.CharField(max_length=45)
dest_port = models.CharField(max_length=45)
first_activity = models.DateTimeField(blank=True, null=True)
last_activity = models.DateTimeField(blank=True, null=True)
hits_counter = models.IntegerField(blank=True, null=True)
def __unicode__(self):
return self.src_ip
class Meta:
db_table = 'Connections'
unique_together = (('router', 'src_mac', 'src_port', 'dest_ip', 'dest_port'),)
当我去运行
> python manage.py shell
>>> Connections.objects.all()
它给我 OperationalError: (1054, "Unknown column 'Connections.id' in 'field list'") 据我了解,这意味着 Django 正在尝试为 Connections 自动创建主键列。 我该如何解决这个问题?
tl;dr:重新创建 table 或手动将 "id" 字段添加到数据库。
我认为不可能在所有数据库中创建主键。 例如,当使用 SQLite 时,如果我创建了您的 table 的简化版本,将其更改为添加 PK returns 错误:
> CREATE TABLE connections(src_MAC CHAR(17) NOT NULL, first_activity DATETIME NULL);
> INSERT INTO connections VALUES ('abcd1234',date('now'));
> ALTER TABLE connections add column id integer NOT NULL PRIMARY KEY AUTOINCREMENT;
Error: Cannot add a PRIMARY KEY column
类似地,运行 使用 SQLite 创建字段的 Django 迁移无法自动添加字段(可能是 Django 问题)。
如果你运气不好,使用的数据库不支持添加主键(如果你不确定,请检查运行 ALTER
命令),最好的办法是转储 table 数据,删除 table,创建一个带有主键的新 table,最后重新加载 table数据。这似乎也是最安全的方式。
另一方面,如果您确实使用了支持添加主键的数据库,您可以尝试进行迁移或手动更改数据库。
在 Postgres 中手动创建 id 字段非常简单:
ALTER TABLE connections ADD COLUMN id SERIAL PRIMARY KEY;
这足以使模型在 Django 中可用。现在进入艰难的道路。
似乎 makemigrations
假定 ID 字段已经存在,因此如果您选择使用迁移,初始迁移将需要修复(删除 id 字段)。您可以这样手动创建 CreateField 迁移:
migrations/0002_connections_id.py
# -*- coding: utf-8 -*-
# Generated by Django 1.9.7 on 2016-07-08 08:56
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('testapp', '0001_initial'),
]
operations = [
migrations.AddField(
model_name='connections',
name='id',
field=models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
),
]
不幸的是,这似乎还不够,因为创建的列不会自动递增(可能 另一个 Django 问题)。现在的解决方案是像这样更改创建的字段:
> ALTER TABLE connections ALTER id SET default nextval('connections_id_seq');
最终这些值对 Django 有意义,您现在可以像往常一样查询和创建 "Connections" 个实例。
以防万一有人以后需要这个,我已经将我用来测试这个的代码推送到 this GitHub repo。