Django REST Framework: thêm trường bổ sung vào ModelSerializer


147

Tôi muốn tuần tự hóa một mô hình, nhưng muốn bao gồm một trường bổ sung yêu cầu thực hiện một số tra cứu cơ sở dữ liệu trên phiên bản mô hình để được tuần tự hóa:

class FooSerializer(serializers.ModelSerializer):
  my_field = ... # result of some database queries on the input Foo object
  class Meta:
        model = Foo
        fields = ('id', 'name', 'myfield')

Cách đúng đắn để làm điều này là gì? Tôi thấy rằng bạn có thể chuyển "ngữ cảnh" bổ sung cho bộ nối tiếp, đây có phải là câu trả lời đúng để chuyển vào trường bổ sung trong từ điển ngữ cảnh không? Với cách tiếp cận đó, logic nhận được trường tôi cần sẽ không được bao gồm với định nghĩa serializer, lý tưởng vì mọi trường hợp được tuần tự hóa sẽ cần my_field. Ở những nơi khác trong tài liệu của DRF serializers nó nói "trường bổ sung có thể tương ứng với bất kỳ tài sản hoặc có thể được gọi vào mô hình". Là các lĩnh vực thêm những gì tôi đang nói về? Tôi có nên định nghĩa một hàm trong Foođịnh nghĩa mô hình trả về my_fieldgiá trị và trong trình tuần tự hóa, tôi kết nối my_field với lệnh có thể gọi đó không? Điều đó giống như thế nào?

Cảm ơn trước, vui lòng làm rõ câu hỏi nếu cần thiết.

Câu trả lời:


224

Tôi nghĩ rằng SerializerMethodField là những gì bạn đang tìm kiếm:

class FooSerializer(serializers.ModelSerializer):
  my_field = serializers.SerializerMethodField('is_named_bar')

  def is_named_bar(self, foo):
      return foo.name == "bar" 

  class Meta:
    model = Foo
    fields = ('id', 'name', 'my_field')

http://www.django-rest-framework.org/api-guide/fields/#serializermethodfield


19
Có thể thêm xác nhận vào các lĩnh vực như vậy? Câu hỏi của tôi là: làm thế nào để chấp nhận các giá trị POST tùy chỉnh có thể được xác nhận và các quy trình trong trình xử lý post_save ()?
Alp

20
Lưu ý rằng SerializerMethodField là chỉ đọc, vì vậy điều này sẽ không hoạt động cho POST / PUT / PATCH đến.
Scott A

24
Trong DRF 3, nó được đổi thành field_name = serializers.SerializerMethodField()def get_field_name(self, obj):
Lập trình viên hóa học

1
Điều gì fookhi def một serializerMethodField? Khi sử dụng CreatAPIView, foo đã được lưu trữ rồi thì có thể sử dụng phương thức is_named_bar () không?
244boy

Vì vậy, dựa trên câu trả lời này, nếu bạn muốn chuyển 12 trường bổ sung cho serializer của mình, bạn cần xác định 12 phương thức cụ thể cho từng trường chỉ trả về foo.field_custom?
AlxVallejo

41

Bạn có thể thay đổi phương thức mô hình của mình thành thuộc tính và sử dụng nó trong serializer với phương pháp này.

class Foo(models.Model):
    . . .
    @property
    def my_field(self):
        return stuff
    . . .

class FooSerializer(ModelSerializer):
    my_field = serializers.ReadOnlyField(source='my_field')

    class Meta:
        model = Foo
        fields = ('my_field',)

Chỉnh sửa: Với các phiên bản gần đây của khung nghỉ (tôi đã thử 3.3.3), bạn không cần thay đổi thành thuộc tính. Phương pháp mô hình sẽ chỉ hoạt động tốt.


Cảm ơn @Wasil! Tôi không quen với việc sử dụng các thuộc tính trong các mô hình Django và không thể tìm thấy lời giải thích tốt về ý nghĩa của nó. Bạn có thể giải thích? Điểm của trang trí @property ở đây là gì?
Neil

2
nó có nghĩa là bạn có thể gọi phương thức này giống như một thuộc tính: tức là variable = model_instance.my_fieldcho kết quả giống như variable = model_instance.my_field()không có trình trang trí. cũng: stackoverflow.com/a/6618176/2198571
Wasil Sergejchot

1
Điều này không hoạt động, ít nhất là trong Django 1.5.1 / djangorestframework == 2.3.10. ModelSerializer không nhận được sự phù hợp ngay cả khi được gọi một cách rõ ràng trong thuộc tính Meta "trường".
ygneo

9
bạn cần thêm trường vào serializer bởi vì nó không có modelfield thực sự : my_field = serialators.Field (source = 'my_field')
Marius

2
source='my_field' không yêu cầu nữa và đưa ra một ngoại lệ
Guillaume Vincent

13

Với phiên bản cuối cùng của Django Rest Framework, bạn cần tạo một phương thức trong mô hình của mình với tên của trường bạn muốn thêm. Không cần @propertysource='field'đưa ra một lỗi.

class Foo(models.Model):
    . . .
    def foo(self):
        return 'stuff'
    . . .

class FooSerializer(ModelSerializer):
    foo = serializers.ReadOnlyField()

    class Meta:
        model = Foo
        fields = ('foo',)

Điều gì xảy ra nếu tôi muốn có requestđối tượng bên trong def foo (bản thân) có thể sửa đổi giá trị của foo? (ví dụ: tra cứu dựa trên request.user)
saran3h

1
Nếu giá trị của foo đến từ yêu cầu thì sao?
saran3h

11

Câu trả lời của tôi cho một câu hỏi tương tự ( ở đây ) có thể hữu ích.

Nếu bạn có Phương thức mô hình được xác định theo cách sau:

class MyModel(models.Model):
    ...

    def model_method(self):
        return "some_calculated_result"

Bạn có thể thêm kết quả của việc gọi phương thức đã nói vào serializer của mình như sau:

class MyModelSerializer(serializers.ModelSerializer):
    model_method_field = serializers.CharField(source='model_method')

ps Vì trường tùy chỉnh không thực sự là một trường trong mô hình của bạn, nên bạn thường muốn làm cho nó ở chế độ chỉ đọc, như vậy:

class Meta:
    model = MyModel
    read_only_fields = (
        'model_method_field',
        )

10

nếu bạn muốn đọc và viết trên trường thêm của mình, bạn có thể sử dụng trình tuần tự tùy chỉnh mới, mở rộng serializer.Serializer và sử dụng nó như thế này

class ExtraFieldSerializer(serializers.Serializer):
    def to_representation(self, instance): 
        # this would have the same as body as in a SerializerMethodField
        return 'my logic here'

    def to_internal_value(self, data):
        # This must return a dictionary that will be used to
        # update the caller's validation data, i.e. if the result
        # produced should just be set back into the field that this
        # serializer is set to, return the following:
        return {
          self.field_name: 'Any python object made with data: %s' % data
        }

class MyModelSerializer(serializers.ModelSerializer):
    my_extra_field = ExtraFieldSerializer(source='*')

    class Meta:
        model = MyModel
        fields = ['id', 'my_extra_field']

tôi sử dụng điều này trong các trường lồng nhau có liên quan với một số logic tùy chỉnh


2

Điều này làm việc cho tôi . Nếu chúng tôi muốn thêm một trường bổ sung vào ModelSerializer, chúng tôi có thể làm như dưới đây và trường cũng có thể được chỉ định một số val sau khi tính toán tra cứu. Hoặc trong một số trường hợp nếu chúng tôi muốn gửi các tham số trong phản hồi API.

Trong mô hình

class Foo(models.Model):
    """Model Foo"""
    name = models.CharField(max_length=30, help_text="Customer Name")



   **

Trong serializer.py

**

class FooSerializer(serializers.ModelSerializer):
    retrieved_time = serializers.SerializerMethodField()

    @classmethod
    def get_retrieved_time(self, object):
        """getter method to add field retrieved_time"""
        return None

  class Meta:
        model = Foo
        fields = ('id', 'name', 'retrieved_time ')

**

Hy vọng điều này có thể giúp ai đó

**


Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.