2011-11-15 25 views
21

Trong chế độ xem django, tôi cần nối thêm dữ liệu chuỗi vào cuối cột văn bản hiện có trong cơ sở dữ liệu của tôi. Vì vậy, ví dụ, nói rằng tôi có một bảng có tên "ATable", và nó có một trường có tên là "aField". Tôi muốn có thể nối thêm một chuỗi vào cuối "aField" theo cách không có điều kiện. Ban đầu, tôi đã có này:Django: Sử dụng biểu thức F cho trường văn bản trong cuộc gọi cập nhật

tableEntry = ATable.objects.get(id=100) 
tableEntry.aField += aStringVar 
tableEntry.save() 

Vấn đề là nếu điều này được thực hiện đồng thời, cả hai có thể nhận được cùng một "tableEntry", sau đó họ từng một cách độc lập cập nhật, và người cuối cùng để "cứu" thắng, thua dữ liệu được người khác nối thêm.

Tôi nhìn vào trong này một chút và thấy điều này, mà tôi hy vọng sẽ làm việc, sử dụng một biểu thức F:

ATable.objects.filter(id=100).update(aField=F('aField') + aStringVar) 

Vấn đề ở đây, là tôi nhận được một lỗi SQL, nói:

operator does not exist: text + unknown 
HINT: No operator matches the given name and argument type(s). You might need to add explicit type casts. 

Đã cố gắng thay đổi thành "str (aStringVar)" mặc dù nó đã là một chuỗi - không may mắn .. Tôi tìm thấy một vài báo cáo lỗi django phàn nàn về các vấn đề tương tự, nhưng tôi không thấy một sửa chữa hoặc một workaround. Có cách nào tôi có thể cast aStringVar sao cho nó có thể được thêm vào văn bản của biểu thức F? BTW - cũng đã thử "str (F ('aField')) + aStringVar" nhưng đã chuyển đổi kết quả của biểu thức F thành chuỗi "(DEFAULT:)".

+0

Bạn có thể thấy Django sqlquery thử thực thi không? – Willian

+1

có thể trùng lặp của [Tôi có thể sử dụng các đối tượng Django F() với chuỗi nối không?] (Http://stackoverflow.com/questions/3300944/can-i-use-django-f-objects-with-string-concatenation) – Alasdair

+0

Tôi nghĩ rằng giải thích của Daniel về câu hỏi khác là khá dứt khoát. Để thay thế, bạn có thể viết [custom sql] (https://docs.djangoproject.com/en/dev/topics/db/sql/#executing-custom-sql-directly) để thực hiện các cập nhật của bạn. – Alasdair

Trả lời

2

có vẻ như bạn không thể làm điều này. tuy nhiên, những gì bạn đang cố gắng thực hiện có thể được giải quyết bằng cách sử dụng transactions

(có vẻ như bạn đang sử dụng postgres, vì vậy nếu bạn muốn thực hiện trong một truy vấn và sử dụng sql thô như được đề xuất, || là toán tử nối mà bạn muốn)

3

Và nếu bạn chạy ứng dụng này, nó không phải là chủ đề an toàn. Trong khi bản cập nhật của bạn đang chạy, một số quy trình khác có thể cập nhật một mô hình không biết dữ liệu trong cơ sở dữ liệu được cập nhật.

Bạn có quá có được một khóa, nhưng đừng quên senario này:

  1. Django: m = Model.objects.all() [10]
  2. Django: m.field = lĩnh vực
  3. Django: một tiến bộ mà mất một thời gian (time.sleep (100))
  4. DB: bảng Khóa
  5. DB: cập nhật lĩnh vực
  6. 01.
  7. DD: Mở bảng
  8. Django: quá trình chậm xong
  9. Django: m.tiết kiệm()

Bây giờ cập nhật lĩnh vực trở nên hoàn tác bằng các ví dụ mô hình trong Django (Ghost ghi)

+0

Điểm rất thú vị (nhưng không thực sự liên quan đến câu hỏi). Bạn có một số tài nguyên thảo luận làm thế nào để xử lý loại tình hình với Django? – lajarre

3

Bạn có thể đạt được chức năng này với select_for_update của Django() điều hành: https://docs.djangoproject.com/en/dev/ref/models/querysets/#select-for-update

Something như thế này:

obj = ATable.objects.select_for_update().get(id=100) 
obj.aField = obj.aField + aStringVar 
obj.save() 

các dòng của bảng sẽ bị khóa khi bạn gọi .select_for_update(). get(), và khóa sẽ được phát hành khi bạn gọi lệnh .save(), cho phép bạn thực hiện các hoạt động một cách nguyên tử.

22

Bạn có thể ghi đè lên F đối tượng trong Django với một thay đổi đơn giản:

class CF(F): 
    ADD = '||' 

Sau đó, chỉ cần sử dụng CF ở vị trí của F. Nó sẽ đặt "||" thay vì "+" khi tạo SQL. Ví dụ, truy vấn:

User.objects.filter(pk=100).update(email=CF('username') + '@gmail.com') 

sẽ tạo ra SQL:

UPDATE "auth_user" SET "email" = "auth_user"."username" || '@gmail.com' 
WHERE "auth_user"."id" = 100 
+1

Chỉ để hoàn thành câu trả lời này (làm việc cho tôi! Cảm ơn!), Bạn cũng nên đặt 'sql_mode = 'PIPES_AS_CONCAT''; nếu bạn không làm điều đó, MySQL của tôi xem xét "||" như logic HOẶC –

+1

Điểm tốt! Tôi đã thử nghiệm trên PostgreSQL. Thực tế, '||' không phải là toán tử SQL chuẩn. Cách tiêu chuẩn là sử dụng hàm 'CONCAT()', tuy nhiên nó không phù hợp với giải pháp này ... –

+0

Xem câu trả lời bên dưới để biết giải pháp di động sử dụng Concat! –

15

Bạn có thể sử dụng chức năng Concat db.

from django.db.models import Value 
from django.db.models.functions import Concat 

ATable.objects.filter(id=100).update(some_field=Concat('some_field', Value('more string'))) 

Trong trường hợp của tôi, tôi đang bổ sung thêm một hậu tố cho facebook avatar URI như thế này:

FACEBOOK_URI = 'graph.facebook.com' 
FACEBOOK_LARGE = '?type=large' 
# ... 
users = User.objects.filter(Q(avatar_uri__icontains=FACEBOOK_URI) & ~Q(avatar_uri__icontains=FACEBOOK_LARGE)) 
users.update(avatar_uri=Concat('avatar_uri', Value(FACEBOOK_LARGE))) 

và tôi nhận được lệnh SQL như thế này (Django 1.9):

UPDATE `user_user` SET `avatar_uri` = CONCAT(COALESCE(`user_user`.`avatar_uri`, ''), COALESCE('?type=large', '')) 
WHERE (`user_user`.`avatar_uri` LIKE '%graph.facebook.com%' AND NOT (`user_user`.`avatar_uri` LIKE '%?type=large%' AND `user_user`.`avatar_uri` IS NOT NULL)) 

Kết quả là tất cả các URI hình ảnh đã được thay đổi từ http://graph.facebook.com/<fb user id>/picture thành http://graph.facebook.com/<fb user id>/picture?type=large

+1

Đây là cách phù hợp để làm điều đó kể từ Django 1.8 – Fush

Các vấn đề liên quan