簡體   English   中英

Django 無法修改 SQL 服務器中具有多個主鍵的行

[英]Django unable to modify a row in SQL Server with multiple primary keys

我正在使用Django 3.0DjangoRestFramework 3.12django-mssql-backend 2.8.1來構建當前桌面應用程序的 webapp 版本,該版本將所有內容存儲在舊版 MS SQL 服務器數據庫中。 因此,我僅限於不會改變已經存在的表結構的數據庫修改。

我使用內置的遺留數據庫模型生成器構建了我的 Django 模型,然后自己進行了最終修改。 我一直在按照教程構建一個 API 來處理數據,每個人似乎都建議使用 DRF。 我的所有視圖都使用ListAPIViewRetrieveAPIViewRetrieveUpdateAPIView 現在,當我嘗試構建 API 的一部分以允許我更改其中一個表中的設置時,我遇到了關於插入重復鍵值的錯誤。

數據庫表:

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

Model:

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 服務器數據庫正在使用 LocationID 和 Setting 兩者作為主鍵,但 Django 不允許多個主鍵。

當我前往那個 URL 時,我能夠拉下一個實例。 但是當我 go 更改值時,我只是遇到了關於插入重復鍵的錯誤; 這是不尋常的,因為我沒有創建一個新的鍵值,只是試圖修改一個預先存在的鍵值。

我在此處查看了人們在數據庫中有多個主鍵的其他實例,例如此處此處此處,但他們似乎都提到了使用unique_together ,我有,但沒有提到如何使用那個約束。

有沒有辦法解決這個問題? 還是我需要以某種方式修改舊數據庫?

編輯:我在 SQL 服務器中編寫了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和相同setting名稱和新value的每個SettingValue 似乎它只是為了防止LocationIDSetting重復。

只是為了讓我對我想做的事情一清二楚,這就是我的桌子事先看起來的樣子:

修改前

這是我希望能夠對更新頁面執行的操作:

修改數據庫后

您的錯誤是告訴您您正在嘗試添加/更新數據庫中的一行,該行已經存在於models.py中的unique_together = (('location_id', 'setting'),)約束為避免這種情況,您必須確保您正在添加/更新的值在數據庫中尚不存在。 在您的情況下,錯誤告訴您location_id=3setting='Next Measurement'已經存在。

要解決此問題,請刪除約束並運行遷移,或者在添加/更新這些字段時處理Integrity錯誤。

既然你說

LocationID 和將兩者都設置為主鍵

您還需要將設置字段更新為唯一。

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM