MySQL INSERT… ON DUPLICATE KEY UPDATE с django 1.4 для массовой вставки

У меня проблемы с выяснением ВСТАВКИ MySQL ... НА ДУБЛИКАТЕ ОБНОВЛЕНИЕ КЛЮЧЕЙ с django 1.4

Таблица, в которую я пытаюсь вставить записи, имеет уникальный ключ в 2 столбца (составной). Записи, которые я получаю, поступают из стороннего источника, и их значения будут меняться со временем, за исключением тех полей, в которых задан уникальный ключ. Я получаю 1 ~ 5 тыс. Записей одновременно, и мне потребуется

В настоящее время я использую 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

Хотите знать, есть ли лучшее решение моей проблемы? Также, как бы я санировал значения полей для необработанной вставки?

 Joran Beasley16 окт. 2012 г., 16:29
Зачем вам делать сырые курсоры вместо использования встроенного в Djangos ORM с MySQL?
 mmohiudd16 окт. 2012 г., 21:38
Проблема для массовой вставки. когда я получаю записи 5k, которые уже существуют в таблице, неэффективно создавать объекты ORK 5k. Однако вставка новых записей очень эффективна с использованием objects.bulk_create. Я получу двойную ошибку при входе (IntegrityError).

Ответы на вопрос(2)

Решение Вопроса

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)

Здесьсуть.

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, я говорю, пойти на это. Похоже, что ORM Django не поддерживаетON DUPLICATE KEY UPDATEтак что не позволяйте этому мешать вам.Django Docs говорят о том, чтобы делать это без каких-либо оговорок.

Возможно, стоит использоватьManager.raw, хотя.

Ваш ответ на вопрос