3

MySQL INSERT ... ON DUPLICATE KEY UPDATE withdjango1.4を理解するのに問題があります。

レコードを挿入しようとしているテーブルには、2列(複合)の一意のキーがあります。私が受け取っているレコードはサードパーティのソースからのものであり、一意のキーセットを作成するフィールドを除いて、値は時間の経過とともに変化します。一度に1〜5kのレコードを受信して​​いるので、

現在、Model.objects.bulk_createを使用して一括挿入していますが、レコードセットのサイズに関係なく、通常1つのクエリを発行するため、パフォーマンスは非常に優れています。ただし、サードパーティ側でレコードが時間の経過とともに変更される可能性があるため、レコードセットでMySQL INSERT ... ON DUPLICATEKEYUPDATEクエリを実行する必要があります。

生の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

私の問題に対するより良い解決策があるかどうか疑問に思います。また、生の挿入のフィールド値をどのようにサニタイズしますか?

4

2 に答える 2

9

そこで、カスタムマネージャーを作成しました。マネージャーは次のとおりです。

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)

ここに要点があります。

于 2012-10-17T03:20:13.703 に答える
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ようには見えないので、邪魔にならないようにしてください。Djangoのドキュメントでは、予約なしでそれを行うことについて説明しています

ただし、使用する価値があるかもしれませんManager.raw

于 2012-10-16T21:54:55.880 に答える