我在使用django 1.4解决MySQL INSERT ... DUPLICATE KEY UPDATE时遇到问题。
我尝试插入记录的表有一个2列(复合)唯一键。我收到的记录来自第三方来源,除了制作唯一键集的字段外,值会随时间变化。我一次收到1~5k的记录,需要
目前我正在使用Model.objects.bulk_create进行批量插入,性能非常惊人,因为无论记录集有多大,它通常会发出一个查询。但是,由于我的记录可能会在第三方结束时随时间发生变化,因此我需要在记录集上执行MySQL INSERT ... ON DUPLICATE KEY UPDATE查询。
我打算编写原始SQL语句并使用类似这样的内容执行:
sql = "MySQL INSERT ... ON DUPLICATE KEY UPDATE"
raw_insert(sql)
def raw_insert(sql):
from django.db import connection, transaction
cursor = connection.cursor()
# Data modifying operation - commit required
cursor.execute(sql)
transaction.commit_unless_managed()
return 1
想知道我的问题是否有更好的解决方案。另外,我如何清理原始插入的字段值?
答案 0 :(得分:8)
所以我创建了一个自定义管理器。这是经理:
class BulkInsertManager(models.Manager):
def _bulk_insert_or_update(self, create_fields, update_fields, values):
from django.db import connection, transaction
cursor = connection.cursor()
db_table = self.model._meta.db_table
values_sql = []
values_data =[]
for value_lists in values:
values_sql.append( "(%s)" % (','.join([ "%s" for i in range(len(value_lists))]),) )
values_data.extend(value_lists)
base_sql = "INSERT INTO %s (%s) VALUES " % (db_table, ",".join(create_fields))
on_duplicates = []
for field in update_fields:
on_duplicates.append(field + "=VALUES(" + field +")")
sql = "%s %s ON DUPLICATE KEY UPDATE %s" % (base_sql, ", ".join(values_sql), ",".join(on_duplicates))
cursor.executemany(sql, [values_data])
transaction.commit_unless_managed()
样本模型:
class User_Friend(models.Model):
objects = BulkInsertManager() # assign a custom manager to handle bulk insert
id = models.CharField(max_length=255)
user = models.ForeignKey(User, null=False, blank=False)
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=30)
city = models.CharField(max_length=50, null=True, blank=True)
province = models.CharField(max_length=50, null=True, blank=True)
country = models.CharField(max_length=30, null=True, blank=True)
示例实施:
def save_user_friends(user, friends):
user_friends = []
for friend in friends:
create_fields = ['id', 'user_id', 'first_name', 'last_name', 'city', 'province', 'country']
update_fields = ['first_name', 'last_name', 'city', 'province', 'country']
user_friends.append(
[
str(user.id),
str(friend['id']),
friend['first_name'],
friend['last_name'],
friend['city'],
friend['province'],
friend['country'],
]
)
User_Friend.objects._bulk_insert_or_update(create_fields, update_fields, user_friends)
这是gist。
答案 1 :(得分:1)
您可以使用ModelForm进行清理:
from django.forms.models import modelform_factory
form_class = modelform_factory(MyModel)
for obj in my_data:
form = form_class(obj)
if not form.is_valid():
raise Hell()
对于原始SQL,我说去吧。 Django的ORM似乎不支持ON DUPLICATE KEY UPDATE
,所以不要让它妨碍你。 The Django docs talk about doing it without any reservation
虽然可能值得使用Manager.raw
。