阻止Django更新MSSQL中的标识列



我正在使用MSSQL中的遗留DB。我们有一个表,其中有两列导致我的问题:

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语句的方式。如果有人有更好的方法或可以解释为什么这是不好的做法,我会很高兴听到它!

这个问题很老了,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])

最新更新