Django中的列名“id”无效

时间:2017-09-20 11:43:19

标签: python sql-server django django-models

所以我以不同的方式使用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',
            },
        )

2 个答案:

答案 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