在Django模型中使用unique_together时,save()方法删除现有记录

时间:2009-08-26 01:03:31

标签: django django-models

我在models.py中使用以下类:

class Player(models.Model):
    id = models.AutoField(primary_key=True)
    sport = models.CharField(max_length=3, choices=SPORT_CHOICES)
    yid = models.IntegerField()
    first = models.CharField(max_length=30)
    last = models.CharField(max_length=30)
    team = models.CharField(max_length=3)
    class Meta:
        unique_together = (("sport", "yid"),)

如果运行以下代码并且数据库中已存在具有该sport / yid的播放器,则会删除该播放器的记录并插入新的播放器记录:

for (sport, yid, first, last, team) in NBA_PLAYERS:
    player = Player(sport=sport, yid=yid, first=first, last=last, team=team)
    player.save()

这个问题的主要问题是新记录的自动生成的id与已删除记录中的id不同,而其他使用Player作为外键的类引用具有旧id的记录。

SQL调用似乎正常工作:

mysql> insert into swap_player (sport, yid, first, last, team) values ('mlb', 1234, 'Joel', 'Zumaya', 'det');
ERROR 1062 (23000): Duplicate entry 'mlb-1234' for key 2

以下是来自Django的CREATE TABLE调用:

CREATE TABLE `swap_player` (
    `id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY,
    `sport` varchar(3) NOT NULL,
    `yid` integer NOT NULL,
    `first` varchar(30) NOT NULL,
    `last` varchar(30) NOT NULL,
    `team` varchar(3) NOT NULL,
    UNIQUE (`sport`, `yid`)
)
;

只有在网页上的操作(HttpRequest)启动了save()函数时,才会丢失错误。如果我从python命令行运行save()函数,那么我得到正确的错误:

>>>
>>> p = Player(sport='mlb', yid=1234, first='Joel', last='Zumaya', team='det')
>>> p.save()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/Users/dave/Development/django_trunk/django/db/models/base.py", line 328, in save
    self.save_base(force_insert=force_insert, force_update=force_update)
  File "/Users/dave/Development/django_trunk/django/db/models/base.py", line 400, in save_base
    result = manager._insert(values, return_id=update_pk)
  File "/Users/dave/Development/django_trunk/django/db/models/manager.py", line 138, in _insert
    return insert_query(self.model, values, **kwargs)
  File "/Users/dave/Development/django_trunk/django/db/models/query.py", line 894, in insert_query
    return query.execute_sql(return_id)
  File "/Users/dave/Development/django_trunk/django/db/models/sql/subqueries.py", line 309, in execute_sql
    cursor = super(InsertQuery, self).execute_sql(None)
  File "/Users/dave/Development/django_trunk/django/db/models/sql/query.py", line 1756, in execute_sql
    cursor.execute(sql, params)
  File "/Users/dave/Development/django_trunk/django/db/backends/util.py", line 19, in execute
    return self.cursor.execute(sql, params)
  File "/Users/dave/Development/django_trunk/django/db/backends/mysql/base.py", line 83, in execute
    return self.cursor.execute(query, args)
  File "build/bdist.macosx-10.5-i386/egg/MySQLdb/cursors.py", line 166, in execute
  File "build/bdist.macosx-10.5-i386/egg/MySQLdb/connections.py", line 35, in defaulterrorhandler
_mysql_exceptions.IntegrityError: (1062, "Duplicate entry 'mlb-1234' for key 2")
>>> connection.queries
[{'time': '0.000', 'sql': u'INSERT INTO `swap_player` (`sport`, `yid`, `first`, `last`, `team`) VALUES (mlb, 1234, Joel, Zumaya, det)'}]
>>> 
>>> 

如果已存在具有相同sport / yid的记录,如何让save()方法出错?

2 个答案:

答案 0 :(得分:0)

您可以覆盖Player:save()方法。具有如下的东西。我不熟悉unique_together的属性,知道你遇到的是否表明了一个bug。

def save(self, *args, **kwargs):
    try:
        Player.objects.get(yid = self.yid, sport=self.sport)
        raise PlayerObjectExists
    except:
        return super(Player, self).save(*args, **kwargs)

答案 1 :(得分:0)

听起来你需要take a look at the SQL django orm正在创作。