防止Django更新MSSQL中的标识列

时间:2011-08-23 09:04:40

标签: sql-server django django-models pyodbc django-pyodbc

我正在使用MSSQL中的遗留数据库。我们有一个表有两列导致我出现问题的表:

class Emp(models.Model):  
    empid = models.IntegerField(_("Unique ID"), unique=True, db_column=u'EMPID')  
    ssn = models.CharField(_("Social security number"), max_length=10, primary_key=True, db_column=u'SSN') # Field name made lowercase.  

因此该表将ssn列作为主键,并且django生成的SQL更新代码的相关部分是:

UPDATE [EMP] SET [EMPID] = 399, 
......... 
WHERE [EMP].[SSN] = 2509882579 

问题是EMP.EMPID是MSSQL中的标识字段,因此每当我尝试将更改保存到现有员工时,pyodbc都会抛出此错误:

ProgrammingError: ('42000', "[42000] [Microsoft][SQL Native Client][SQL Server]C
annot update identity column 'EMPID'. (8102) (SQLExecDirectW); [42000] [Microsof
t][SQL Native Client][SQL Server]Statement(s) could not be prepared. (8180)")

将EMP.EMPID作为标识对于程序的任何内容都不是至关重要的,因此通过创建临时列并复制,删除,重命名来删除它似乎是合乎逻辑的事情。这为将旧客户转移到Django创造了一个额外的步骤,所以我的问题是,有没有办法阻止Django在我对这个表进行更新时生成'[EMPID] = XXX'片段?

修改
我修补了我的模型:

def save(self, *args, **kwargs):
    if self.empid:
        self._meta.local_fields = [f for f in self._meta.local_fields if f.name != 'empid']
        super().save(*args, **kwargs)

这很有效,利用Django在django / db / models / base.py(525)中填充sql-sentence的方式。如果有人有更好的方法或者可以解释为什么这是不好的做法我会很高兴听到它!

1 个答案:

答案 0 :(得分:3)

这个问题已经过时了,Sindri找到了一个可行的解决方案,但我想提供一个我已经在生产中使用了几年的解决方案,这个解决方案不需要在_meta中解决。

我必须编写一个与包含许多计算字段的现有业务数据库集成的Web应用程序。这些字段通常计算记录的状态,几乎每个对象都可以访问整个应用程序,Django必须能够使用它们。

这些类型的字段可用于模型管理器,该管理器使用extra(select=...)将所需字段添加到查询中。

ComputedFieldsManager代码段:https://gist.github.com/manfre/8284698

class Emp(models.Model):
    ssn = models.CharField(_("Social security number"), max_length=10, primary_key=True, db_column=u'SSN') # Field name made lowercase.

    objects = ComputedFieldsManager(computed_fields=['empid'])


# the empid is added on to the model instance
Emp.objects.all()[0].empid

# you can also search on the computed field
Emp.objects.all().computed_field_in('empid', [1234])