Truy xuất giá trị Khóa ngoại bằng trình tuần tự django-rest-framework


83

Tôi đang sử dụng khung phần còn lại django để tạo API. Tôi có các mô hình sau:

class Category(models.Model):
    name = models.CharField(max_length=100)

    def __unicode__(self):
        return self.name


class Item(models.Model):
    name = models.CharField(max_length=100)
    category = models.ForeignKey(Category, related_name='items')

    def __unicode__(self):
        return self.name

Để tạo bộ tuần tự cho các danh mục, tôi phải làm:

class CategorySerializer(serializers.ModelSerializer):
    items = serializers.RelatedField(many=True)

    class Meta:
        model = Category

... và điều này sẽ cung cấp cho tôi:

[{'items': [u'Item 1', u'Item 2', u'Item 3'], u'id': 1, 'name': u'Cat 1'},
 {'items': [u'Item 4', u'Item 5', u'Item 6'], u'id': 2, 'name': u'Cat 2'},
 {'items': [u'Item 7', u'Item 8', u'Item 9'], u'id': 3, 'name': u'Cat 3'}]

Tôi sẽ làm thế nào về việc lấy ngược lại từ bộ tuần tự hóa Mục, tức là:

[{u'id': 1, 'name': 'Item 1', 'category_name': u'Cat 1'},
{u'id': 2, 'name': 'Item 2', 'category_name': u'Cat 1'},
{u'id': 3, 'name': 'Item 3', 'category_name': u'Cat 1'},
{u'id': 4, 'name': 'Item 4', 'category_name': u'Cat 2'},
{u'id': 5, 'name': 'Item 5', 'category_name': u'Cat 2'},
{u'id': 6, 'name': 'Item 6', 'category_name': u'Cat 2'},
{u'id': 7, 'name': 'Item 7', 'category_name': u'Cat 3'},
{u'id': 8, 'name': 'Item 8', 'category_name': u'Cat 3'},
{u'id': 9, 'name': 'Item 9', 'category_name': u'Cat 3'}]

Tôi đã đọc qua các tài liệu về mối quan hệ đảo ngược cho khung còn lại nhưng điều đó có vẻ là kết quả giống với các trường không đảo ngược. Tôi có thiếu một cái gì đó rõ ràng không?

Câu trả lời:


82

Chỉ cần sử dụng một trường liên quan mà không cần thiết lập many=True.

Lưu ý rằng cũng vì bạn muốn đầu ra được đặt tên category_name, nhưng trường thực tế là category, bạn cần sử dụng sourceđối số trên trường bộ tuần tự.

Những điều sau đây sẽ cung cấp cho bạn đầu ra bạn cần ...

class ItemSerializer(serializers.ModelSerializer):
    category_name = serializers.RelatedField(source='category', read_only=True)

    class Meta:
        model = Item
        fields = ('id', 'name', 'category_name')

21
điều gì về truy xuất tất cả các trường của mô hình catagory ??
AJ

12
nếu bạn muốn lấy tất cả các lĩnh vực thể loại mô hình thực hiện các hạng mục serializer và có nó trong mã như CATEGORY_NAME = CategorySerliazer ()
Faizan Ali

7
Tôi cố gắng để làm điều này nhưng tôi nhận được một lỗi Relational field must provide a 'queryset' argument, or set read_only='True'
ePascoal

hoặc cung cấp thuộc tính bộ truy vấn nếu bạn muốn hỗ trợ tạo / cập nhật, đại loại như: category_name = serializers.RelatedField(source='category', queryset=Category.objects.all()) Tôi cho là vậy.
stelios

1
Nếu bạn nhận được, hãy AssertionError:...sử dụng câu trả lời này stackoverflow.com/a/44530606/5403449
Josh

82

Trong phiên bản DRF 3.6.3, điều này phù hợp với tôi

class ItemSerializer(serializers.ModelSerializer):
    category_name = serializers.CharField(source='category.name')

    class Meta:
        model = Item
        fields = ('id', 'name', 'category_name')

Có thể tìm thấy thêm thông tin tại đây: Các đối số cốt lõi của Trường Serializer


Nhưng bạn phải là đồ đạc vì nó sẽ xuất hiện lỗi NoneType nếu trường danh mục Trong mô hình Item được đặt thành trống = True
Desert Camel

29

Một điều khác bạn có thể làm là:

  • tạo một thuộc tính trong Itemmô hình của bạn để trả về tên danh mục và
  • phơi bày nó như là một ReadOnlyField.

Mô hình của bạn sẽ giống như thế này.

class Item(models.Model):
    name = models.CharField(max_length=100)
    category = models.ForeignKey(Category, related_name='items')

    def __unicode__(self):
        return self.name

    @property
    def category_name(self):
        return self.category.name

Serializer của bạn sẽ trông như thế này. Lưu ý rằng bộ tuần tự sẽ tự động lấy giá trị của thuộc tính category_namemô hình bằng cách đặt tên trường có cùng tên.

class ItemSerializer(serializers.ModelSerializer):
    category_name = serializers.ReadOnlyField()

    class Meta:
        model = Item

16

điều này làm việc tốt cho tôi:

class ItemSerializer(serializers.ModelSerializer):
    category_name = serializers.ReadOnlyField(source='category.name')
    class Meta:
        model = Item
        fields = "__all__"

9

Làm việc vào ngày 08/08/2018 và trên phiên bản DRF 3.8.2:

class ItemSerializer(serializers.ModelSerializer):
    category_name = serializers.ReadOnlyField(source='category.name')

    class Meta:
        model = Item
        read_only_fields = ('id', 'category_name')
        fields = ('id', 'category_name', 'name',)

Bằng cách sử dụng Meta, read_only_fieldschúng ta có thể khai báo chính xác trường nào nên được read_only. Sau đó, chúng ta cần khai báo foreigntrường trên Meta fields(tốt hơn nên rõ ràng như câu thần chú: zen of python ).


5

Giải pháp đơn giản source='category.name'đâu categorylà khóa ngoại và .namethuộc tính của nó.

from rest_framework.serializers import ModelSerializer, ReadOnlyField
from my_app.models import Item

class ItemSerializer(ModelSerializer):
    category_name = ReadOnlyField(source='category.name')

    class Meta:
        model = Item
        fields = "__all__"

0

Giải pháp này tốt hơn vì không cần xác định mô hình nguồn. Nhưng tên của trường bộ tuần tự phải giống với tên trường khóa ngoại

class ItemSerializer(serializers.ModelSerializer):
    category = serializers.SlugRelatedField(read_only=True, slug_field='title')

    class Meta:
        model = Item
        fields = ('id', 'name', 'category')
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.