2010-03-08 15 views
7

Tôi cần phát hiện khi một số trường của mô hình nhất định đã thay đổi trong quản trị viên, sau đó gửi thông báo tùy thuộc vào trường nào đã thay đổi và trước đó/giá trị hiện tại của các trường đó.Django Admin: Phát hiện nếu một tập hợp con của một trường đối tượng đã thay đổi và số nào trong số chúng

Tôi đã thử sử dụng ModelForm và ghi đè phương pháp save(), nhưng biểu mẫu self.cleaned_dataseld.instance đã có giá trị mới của trường.

Trả lời

7

Sửa đổi câu trả lời ở trên ... tham gia các chức năng rực rỡ từ Dominik Szopa và thay đổi nó sẽ giải quyết phát hiện sự thay đổi mối quan hệ của bạn: Sử dụng này:

def get_changes_between_models(model1, model2, excludes = []): 
    changes = {} 
    for field in model1._meta.fields: 
     if not (field.name in excludes): 
      if field.value_from_object(model1) != field.value_from_object(model2): 
       changes[field.verbose_name] = (field.value_from_object(model1), 
                field.value_from_object(model2)) 
    return changes 

Sau đó trong mã của bạn, bạn có thể nói (tránh try/trừ vì lý do hiệu suất):

if (self.id): 
    old = MyModel.Objects.get(pk=self.id) 
    changes = get_changes_between_models(self, old) 

    if (changes): 
     # Process based on what is changed. 

Nếu bạn đang làm điều này ở cấp "mô hình", không có cách nào để lưu truy vấn bổ sung. Dữ liệu đã được thay đổi khi bạn đạt đến điểm "Lưu". Bài đăng đầu tiên của tôi, vì vậy hãy tha thứ cho tôi nếu tôi nghe như một thằng ngốc.

+0

Cảm ơn bạn đã biết mẹo về 'Field.value_from_object()'! Rõ ràng nó cung cấp một cách nhất quán so sánh các giá trị. Tốt đẹp! –

+0

Để làm cho câu trả lời này dễ đọc hơn, chính xác và rõ ràng hơn, tôi sẽ thay đổi "model1" thành "model_instance_1" và "model2" thành "model_instance_2". Và tên phương thức có lẽ là "get_changes_between_model_instances". Không chắc chắn nếu có một cách tốt hơn trong các phiên bản gần đây của django nhưng tôi đang sử dụng 1.8 hiện tại và câu trả lời này sẽ làm việc cho tôi. – jenniwren

0

Điều bạn cần làm là lấy một bản sao bổ sung của đối tượng mà bạn đang làm việc từ cơ sở dữ liệu bên trong phương thức lưu trước khi lưu hoàn toàn. Ví dụ:

class MyModel(models.Model): 
    field1 = models.CharField(max_length=50) 

    def save(self): 
     if self.id: 
      try: 
       old = MyModel.objects.get(pk=self.id) 
       if old.field1 != self.field1: 
        # Process somehow 
      except MyModel.DoesNotExist: 
       pass 
     super(MyModel, self).save() 
+0

Tôi cũng đã đưa ra một cái gì đó như thế này, (lấy đối tượng từ DB trước khi nó được lưu và so sánh nó với bản sao sắp được lưu) nhưng tôi muốn lưu truy vấn bổ sung. –

1

Để có sự khác biệt về hai trường hợp mẫu, bạn cũng có thể sử dụng số function này. Nó so sánh với các cá thể mô hình và trả về từ điển các thay đổi.

+0

Rất hữu ích! Nhưng có vẻ như nó không nhận thức được các lĩnh vực liên quan. Vì mục đích của tôi, việc thêm hoặc xóa một mối quan hệ (một-nhiều hoặc nhiều-nhiều) cũng là một sự thay đổi của đối tượng. –

7

Để tránh thêm tra cứu DB, tôi sửa đổi constructor để nhớ giá trị ban đầu và sử dụng trong phương pháp tiết kiệm sau:

class Package(models.Model): 
    feedback = models.IntegerField(default = 0, choices = FEEDBACK_CHOICES) 
    feedback_time = models.DateTimeField(null = True) 

    def __init__(self, *args, **kw): 
     super(Package, self).__init__(*args, **kw) 
     self._old_feedback = self.feedback 

    def save(self, force_insert=False, force_update=False, *args, **kwargs): 
     if not force_insert and self.feedback != self._old_feedback: 
      self.feedback_time = datetime.utcnow() 
     return super(Package, self).save(force_insert, force_update, *args, **kwargs) 
+2

Trông với tôi như thể điều này sẽ không làm những gì bạn muốn trong nhiều trường hợp. Ví dụ, khi gửi biểu mẫu, một đối tượng được khởi tạo từ các tham số POST và sau đó được lưu lại. Phương thức lưu sẽ không tìm thấy sự khác biệt giữa giá trị trường ban đầu và hiện tại; nhưng chúng khác với những người trong cơ sở dữ liệu. –

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