2010-09-09 35 views
5

Có Django ORM thực hành tốt nhất cho SQL này:Django tương đương với SQL REPLACE

REPLACE app_model SET field_1 = 'some val', field_2 = 'some val'; 

Assumption: field_1 hoặc field_2 sẽ có một khóa duy nhất trên chúng (hoặc trong trường hợp của tôi trên cả hai), nếu không này sẽ luôn luôn đánh giá một INSERT.

Edit:

câu trả lời cá nhân tốt nhất của tôi ngay bây giờ là thế này, nhưng đó là 2-3 truy vấn mà 1 ta có thể:

from django.core.exceptions import ValidationError 
    try: 
     Model(field_1='some val',field_2='some val').validate_unique() 
     Model(field_1='some val',field_2='some val',extra_field='some val').save() 
    except ValidationError: 
     Model.objects.filter(field_1='some val',field_2='some val').update(extra_field='some val') 

Trả lời

11

Bạn nói rằng bạn muốn REPLACE, mà tôi tin là nghĩa vụ phải xóa mọi hàng hiện có trước khi chèn, nhưng ví dụ của bạn cho biết bạn muốn một cái gì đó giống như UPSERT.

AFAIK, django không hỗ trợ REPLACE (hoặc sqlite là INSERT OR REPLACE hoặc UPSERT). Nhưng code của bạn có thể được củng cố:

obj, created = Model.objects.get_or_create(field_1='some val', field_2='some_val') 
obj.extra_field = 'some_val' 
obj.save() 

Điều này tất nhiên giả định rằng một trong hai field_1, field_2, hoặc cả hai đều độc đáo (như bạn đã nói).

Nó vẫn còn hai truy vấn (một SELECT cho get_or_create, và một INSERT hoặc UPDATE cho save), nhưng cho đến một giải pháp UPSERT -like đến cùng (và nó có thể không cho một thời gian dài), nó có thể là tốt nhất bạn có thể làm.

+4

lol 'get_or_create() 'trả về một tuple' (đối tượng, được tạo ra) '. Tôi đã mắc sai lầm tương tự hàng chục lần trước đó. Hàm này thực sự nên được đổi tên thành 'get_a_tuple_or_create()' – est

+0

Bắt tốt, @est. Đã sửa. – eternicode

4

Tôi nghĩ sau đây hiệu quả hơn.

(obj, created) = Model.objects.get_or_create(
    field_1 = 'some val', 
    field_2 = 'some_val', 
    defaults = { 
     'extra_field': 'some_val' 
    }, 
) 
if not created and obj.extra_field != 'some_val': 
    obj.extra_field = 'some_val' 
    obj.save(
     update_fields = [ 
     'extra_field', 
     ], 
    ) 

Điều này sẽ chỉ cập nhật extra_field nếu hàng không được tạo và cần được cập nhật.

+1

đây là câu trả lời tốt hơn ... Django có 'mặc định' arg kể từ ít nhất 1.3 (tài liệu cũ nhất mà tôi vẫn có thể tìm thấy trực tuyến). BTW bạn không cần các dấu ngoặc xung quanh '(obj, tạo)' :) – Anentropic

+1

@Anentropic yeah Tôi biết tôi có mã OCD khá tệ và vì lý do nào đó tôi thích nó tốt hơn, nhưng trong năm qua tôi đã áp dụng hầu hết Các tiêu chuẩn định dạng PEP8, theo cách PEP8 cho phép/cho ăn mã OCD của tôi nhiều hơn ngay bây giờ! – byoungb

+0

Tôi biết, điều tương tự cũng xảy ra với tôi :) – Anentropic

9

Kể từ Django 1,7 bạn có thể sử dụng phương pháp update_or_create:

obj, created = Person.objects.update_or_create(
    first_name='John', last_name='Lennon', defaults=updated_values) 
Các vấn đề liên quan