2015-03-27 24 views
11

Tôi đang nâng cấp lên DRF3.1.1 từ 2.4. Tôi đã sử dụng một serializer tùy chỉnh để tạo ra một thể hiện của một đối tượng không phải là một Model.Django Rest Framework 3 Serializers trên các đối tượng không phải Model?

Trong 2,4, thật dễ dàng để làm điều này vì trong bộ nối tiếp, tôi sẽ tạo đối tượng trong restore_object(). Theo quan điểm, tôi sẽ gọi serializer.is_valid() và sau đó bật thể hiện của đối tượng ra khỏi bộ nối tiếp với serializer.object. Sau đó, tôi có thể làm bất cứ điều gì tôi muốn.

Với các thay đổi 3.x, khó có thể loại bỏ đối tượng ra khỏi đối tượng vì phương thức tạo và cập nhật được thực hiện để lưu và "serializer.object" không khả dụng nữa.

Ví dụ, tôi đã từng sử dụng đối tượng này cho đối tượng "UserRegistration" của mình. Đây không phải là một mô hình vì nó là một đối tượng tiện lợi mà máy chủ phân tích và lưu trữ dữ liệu trong một số đối tượng/bảng db khác.

class UserRegistration(object): 
    def __init__(self, full_name, stage_name, password="", email="", locale="en_US"): 
     self.full_name = full_name 
     self.password = password 
     self.locale = locale 
     self.email = email 
     self.stage_name = stage_name 

Đây là liên DRF-2.4 serializer:

class UserRegistrationSerializer(serializers.Serializer): 
    full_name = serializers.CharField(max_length=128, required=False) 
    stage_name = serializers.CharField(max_length=128) 
    password = serializers.CharField(max_length=128, required=False) 
    locale = serializers.CharField(max_length=10, required=False) 
    # use CharField instead of EmailField for email. We do our own validation later to make for a better error msg. 
    email = serializers.CharField(max_length=254, required=False) 

    def restore_object(self, attrs, instance=None): 
     if instance is not None: 
      instance.full_name = attrs.get('full_name', instance.full_name) 
      instance.password = attrs.get('password', instance.password) 
      instance.locale = attrs.get('locale', instance.locale) 
      instance.email = attrs.get('email', instance.email) 
      instance.stage_name = attrs.get('stage_name', instance.stage_name) 
      return instance 
     return UserRegistration(**attrs) 

Sau đó, trong quan điểm của tôi, tôi làm điều gì đó như thế này:

class UserRegistration(APIView): 
    throttle_classes =() 
    serializer_class = UserRegistrationSerializer 

    def post(self, request, format=None): 
     event_type = "user_registration" 
     serializer = UserRegistrationSerializer(data=request.DATA, context={'request': request}) 
     try: 
      if serializer.is_valid(): 
      user_registration = serializer.object 
      # save user_registration pieces in various places... 

Tuy nhiên, trong DRF3, tôi serializer.object đã biến mất. Các tài liệu nói để làm "xác nhận" bằng cách sử dụng serializer.validated_data, nhưng đó chỉ là một băm và không phải là đối tượng thực sự. Có cách nào để lấy vật đó không?

Toàn bộ điều dường như kết hôn với đối tượng DB, trong trường hợp cụ thể này chính xác là những gì tôi đang cố gắng tránh.

Tôi chỉ thiếu một số khái niệm DRF3 mới?

Trả lời

1

Có, bạn có thể nhận được các vật thể tự sử dụng DRF 3. Phương pháp update của bạn nên có chữ ký này update(self, instance, validated_data)

serializer của bạn nên trông như thế này:

class UserRegistrationSerializer(serializers.Serializer): 
    full_name = serializers.CharField(max_length=128, required=False) 
    stage_name = serializers.CharField(max_length=128) 
    password = serializers.CharField(max_length=128, required=False) 
    locale = serializers.CharField(max_length=10, required=False) 
    # use CharField instead of EmailField for email. We do our own validation later to make for a better error msg. 
    email = serializers.CharField(max_length=254, required=False) 

    def update(self, instance, validated_data): 
      // here instance is the object . 
11

Cảm ơn @levi cho sự khởi đầu của một câu trả lời, nhưng thật không may, đó không phải là tất cả, vì vậy tôi nghĩ rằng đây là một câu trả lời hoàn chỉnh hơn.

tôi ban đầu hỏi:

Tôi chỉ thiếu một số khái niệm DRF3 mới?

Tắt ... Yep. Tôi đã. Các tài liệu nói về Single-step object creation mới, điều này khiến tôi nghĩ rằng sự tuần tự hóa và mô hình đã trở nên kết hợp chặt chẽ hơn. Suy nghĩ này là không chính xác, bởi vì nếu bạn viết serializer tùy chỉnh của riêng bạn, bạn có thể lưu đối tượng thực tế (hoặc không) trong các phương thức serializer.update()serializer.create() mới.

Tôi cũng hỏi:

Trong 2.4, nó là đủ dễ dàng để làm điều này bởi vì trong serializer, tôi sẽ tạo ra các đối tượng trong restore_object().Theo quan điểm, tôi sẽ gọi serializer.is_valid() và sau đó pop instance của đối tượng ra khỏi serializer với serializer.object. Sau đó, tôi có thể làm bất cứ điều gì tôi muốn.

Với các thay đổi 3.x, khó có thể loại bỏ đối tượng ra khỏi đối tượng vì phương thức tạo và cập nhật được thực hiện để lưu và "serializer.object" không khả dụng nữa.

Mặc dù không có serializer.object mà bạn có thể sử dụng để kéo đối tượng được tạo ra sau khi gọi serializer.is_valid(), phương pháp serializer.save() trả về đối tượng chính nó, mà trong trường hợp của tôi là tốt.

Vì vậy, hóa ra, thay đổi mã không quá lớn. Đây là mã mới của tôi khá hài lòng với DRF-3:

class UserRegistration(object): 
    def __init__(self, full_name, stage_name, password="", email="", locale="en_US", notification_pref="ask"): 
     self.full_name = full_name 
     self.password = password 
     self.locale = locale 
     self.email = email 
     self.stage_name = stage_name 


class UserRegistrationSerializer(serializers.Serializer): 
    full_name = serializers.CharField(max_length=128, required=False) 
    stage_name = serializers.CharField(max_length=128) 
    password = serializers.CharField(max_length=128, required=False) 
    locale = serializers.CharField(max_length=10, required=False) 
    # use CharField instead of EmailField for email. We do our own validation later to make for a better error msg. 
    email = serializers.CharField(max_length=254, required=False) 

    def update(self, instance, validated_data): 
     instance.full_name = validated_data.get('full_name', instance.full_name) 
     instance.password = validated_data.get('password', instance.password) 
     instance.locale = validated_data.get('locale', instance.locale) 
     instance.email = validated_data.get('email', instance.email) 
     instance.stage_name = validated_data.get('stage_name', instance.stage_name) 
     return instance 

    def create(self, validated_data): 
     return UserRegistration(**validated_data) 

lưu ý rằng không lưu đối tượng vào bất kỳ DB nào trong Trình nối tiếp. Tôi chỉ đang tạo hoặc cập nhật đối tượng và sau đó trả lại nó.

Bây giờ nhìn trông như thế này:

class UserRegistration(APIView): 
    throttle_classes =() 
    serializer_class = UserRegistrationSerializer 

    def post(self, request, format=None): 
     event_type = "user_registration" 
     serializer = UserRegistrationSerializer(data=request.DATA, context={'request': request}) 
     try: 
      if serializer.is_valid(): 
       user_registration = serializer.save() 
       # save user_registration pieces in various places... 

Tôi cũng đã nói trong bài ban đầu của tôi:

Toàn bộ điều dường như đã lập gia đình hơn để DB đối tượng, mà trong trường hợp đặc biệt này là chính xác những gì Tôi đang cố tránh.

Tuyên bố này cũng không chính xác khi thấy thực tế là phương thức tạo và cập nhật không phải lưu bất kỳ thứ gì cho bất kỳ DB nào.

Một lưu ý ở đây là mã có chức năng, nhưng rõ ràng là tôi chỉ gói đầu quanh một số thay đổi DRF2.x-> 3.x, vì vậy tôi có thể làm điều này theo cách không phải DRF. Nếu vậy, một người biết xin vui lòng cho tôi biết làm thế nào để làm điều đó tốt hơn. :)

+1

như một người đứng đầu lên bạn không bao giờ nên sử dụng một đường như một giá trị mặc định cho một hàm khi nó trở nên có thể thay đổi và có thể dẫn đến hành vi lạ - http://docs.python-guide.org/en/latest/ viết/gotchas/ – Alvin

+1

@Alvin Những gì bạn đang nói là đúng cho các loại mutable nhưng tôi gần như 100% một số chuỗi python là bất biến. – jackdbernier

+0

Chỉ cần lưu ý nhanh: 'request.DATA' đã không còn được dùng cho 'request.data' kể từ phiên bản 3.0 và đã bị xóa hoàn toàn kể từ phiên bản 3.2. – Slipstream

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