Django无法用多个主键修改SQL Server中的一行



我正在使用Django 3.0DjangoRestFramework 3.12django-mssql-backend 2.8.1来构建当前桌面应用程序的Web应用程序版本,该版本将所有内容存储在遗留的MS SQL Server数据库中。由于这一点,我只能修改数据库,而不会改变已经存在的表结构。

我使用内置的遗留数据库模型生成器构建了Django模型,然后自己进行了最后的修改。我一直在学习构建API来处理数据的教程,似乎每个人都建议使用DRF。我的所有视图都使用ListAPIViewRetrieveAPIViewRetrieveUpdateAPIView。现在,当我试图构建API的一部分以允许我更改其中一个表中的设置时,我遇到了一个关于插入重复键值的错误。

数据库表:

dbo.systemDateTimeSettings
- LocationID (PK, FK, int, not null)  
- Setting (PK, nvarchar(50), not null)
- Value (datetime, null)

型号:

class SystemDatetimeSettings(models.Model):
location_id = models.OneToOneField(Locations, models.DO_NOTHING, db_column='LocationID', primary_key=True)
setting = models.CharField(db_column='Setting', max_length=50)
value = models.DateTimeField(db_column='Value', blank=True, null=True)

def get_api_url(self, request=None):
return reverse("api:datetime-settings-update",
kwargs={
'location_id': int(self.location_id.location_id),
'setting': self.setting
},
request=request)
class Meta:
managed = False
db_table = 'SystemDateTimeSettings'
unique_together = (('location_id', 'setting'),)

序列化程序:

class SystemDatetimeSettingsSerializer(serializers.ModelSerializer):
url = serializers.SerializerMethodField(read_only=True)

class Meta:
model = SystemDatetimeSettings
fields = [
'url',
'location_id',
'setting',
'value'
]
read_only_fields = [
'location_id',
'setting',
]

def get_url(self, obj):
request = self.context.get("request")
return obj.get_api_url(request=request)

Url:

path('locations/<int:location_id>/settings/datetime/<str:setting>/update', DatetimeSettingsUpdate.as_view(), name='datetime-settings-update'),

视图:

class DatetimeSettingsUpdate(RetrieveUpdateAPIView):
lookup_field        = 'setting'
serializer_class    = SystemDatetimeSettingsSerializer
permission_classes  = [permissions.IsAuthenticated]
# queryset            = SystemDatetimeSettings.objects.all()

def get_object(self):
location_id = self.kwargs.get('location_id')
setting = self.kwargs.get('setting')
return get_object_or_404(SystemDatetimeSettings, location_id=location_id, setting=setting)

我得到的错误是:

IntegrityError at /api/locations/3/settings/datetime/Next Measurement/update
('23000', "[23000] [Microsoft][ODBC Driver 13 for SQL Server][SQL Server]Violation of PRIMARY KEY constraint 'aaaaaSystemDateTimeSettings_PK'. Cannot insert duplicate key in object 'dbo.SystemDateTimeSettings'. The duplicate key value is (3, Next Measurement). (2627) (SQLExecDirectW); [23000] [Microsoft][ODBC Driver 13 for SQL Server][SQL Server]The statement has been terminated. (3621)")

我从中了解到,真正的根本问题是SQL Server数据库使用LocationID和Setting作为主键,但Django不允许使用多个主键。

当我指向那个URL时,我能够拉下一个实例。但当我去更改值时,我只遇到了插入重复密钥的错误;这是不寻常的,因为我并没有创建一个新的键值,只是试图修改一个预先存在的键值。

我在这里查看了其他一些例子,其中人们在数据库中有多个主键,比如这里、这里和这里,但他们似乎都提到了使用unique_together,我有,但没有提到如何使用该约束。

有什么办法解决这个问题吗?或者我是否需要以某种方式修改旧数据库?

EDIT:我在SQL Server中编写了aaaaaSystemDateTimeSettings_PK约束的脚本,得到了:

ALTER TABLE [dbo].[SystemDateTimeSettings] ADD  CONSTRAINT [aaaaaSystemDateTimeSettings_PK] PRIMARY KEY CLUSTERED 
(
[LocationID] ASC,
[Setting] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
GO

我尝试删除约束(本地副本-不要惊慌(,然后尝试更新页面。它遍历但覆盖了具有相同LocationID的每个SettingValue,并使用相同的setting名称和新的value。它似乎只是为了防止LocationIDSetting一起重复。

为了让我清楚地知道我要做什么,以下是我之前的表格:

修改之前

以下是我希望能够对更新页面进行的操作:

修改数据库后

您的错误告诉您,您正试图在数据库中添加/更新一行,该行已存在models.py中的unique_together = (('location_id', 'setting'),)约束。要避免这种情况,您必须确保正在添加/更新的值在数据库中不存在。在您的情况下,错误会告诉您location_id=3setting='Next Measurement'已经存在。

要解决此问题,请删除约束并运行迁移,或者在添加/更新这些字段时处理Integrity错误。

既然你说

LocationID和Setting二者都作为主键

您还需要更新设置字段以使其唯一。

setting = models.CharField(db_column='Setting', max_length=50, unique=True)

最新更新