所以我以不同的方式使用Django模型,我在MS SQL服务器中有现有的表,我想为我的应用程序访问它们。我一直在关注多个教程中的一些教程 https://docs.djangoproject.com/en/1.11/howto/legacy-databases/。我相应地遵循了这些步骤并准备好了我的模型,当我使用'migrate'命令时,我得到了这个错误
“AssertionError:模型不能有多个AutoField。”
所以我查了一下,得到了Django的另一份文件
默认情况下,Django为每个模型提供以下字段:
id = models.AutoField(primary_key = True)
这是一个自动递增的主键。
如果您想指定自定义主键,请指定 其中一个字段的primary_key = True。如果Django看到你了 显式设置Field.primary_key,它不会添加自动id 列。
每个模型只需要一个字段即可使primary_key = True(或者 明确声明或自动添加)。
所以通过他的解决方案,我已经将'id'列添加到没有主键的表中,并跳过那些具有主键的表。 我的“迁移”命令顺利进行。
但是当我试图测试是否可以从中获取值时,它会显示无效列'ID'
现在,我一直在思考自己,如果Django隐式地创建它们,或者当我在模型中明确地创建它们(然后使用makemigrations和migrate命令)时,它不应该为它创建列吗?
另一种情况: 有一些表已经建立了主键,我已经尝试了对它们的查询并且它有效。
这让我想到如果我错过了所有这些之间的一步,
这是我的lib文件
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',
},
)
答案 0 :(得分:1)
目前还不清楚为什么会出现初始断言错误。我认为你错误地诊断了它并采取了错误的行动。现在我们无法分辨真正发生的事情,而且很难帮助你。
我建议您备份应用的migrations
文件夹。让我们打电话给您的应用程序" msapp"对于其余部分并在适当的时候替换它。
首先,回滚迁移:
python manage.py migrate msapp zero
现在删除所有迁移文件:
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 makemigrations msapp
运行迁移:
python manage.py migrate
现在显示您遇到的问题以及完整追溯如果再次遇到断言错误。
所以问题是当没有主键时,Django会向模型添加一个自动创建的字段,即使模型被标记为非托管。
consensus似乎只是选择一个字段并将其标记为主键,即使它不是一个。这将阻止自动插入的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)
另一种选择是在处理这些模型时始终使用defer,以便' 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
答案 1 :(得分:0)
基本上,要使旧数据库/表/视图正常工作,您至少需要一个在表/视图中唯一的字段。
你只需要输入正确的字段类型(例如CharField,IntegerField - 在我的例子中我使用过CharField)并在Meta选项中输入表名并设置为False。
class YourLegacyModel(models.Model):
id = models.CharField(db_column='unique column', primary_key=True)
class Meta:
db_table = 'your_table'
managed = False