2011-01-15 23 views
11

Tôi đang cố gắng viết một ứng dụng nhỏ nhận tệp video và chuyển đổi chúng thành định dạng thống nhất sau khi chúng được tải lên (do đó được thêm vào cơ sở dữ liệu). Tôi đã tìm kiếm trên web giải pháp tốt nhất cho điều này và đã quyết định sử dụng tín hiệu của Django với Celery. Nhưng bây giờ tôi đang cố gắng tạo ra một bằng chứng về khái niệm để xem nó có hoạt động hay không.Django - tín hiệu post_init được gọi trên Model instance save & trước khi dụ được tạo ra. Tại sao?

Tôi đang cố gắng thực hiện phương thức video_repalce() sau khi video mới đã được tải lên (do đó, một hàng mới đã được thêm vào cơ sở dữ liệu). Nhưng tín hiệu không hoạt động đúng, hoặc tôi không hiểu toàn bộ hệ thống hoạt động như thế nào.

Tôi đang sử dụng Django 1.2.3 với được xác định trước tín hiệu django.db.models.signals.post_init, mà should be called after a model has been instantiated (do đó, một hàng mới được bổ sung vào cơ sở dữ liệu).

from django.core.files.base import File 
from django.db.models.signals import post_init 
import os 
import os.path 
import subprocess 

class Project(models.Model): 
    video = models.FileField(upload_to="projects/videos") 

    def replace_video(self): 
     """Replace original video with an updated one.""" 

     # Video conversion process code goes here, 
     # resulting in a new external video file. 

     self.video.delete() # Delete the original video. 
     self.video.save("newfile.webm", File(open("path/to/newfile.webm") ,"wb"))) # Save the new video instead. 

     self.save() # Commit everything to database. 

     os.remove("path/to/newfile.webm") # Remove original video copy after it was commited (copied) into the DB. 

# ... 
# ... 

def handle_new_project(sender, **kwargs): 
    """Handels some additional tasks for a new added project. i.e. convert video to uniform format.""" 

    project = kwargs['instance'] 
    project.replace_video() 

# Call 'Project.replace_video()' every time a new project is added. 
post_init.connect(handle_new_project, sender=Project, dispatch_uid="new_project_added") 

Tuy nhiên, post_init được gọi không chỉ khi một trường hợp mô hình mới được tạo ra, mà còn ...:

  1. Trước khi mô hình được thậm chí khởi tạo. Ý tôi là, nó được gọi khi tôi exeucte máy chủ lần đầu tiên, khi thậm chí không có một hàng dữ liệu duy nhất trong cơ sở dữ liệu (do đó, không có đối tượng Model nào được khởi tạo). Ví dụ của self.pkNone!
  2. Khi save() -ing một mô hình. Đoạn mã trên cũng được thực thi khi tôi nhấn self.save().

Thực tế, nó không hoạt động theo tài liệu.

Tôi đang làm gì sai? Hãy nhớ rằng đây là một bằng chứng về khái niệm. Tôi định di chuyển mã đến Celery sau khi tôi thấy mã hoạt động. Tuy nhiên, nếu tín hiệu không hoạt động chính xác, Celery sẽ không trợ giúp - Tín hiệu sẽ luôn bị gửi lại một vài lần bất cứ khi nào tôi save() hoặc cập nhật video.

Bạn có nghĩ rằng tôi không nên gọi save() bên trong phương thức replace_video()? Vậy tôi nên gọi nó ở đâu? Tôi nên chọn tín hiệu nào? post_save không phải là một lựa chọn tốt bởi vì nó cũng được gọi là bất cứ khi nào tôi nhấn save().

+0

Bạn đề cập đến tín hiệu luôn được gửi khi bạn thực thi máy chủ, điều gì sẽ xảy ra nếu bạn chỉ cần mở một vỏ 'manage.py shell' và nhập mô hình? –

Trả lời

12

Dường như bạn có chút nhầm lẫn về ý nghĩa của việc tạo đối tượng. Nó không có gì liên quan đến cơ sở dữ liệu. Đây khởi tạo một đối tượng mô hình mà không lưu nó vào cơ sở dữ liệu, trong trường hợp này pk của nó sẽ là None:

MyObject(field1='foo', field2='bar') 

và điều này (gián tiếp) tạo một đối tượng bằng cách nhận nó từ cơ sở dữ liệu:

MyObject.objects.get(field1='baz') 

Tín hiệu post_init sẽ được gửi trong cả hai trường hợp này, mặc dù cả hai trường hợp này đều không liên quan gì đến việc lưu vào cơ sở dữ liệu.

Nếu bạn muốn điều gì đó xảy ra khi bạn lưu, hãy ghi đè chính phương thức save hoặc sử dụng các tín hiệu pre_save hoặc post_save. Bạn có thể kiểm tra xem liệu đối tượng đã được lưu trước đó chưa, bằng cách xác minh xem đối tượng của nó có phải là pk không.

+0

Tôi luôn tìm thấy phương pháp 'pk là None' một chút đáng sợ (có thể đặt nó theo cách thủ công), nhưng tôi đoán đó là cách duy nhất có. – vicvicvic

+0

Cuối cùng tôi đã sử dụng 'post_save' và thêm điều kiện để kiểm tra xem tôi có cần thay video hay không. Vì vậy, tôi không gọi 'save() 'đệ quy. –

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