2012-10-16 2 views
2

MySQL INSERT ... Django 1.4와 중복 키 업데이트시 문제가 있습니다.MySQL INSERT ... 대량 삽입을 위해 django 1.4와 중복 키를 사용합니다.

레코드를 삽입하려고하는 테이블에 2 열 (복합) 고유 키가 있습니다. 내가받는 레코드는 제 3 자 원본에서 가져온 것이고 고유 한 키를 만드는 필드를 제외하고 시간이 지남에 따라 값이 변경됩니다. 한 번에 1 ~ 5k 개의 레코드를 받고 있습니다.

현재 대량 삽입을 위해 Model.objects.bulk_create를 사용하고 있습니다. 레코드 세트의 크기에 관계없이 일반적으로 하나의 쿼리를 발행하므로 성능이 정말 좋습니다. . 그러나 내 레코드가 제 3 자 파티에서 시간이 지남에 따라 바뀔 수 있으므로 레코드 세트에서 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 

가 궁금. 또한 어떻게 원시 삽입에 대한 필드 값을 sanitize까요?

+0

왜 MySQL에서 djangos ORM을 사용하는 대신 원시 커서를 사용합니까? –

+1

문제는 벌크 삽입입니다. 테이블에 이미있는 5k 개의 레코드를 받으면 5k 개의 ORM 오브젝트를 만드는 것이 효율적이지 않습니다. 그러나 objects.bulk_create를 사용하면 새 레코드를 삽입하는 것이 매우 효율적입니다. 나는 중복 엔트리 오류 (IntegrityError)를 얻을 것이다. – mmohiudd

답변

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

당신은 ModelForm으로 살균 수 :

원시 SQL에 관해서는
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() 

, 내가 갈 말한다. 장고의 ORM이 ON DUPLICATE KEY UPDATE을 지원하는 것으로 보이지 않으므로 방해하지 마십시오. The Django docs talk about doing it without any reservation.

Manager.raw을 사용해 볼 가치가 있습니다.

관련 문제