Python 无效的列名';id';在Django
因此,我以不同的方式使用Django模型,我在MS SQL server中有现有的表,我想为我的应用程序访问它们。我一直在学习pluralsights的一些教程 . 我按照相应的步骤操作并准备好了模型,当我使用“migrate”命令时,出现了这个错误 “AssertionError:模型不能有多个自动字段。” 所以我查了一下,得到了Django的另一份文档 默认情况下,Django为每个模型提供以下字段: id=models.AutoField(主键=True) 这是一个自动递增的主键 如果要指定自定义主键,只需指定 primary_key=在一个字段上为True。如果Django看到你 显式设置Field.primary_键,它不会添加自动id 专栏 每个模型只需要一个字段就可以使primary_key=True(或 显式声明或自动添加) 因此,根据他的解决方案,我在没有主键的表中添加了“id”列,并跳过了有主键的表。 我的“迁移”命令运行顺利 但当我尝试测试是否可以从中获取值时,它显示无效列“ID” 现在,我一直在想,如果Django隐式地创建它们,或者当我在模型中显式地创建它们时(然后使用makemigrations和migrate命令),它不应该为它创建列吗 另一种情况: 有些表已经建立了主键,我尝试过对它们进行查询,结果成功了 这让我想如果我错过了这一切之间的一步 这是我的库文件Python 无效的列名';id';在Django,python,sql-server,django,django-models,Python,Sql Server,Django,Django Models,因此,我以不同的方式使用Django模型,我在MS SQL server中有现有的表,我想为我的应用程序访问它们。我一直在学习pluralsights的一些教程 . 我按照相应的步骤操作并准备好了模型,当我使用“migrate”命令时,出现了这个错误 “AssertionError:模型不能有多个自动字段。” 所以我查了一下,得到了Django的另一份文档 默认情况下,Django为每个模型提供以下字段: id=models.AutoField(主键=True) 这是一个自动递增的主键 如果要指
certifi==2016.2.28
Django==1.11.3
django-mssql==1.8
django-pyodbc-azure==1.11.0.0
mysqlclient==1.3.12
PyMySQL==0.7.9
pyodbc==4.0.17
pytz==2017.2
wincertstore==0.2
很抱歉格式错误,但如果我错过了与旧系统连接的任何步骤,请提供帮助。请询问是否需要任何额外信息。谢谢
编辑:如所问,这是我的查询工作的模型
class DjangoSession(models.Model):
session_key = models.CharField(primary_key=True, max_length=40)
session_data = models.TextField()
expire_date = models.DateTimeField()
class Meta:
managed = False
db_table = 'django_session'
这里有一个(许多)不起作用
class table1(models.Model):
id=models.AutoField(primary_key=True)
col2 = models.CharField(db_column='col2', max_length=255, blank=True, null=True) # Field name made lowercase. Field renamed to remove unsuitable characters.
col3 = models.IntegerField(db_column='col3', blank=True, null=True) # Field name made lowercase.
col4 = models.CharField(max_length=250, blank=True, null=True)
col5 = models.DateTimeField(db_column='col5') # Field name made lowercase.
class Meta:
managed = True
db_table = 'table1'
session_key变量已经在表中,因此我不需要为该表创建主键。
然而,由于阅读了各种文档,我添加了id=models.AutoField(primary_key=True)
,我也尝试了创建id的“隐式添加”方法,但它给出了相同的结果
导致此错误的sql shell查询:
from app.models import table1
table1.objects.filter(column_name='col3')
migration.createModel函数如下所示
migrations.CreateModel(
name='VikalpFtrFeatureCr',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('col2', models.CharField(blank=True, db_column='col2', max_length=255, null=True)),
('col3', models.IntegerField(blank=True, db_column='col3', null=True)),
('col4', models.CharField(blank=True, max_length=250, null=True)),
('col5', models.DateTimeField(db_column='UPDATE_DTTM')),
],
options={
'managed': False,
'db_table': 'VIKALP_FTR_Feature_CR',
},
)
基本上,要使遗留数据库/表/视图正常工作,至少需要一个在整个表/视图中唯一的字段 您只需输入正确的字段类型(例如CharField、IntegerField-在我的示例中,我使用了CharField)并在元选项中输入表名,然后将managed设置为False
class YourLegacyModel(models.Model):
id = models.CharField(db_column='unique column', primary_key=True)
class Meta:
db_table = 'your_table'
managed = False
不清楚为什么会出现初始断言错误。我认为你诊断错了,采取了错误的行动。现在我们不知道到底发生了什么,很难进一步帮助你 我建议您备份应用程序的
迁移
文件夹。接下来,我们将您的应用程序称为“msapp”,并在适当的情况下替换它
首先,回滚迁移:
python manage.py migrate msapp zero
python manage.py makemigrations msapp
现在删除所有迁移文件:
rm msapp/migrations/0*.py
然后清除models.py:
rm msapp/models.py && touch msapp/models.py
使用所需表列表运行inspectdb:
python manage.py inspectdb table1 table2 ... >> msapp/models.py
运行makemigrations:
python manage.py migrate msapp zero
python manage.py makemigrations msapp
运行迁移:
python manage.py migrate
现在显示您遇到了什么问题,如果再次遇到断言错误,则显示完全回溯
更新
因此,问题是当没有主键时,Django将向模型添加一个自动创建的字段,,即使模型被标记为非托管。
问题似乎是,人们可以简单地选择一个字段并将其标记为主键,即使它不是主键。这将阻止自动插入ID字段,该字段是在django.db.models.options
中的元类中完成的:
def _prepare():
# ...
if self.pk is None:
if self.parents:
# Promote the first parent link in lieu of adding yet another
# field.
field = next(six.itervalues(self.parents))
# Look for a local field with the same name as the
# first parent link. If a local field has already been
# created, use it instead of promoting the parent
already_created = [fld for fld in self.local_fields if fld.name == field.name]
if already_created:
field = already_created[0]
field.primary_key = True
self.setup_pk(field)
if not field.remote_field.parent_link:
warnings.warn(
'Add parent_link=True to %s as an implicit link is '
'deprecated.' % field, RemovedInDjango20Warning
)
else:
auto = AutoField(verbose_name='ID', primary_key=True, auto_created=True)
model.add_to_class('id', auto)
另一个选项是在处理这些模型时始终使用,这样就永远不会从数据库中查询“id”字段。您可以通过执行以下操作,在当前设置中测试这一点:
table1.objects.filter(column_name='col3').defer('id')
您可以在管理器中进一步抽象:
class NoPkModelManager(models.Manager):
def get_queryset(self):
return super(NoPkModelManager, self).get_queryset().defer('id')
class Table1(models.Model):
objects = NoPkModelManager()
# .. other fields and methods
在添加
自动字段
之前,您是否可以发布一个模型,以及在您将其更改为“我已将'id'列添加到没有主键的表中”之后发布的模型。在您的问题中添加models.py
,我将与模型一起编辑问题,谢谢。看到了托管的
元类属性中的差异吗?1.它不应该是真的,这样django就可以将id列添加到表中吗?2.在面向问题的表格上尝试了managed=False,仍然没有进展我已相应地编辑了问题。我已经创建了整个表中唯一的主键列。我之所以将managed=True,是因为我想对它执行CRUD操作。不是这样的。让managed为false,您也可以执行crud操作。默认情况下,inspectdb创建非托管模型。也就是说,模型的元类中的managed=False告诉Django不要管理每个表的创建、修改和删除:
这是我所指的文档。但是您不想创建新表。我以为你在访问旧数据库?!是的,我正在访问遗留数据库,我现在知道Django指的是表的CRUD,而不是数据的CRUD,我将测试它并返回这里,谢谢!您好,感谢您提供了清晰的步骤,我已经按照您提供的方法进行了尝试,这是我的回溯回溯(最近一次调用):文件“C:\Anaconda3\envs\django\lib\site packages\django\db\backends\utils.py”,第65行,在execute return self.cursor.execute(sql,params)文件中“C:\Anaconda3\envs\django\lib\site packages\sql\pyodbc\base.py”,第545行,在执行返回self.cursor.execute(sql,params)pyodbc.ProgrammingError:('42S22',“[42S22][Microsoft][ODBC sql server驱动程序][sql server]无效的列名'id'(207 SQLExecDirectW)”)
如果需要,我可以提供更多的信息,因为我是Django的新手,我很高兴