2012-08-23 24 views
13

Tôi đang trong quá trình di chuyển từ db.Model đến ndb.Model. Vấn đề duy nhất mà tôi phải giải quyết trước khi hoàn thành việc di chuyển này là không có phương thức Model.is_saved. Tôi đã sử dụng db.Model.is_saved trong ứng dụng của tôi để xác định xem quầy sharded phải được cập nhật trên put/delete, để kiểm tra phím mâu thuẫn về việc tạo ra các đơn vị, vvCó thể xác định với NDB nếu mô hình liên tục trong kho dữ liệu hay không?

Các tài liệu nói rằng ndb.Model không có tương đương cho is_saved phương pháp. Tôi có thể triển khai lại một số trường hợp sử dụng với get_or_insert thay vì is_saved. Nhưng không phải tất cả trong số họ.

Là một hack bẩn tôi có thể đặt cờ như _in_memory_instance cho mọi trường hợp tôi đã tạo bằng cách gọi hàm tạo. Nhưng nó không giải quyết được vấn đề của tôi. Tôi vẫn phải cập nhật cờ này ít nhất sau mỗi cuộc gọi put().

Câu hỏi đặt ra là: có cách nào tốt hơn để xác định xem mô hình có tồn tại lâu dài trong kho dữ liệu hay không mà không có thêm lần truy cập datastore?

Chỉnh sửa 1: Quên đề cập: tất cả các thực thể đều có khóa để kiểm tra Model._has_complete_key() không hoạt động đối với tôi.

Chỉnh sửa 2: Sau cuộc thảo luận này https://groups.google.com/d/topic/google-appengine/Tm8NDWIvc70/discussion có vẻ như cách duy nhất để giải quyết vấn đề của tôi là sử dụng _post_get_hook/_post_put_hook. Tôi tự hỏi tại sao một điều tầm thường như vậy không được đưa vào API chính thức.

Chỉnh sửa 3: Tôi đã kết thúc với lớp cơ sở tiếp theo cho tất cả các mô hình của mình. Bây giờ tôi có thể để lại codebase của tôi (hầu như) không bị ảnh hưởng:

class BaseModel(ndb.Model): 

    @classmethod 
    def _post_get_hook(cls, key, future): 
     self = future.get_result() 
     if self: 
      self._is_saved = bool(key) 

    def _post_put_hook(self, future): 
     self._is_saved = future.state == future.FINISHING 

    def is_saved(self): 
     if self._has_complete_key(): 
      return getattr(self, "_is_saved", False) 
     return False 
+0

bạn có thể kiểm tra xem đối tượng có thực sự có khóa/id không? (có thể trong mệnh đề try/except). Không quen thuộc với lớp mô hình NDB, nhưng tôi nhớ lại rằng db.Model đưa ra một lỗi (hoặc trả về None?) nếu bạn cố gắng lấy id/key của một cá thể mô hình trước khi nó được lưu (hoặc có thể nó trả về 'None'). Đừng nghĩ rằng sẽ kết thúc với một Datastore hit hoặc. Nếu nó hoạt động, bạn có thể viết một thuộc tính giống như 'def is_saved (self): return self.key() là None' (hoặc làm điều đó với mệnh đề try/except trả về True nếu ngoại lệ được nâng lên và False nếu không). –

+0

Kiểm tra phím sẽ không hoạt động nếu bạn tạo khóa. Một lựa chọn có thể (nhưng có thể không đủ) là có một cờ create_date (được đặt thành auto_now_add = True). Từ tài liệu "Giá trị tự động không được tạo cho đến khi thực thể được viết, nghĩa là các tùy chọn này không cung cấp mặc định động". Tuy nhiên nếu viết không thành công thì giá trị đó sẽ được đặt. Mặc dù bạn nên biết rằng viết không thành công ;-) –

+1

luân phiên sử dụng _post_put_hook để đặt cờ của bạn cho biết nó đã được lưu. –

Trả lời

11

Để có cùng một loại trạng thái trong NDB, bạn cần có sự kết hợp của post-get-hook và post-put-hook để đặt cờ. Dưới đây là một ví dụ làm việc:

class Employee(ndb.Model): 
    <properties here> 

    saved = False # class variable provides default value 

    @classmethod 
    def _post_get_hook(cls, key, future): 
    obj = future.get_result() 
    if obj is not None: 
     # test needed because post_get_hook is called even if get() fails! 
     obj.saved = True 

    def _post_put_hook(self, future): 
    self.saved = True 

Không cần để kiểm tra tình trạng của tương lai - khi một trong hai móc được gọi là, tương lai luôn luôn có một kết quả. Điều này là do móc thực sự là một cuộc gọi lại trong tương lai. Tuy nhiên, cần phải kiểm tra xem kết quả của nó là Không!

PS: Bên trong giao dịch, móc được gọi ngay khi lệnh gọi put() trả về; thành công hay thất bại của giao dịch không ảnh hưởng đến chúng. Xem https://developers.google.com/appengine/docs/python/ndb/contextclass#Context_call_on_commit để biết cách chạy móc sau khi cam kết thành công.

+5

Như đã thảo luận [ở đây] (https://code.google.com/p/appengine-ndb-experiment/issues/detail?id=211) điều này sẽ không hoạt động đối với các thực thể truy xuất các truy vấn máng/gql vì _post_get_hook không phải là kêu gọi họ và không có callback tương đương (chưa) cho các truy vấn. –

2

Dựa trên @ Tim Hoffmans ý tưởng bạn có thể giúp bạn một cái móc bài như vậy:

class Article(ndb.Model): 
    title = ndb.StringProperty() 

    is_saved = False 

    def _post_put_hook(self, f): 
     if f.state == f.FINISHING: 
      self.is_saved = True 
     else: 
      self.is_saved = False 


article = Article() 
print article.is_saved ## False 
article.put() 
print article.is_saved ## True 

tôi có thể không đảm bảo rằng nó tồn tại kho dữ liệu. Không tìm thấy bất cứ điều gì về nó trên google :)

Mặt khác, tìm cách xem một cá thể ndb.Model có khóa không có thể hoạt động vì một cá thể mới dường như nhận được Khóa trước khi nó được gửi đến kho dữ liệu. Bạn có thể xem số source code để xem điều gì xảy ra khi bạn tạo một thể hiện của lớp ndb.Model.

+1

Nó đủ gần để sử dụng nó như một cách giải quyết. Vì vậy, tôi bỏ phiếu +1. Tôi sẽ chấp nhận câu trả lời của bạn trong vài ngày nếu giải pháp tốt hơn sẽ không xuất hiện. – Sergey

+0

Nhược điểm duy nhất tôi thấy với phương pháp này vì nó hiện đang đứng là nếu một thực thể đã được lấy ra chứ không phải là tạo ra sau đó 'is_saved' sẽ là' False'. Mà không ánh xạ tới hành vi 'db.Model' của' is_saved() '. Để hoàn thành, bạn có thể muốn thêm phương thức '_post_get_hook' cũng đặt is_saved thành True. –

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