Django创建Location模型时出现重复键错误的问题排查
我定义了一个Location模型,其中city字段关联City模型,数据库已预先填充国家、州/省和城市数据,创建新Location时只需选择对应城市即可。
Location模型代码:
class Location(models.Model): name = models.CharField(max_length=50, default=None, null=True, blank=True) street = models.CharField(max_length=100) additional = models.CharField(max_length=100, null=True, blank=True) city = models.OneToOneField(City, on_delete=models.CASCADE, related_name="cities") zip_code = models.CharField(max_length=30) phone = models.CharField(max_length=15, null=True, blank=True) user = models.ForeignKey(User, on_delete=models.CASCADE, null=True, blank=True) created_at = models.DateTimeField(auto_now_add=True, verbose_name="created at") updated_at = models.DateTimeField(auto_now=True, verbose_name="updated at") class Meta: verbose_name = "location" verbose_name_plural = "locations" db_table = "locations" ordering = ["zip_code"] def __str__(self): return self.name def get_absolute_url(self): return self.slug
我尝试通过Patch请求中的update_or_create方法更新或创建Location,视图代码如下:
class UpdateUserSettings(generics.UpdateAPIView): permission_classes = [permissions.IsAuthenticated] serializer_class = SettingsSerializer name = 'user-settings' def get_queryset(self): id = self.kwargs['pk'] return UserSettings.objects.all().filter(user=id) def patch(self, request, *args, **kwargs): user = User.objects.get(id=self.request.data.get('user')) settings = UserSettings.objects.get(user=user) form = self.request.data.get('form') if form == 'editEssentialsForm': email = self.request.data.get('email') elif form == 'editPaymentsForm': gateway = Gateway.objects.get(name=request.data.get("gateway")) settings.gateway = gateway name = "user-" + str(user) + "'s billing address" street = request.data.get("billing_street") additional = request.data.get("billing_additional") city = City.objects.get(id=request.data.get("billing_city")) zipcode = request.data.get("billing_zip") Location.objects.update_or_create(name=name, street=street, additional=additional, city=city, zip_code=zipcode, phone=settings.phone, user=user) return Response("Settings updated successfully", status=HTTP_200_OK)
执行创建新Location时出现以下错误:
django.db.utils.IntegrityError: duplicate key value violates unique constraint "locations_city_id_key" DETAIL: Key (city_id)=(1) already exists.
数据库中已有一个使用同一城市的Location,想知道为何无法创建多个同城市的Location,哪里操作有误?
核心问题出在Location模型的city字段定义上:你使用了OneToOneField,这种关联关系的特性是一个City实例只能对应一个Location实例,Django会自动在数据库的locations表中为city_id字段添加唯一约束。当你尝试创建第二个关联同一City的Location时,就会触发唯一约束冲突,抛出上述错误。
要允许多个Location关联同一个City,需要将OneToOneField改为ForeignKey(多对一关联,多个位置属于同一个城市):
- 修改
Location模型中的city字段:
city = models.ForeignKey(City, on_delete=models.CASCADE, related_name="locations")
- 同时建议把
related_name从"cities"改为"locations",语义更准确(表示一个城市对应的所有位置)。
- 执行数据库迁移命令,更新数据库结构:
python manage.py makemigrations python manage.py migrate
迁移完成后,数据库会移除city_id字段的唯一约束,你就可以创建多个关联同一城市的Location了。
另外补充一点:你的update_or_create用法可能存在逻辑问题——当前是把所有字段作为匹配条件,意味着只要任何一个字段(比如street、zip_code)变化,就会创建新的Location。如果你的需求是为同一个用户更新或创建唯一的账单地址,应该把user作为唯一匹配条件,其他字段放在defaults参数里:
Location.objects.update_or_create( user=user, defaults={ 'name': name, 'street': street, 'additional': additional, 'city': city, 'zip_code': zipcode, 'phone': settings.phone } )
这样可以确保每个用户只有一个账单地址,避免重复创建。
内容的提问来源于stack exchange,提问作者EagerLearner

