2010-01-08 33 views
9

Một vài lần tôi gặp phải tình huống, khi tiết kiệm thời gian, tôi cần phải biết trường nào sẽ được cập nhật và hành động tương ứng.Theo dõi các thay đổi kể từ lần lưu cuối cùng trong các mô hình django

Các giải pháp rõ ràng nhất cho điều này là để có những trường tiểu học trọng và lấy một bản sao của mô hình từ cơ sở dữ liệu:

class MyModel(models.Model): 

    def save(self, force_insert=False, force_update=False, using=None): 
     if self.id is not None: 
      unsaved_copy = MyModel.objects.get(id=self.id) 
      # Do your comparisons here 
     super(MyModel, self).save(force_insert, force_update, using) 

đó làm việc hoàn toàn tốt đẹp, tuy nhiên, nó chạm vào cơ sở dữ liệu cho mỗi thể hiện của mô hình bạn đang tiết kiệm (có thể khá bất tiện nếu bạn đang thực hiện rất nhiều lần lưu). Rõ ràng, nếu người ta có thể "nhớ" các giá trị trường cũ khi bắt đầu tuổi thọ của cá thể mô hình (__init__), sẽ không cần phải lấy một bản sao của mô hình từ cơ sở dữ liệu. Vì vậy, tôi đã đưa ra ít hack này:

class MyModel(models.Model): 

    def __init__(self, *args, **kwargs): 
     super(MyModel, self).__init__(*args, **kwargs) 
     self.unsaved = {} 
     for field in self._meta.fields: 
      self.unsaved[field.name] = getattr(self, field.name, None) 

    def save(self, force_insert=False, force_update=False, using=None): 
     for name, value in self.unsaved.iteritems(): 
      print "Field:%s Old:%s New:%s" % (name, value, getattr(self, name, None)) 
     # old values can be accessed through the self.unsaved member 
     super(MyModel, self).save(force_insert, force_update, using) 

Điều này dường như hoạt động, tuy nhiên nó sử dụng giao diện ngoài công cộng django.db.models.Model.

Có lẽ ai đó biết cách làm sạch hơn?

Trả lời

2

Tôi nghĩ giải pháp của bạn có vẻ hợp lý.

Hoặc bạn có thể có một phương pháp quản lý được gọi là get_and_copy() (hoặc một cái gì đó) treo một bản sao của đối tượng gốc ra khỏi những gì được trả về. Sau đó, bạn có thể sử dụng phương thức Người quản lý khác, save_and_check() đã tận dụng bản gốc được sao chép.

FWIW: Nếu bạn đang chơi với mẫu đóng góp/quản trị, có một biến ngữ cảnh được gọi là original là bản sao của đối tượng gốc.

Cập nhật: Tôi đã xem xét kỹ hơn những gì quản trị viên đang làm. Trong class ModelAdmin (nằm trong django/contrib/admin/options.py) có một phương pháp được gọi là construct_change_message(). Nó đang được điều khiển bởi formset.changed_dataformset.changed_objects, vì vậy django/forms/models.py class BaseModelFormSet là nơi thực hiện hành động. Xem phương thức save_existing_objects(). Ngoài ra, hãy xem phương thức _existing_object(). Nó phức tạp hơn một chút so với những gì tôi đã đề cập trước đây bởi vì họ đang đối phó với khả năng của nhiều đối tượng, nhưng về cơ bản là bộ nhớ đệm kết quả của truy vấn được đặt trên truy cập đầu tiên.

+0

Không, tôi đã không hỏi nó trong bối cảnh của các mẫu quản trị viên, tuy nhiên tôi sẽ kiểm tra cách nó được thực hiện ở đó, cảm ơn cho tip. – shylent

0

Điều này sẽ không hoạt động đối với đồ đạc. loaddata lệnh sử dụng models.Model.base_save. Có lẽ phương pháp sạch sẽ nhất là sử dụng các bộ mô tả cho các trường, nhưng người ta phải tìm ra cách để chèn chúng đúng cách.

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