django.db.utils.IntegrityError:无法创建唯一索引 - 详细信息:键(玩家)=(Lonergan)重复。- 模型中没有唯一约束

emb*_*mbe 4 migration django postgresql django-models

经过几次离线提交(包括多次更新模型和部署到生产)后,错误消息是:(它正在用于开发,但在生产中失败)

django.db.utils.IntegrityError: could not create unique index - DETAIL:  Key (player)=(Lonergan) is duplicated.
Run Code Online (Sandbox Code Playgroud)

表中有超过 100 名重复姓名的球员,并且场上球员从未被设置为唯一。为什么会发生这种情况?

class Player(models.Model):
    player = models.CharField(max_length=50)
    team = models.ForeignKey(Team, related_name='players', on_delete=models.PROTECT)
    position = models.CharField(max_length=5)
    cost = models.FloatField()
    selection = models.FloatField()
    form = models.FloatField()
    points = models.IntegerField()
    lastgwscrape = models.DateTimeField(null=True)
    lastapiupdate = models.DateTimeField(null=True)
    currentgwdt = models.DateTimeField(null=True)
    apiid = models.IntegerField(null=True)
Run Code Online (Sandbox Code Playgroud)

apiid 字段之前被定义为唯一的,并且作为使此迁移工作正常进行的测试而被删除。

class APIPlayerGW(models.Model):
    player = models.ForeignKey(Player, related_name='apigws', on_delete=models.CASCADE)
    gwid = models.IntegerField()
    points = models.IntegerField()
    minutesplayed = models.IntegerField()
    goalsscored = models.IntegerField()
    assists = models.IntegerField()
    cleansheets = models.IntegerField()
    goalsconceded = models.IntegerField()
    owngoals = models.IntegerField()
    penaltiessaved = models.IntegerField()
    penaltiesmissed = models.IntegerField()
    yellowcards = models.IntegerField()
    redcards = models.IntegerField()
    saves = models.IntegerField()
    bonuspoints = models.IntegerField()
    bonuspointsystem = models.IntegerField()
    influence = models.FloatField()
    creativity = models.FloatField()
    threat = models.FloatField()
    ictindex = models.FloatField()
    datetime = models.DateTimeField(default=timezone.now)
    season = models.CharField(max_length=10)

    # class Meta:
    #     unique_together = ('player','gwid','season') # Double gameweeks are lumped together
Run Code Online (Sandbox Code Playgroud)

上表具有 unique_together 组合,该组合被注释掉作为使此迁移工作正常进行的测试。我该怎么做才能使此迁移成功?

Abd*_*kat 7

从你的评论来看:

迁移文件与迁移不同步,Django 尝试使用旧的迁移文件。

我假设发生了如下情况(或者可能还有其他情况,例如手动编辑了一些迁移文件等):

  1. 您的项目处于某种版本控制中。
  2. 有些人在本地生成迁移并推送到版本控制(他们的名称以相同的前缀开头,例如0003),不幸的是没有检测到,也许后来在这些迁移之上生成了更多迁移。

我建议通过以下 3 种方法来解决此类问题:

1. 使用合并迁移--merge

一般来说,解决这种情况的第一件事就是尝试使用--merge标志 [Django docs]来合并冲突。如果冲突不是很复杂,大多数情况下 Django 将能够使用此命令为您修复它。

2.回滚迁移并重新生成它们

人们应该尝试的下一个解决方案(而不是直接在生产服务器上进行迁移)是通过回滚到与生产服务器状态一致的某个先前迁移来在本地修复迁移。假设生产已正确迁移到0005,我们将执行如下操作(在开发服务器上):

  1. 迁移回0005

     python manage.py migrate <app_label> 0005
    
    Run Code Online (Sandbox Code Playgroud)
  2. 之后删除所有迁移0005,或者有选择地删除一些迁移,或者重命名一些迁移,以便它们按顺序排列。

  3. 再次生成迁移:

     python manage.py makemigrations
    
    Run Code Online (Sandbox Code Playgroud)
  4. 将这些迁移推向生产并进行迁移。

3. 手动编辑迁移

如果这些步骤不可行,那么可以尝试实际编辑迁移文件本身来解决问题,方法是参考有关编写数据库迁移的文档。


注意:虽然您的解决方案(修复生产上的迁移)效果很好,但很多人不允许这样做,如果我们有多个生产服务器,这也可能会导致以后出现问题,因为它们之间的迁移可能不一致案件。