如何在 Django Rest Framework 序列化程序中获取父对象

How can I get the parent object in Django Rest Framework serializer

我有这个型号:

class Track(models.Model):
    album = models.ForeignKey(Album)

现在在我的 TrackSerializer 中,我想获取相册的名称。

class TrackSerializer(serializers.ModelSerializer):

    class Meta:
        model = Track
        fields = ('album__name')

没用。

我不想为此声明 AlbumSerializer。有没有办法在不声明新的序列化程序的情况下做到这一点?

看起来你需要你需要 Serializer relations.

似乎已经有人问过一个与此非常相似的问题:

你可以这样做(利用 Python 动态):

def create_serializer(target_class, fields):
    class ModelSerializer(serializers.ModelSerializer):

        class Meta:
            model = target_class
            fields = fields

    return ModelSerializer

因此,可以使用这种方法创建 Track 序列化程序:

TrackSerializer = create_serializer(Track, ('album__name',))

此外,请注意 ('album__name'),这是一个带括号的字符串表达式,而不是您可能想要的 tuple。要将其声明为元组,请在其后添加一个逗号,如下所示:

fields = ('album__name',)

您可以通过在 TrackSerializer 上创建一个 has a custom source 检索相册名称的字段来实现。

The name of the attribute that will be used to populate the field. May be a method that only takes a self argument, such as URLField('get_absolute_url'), or may use dotted notation to traverse attributes, such as EmailField(source='user.email').

因此,在您的情况下,需要使用自定义 source

添加字段 album_name
class TrackSerializer(serializers.ModelSerializer):
    album_name = serializers.CharField(read_only=True, source="album.name")

    class Meta:
        model = Track
        fields = ("album_name", )

这将在键 album_name 下的输出中包含相册名称。

我想为我的一个 Django 2.0 项目创建一个可浏览的 api,一个允许 api 用户通过超链接向下钻取到 children 然后再次返回,甚至从 child 开始并通过超链接找到 parent 或 grandparent。另外,我没有使用 pk 数字,而是想使用 slug 字段来查找关系。

对于我想做的事情,我找不到任何完整的解决方案,只是零零碎碎的,但我终于能够将工作 api 放在一起。我希望有人会找到扩展 'Album - Track' 示例的有用解决方案。

对于所有代码,我深表歉意,但通过复制和粘贴,您应该能够组合出一个工作示例。

这是我的 models.py 文件中的内容。请注意 ForeignKey-fields 中的 "related_name" 参数。让整个设置正常工作非常重要。

#models.py
class Artist(models.Model):
    name = models.CharField(max_length=100, blank=False)
    slug = models.SlugField(unique=True, blank=False)

class Album(models.Model):
    artist = models.ForeignKey(Artist, blank=False, 
                    on_delete=models.SET_DEFAULT, 
                    default=1, related_name='albums')
    name = models.CharField(max_length=100, blank=False)
    year = models.IntegerField()
    slug = models.SlugField(unique=True, blank=False)

class Track(models.Model):
    artist = models.ForeignKey(Artist, blank=False, 
                     on_delete=models.SET_DEFAULT, default=1, 
                     related_name='artist_tracks')
    album = models.ForeignKey(Album, blank=True, null=True,  
                     on_delete=models.SET_NULL, 
                     related_name='album_tracks')
    name = models.CharField(max_length=100)
    year = models.IntegerField()

下面是serializers.py。这是我与错误 Could not resolve URL for hyperlinked relationship using view name "artist-detail". You may have failed to include the related model in your API, or incorrectly configured the 'lookup_field' attribute on this field. 最纠结的地方 Resolving the children was quote easy and is facilitated by the model.为 parent 获取 url 的关键在于 HyperlinkRelatedField 序列化程序的 queryset 参数以及 lookup_field= 'slug'。下面是我的序列化器 类.

#serializers.py
class ArtistSerializer(serializers.HyperlinkedModelSerializer):
    albums = serializers.HyperlinkedRelatedField(
        many=True,
        read_only=True,
        view_name='album-detail',
        lookup_field='slug')
    class Meta:
        model = Artist
        fields = ('url', 'name', 'slug', 'albums') #, 'artist_tracks'
        lookup_field = 'slug',
        extra_kwargs = {
            'url': {'lookup_field': 'slug'}
        }

class AlbumSerializer(serializers.HyperlinkedModelSerializer):
    artist = serializers.HyperlinkedRelatedField(
        queryset=Artist.objects.all(),
        lookup_field='slug',
        view_name='artist-detail'
    )
    album_tracks = serializers.HyperlinkedRelatedField(
        many=True,
        read_only=True,
        view_name='track-detail'
    )
    class Meta:
        model = Album
        fields = ('url', 'name', 'artist', 'album_tracks')
        lookup_field = 'slug',
        extra_kwargs = {
            'url': {'lookup_field': 'slug'}
        }

class TrackSerializer(serializers.HyperlinkedModelSerializer):
    artist = serializers.HyperlinkedRelatedField(
        queryset=Artist.objects.all(),
        lookup_field='slug',
        view_name='artist-detail'
    )
    album = serializers.HyperlinkedRelatedField(
        queryset=Album.objects.all(),
        lookup_field='slug',
        view_name='album-detail'
    )
    class Meta:
        model = Track
        fields = ('url', 'name', 'artist', 'album')

这是我的 urls.py.

的内容
#urls.py
urlpatterns = [
    path('artist/', ArtistList.as_view(), name='artist-list'),
    path('artist/<slug:slug>/', ArtistDetail.as_view(), name='artist-detail'),
    path('album/', AlbumList.as_view(), name='album_list'),
    path('album/<slug:slug>/', AlbumDetail.as_view(), name='album-detail'),
    path('track/', TrackList.as_view(), name='track-list'),
    path('track/<int:pk>/', TrackDetail.as_view(), name='track-detail'),
]

下一个views.py。请注意 ...Detail(RetrieveUpdateDestroyAPIView): 类.

中的 lookup_field='slug'
class ArtistList(ListCreateAPIView):
    queryset = Artist.objects.all()
    serializer_class = ArtistSerializer

class ArtistDetail(RetrieveUpdateDestroyAPIView):
    queryset = Artist.objects.all()
    serializer_class = ArtistSerializer
    lookup_field = 'slug'

class AlbumList(ListCreateAPIView):
    queryset = Album.objects.all()
    serializer_class = AlbumSerializer

class AlbumDetail(RetrieveUpdateDestroyAPIView):
    queryset = Album.objects.all()
    serializer_class = AlbumSerializer
    lookup_field = 'slug'

class TrackList(ListCreateAPIView):
    queryset = Track.objects.all()
    serializer_class = TrackSerializer

class TrackDetail(RetrieveUpdateDestroyAPIView):
    queryset = Track.objects.all()
    serializer_class = TrackSerializer

使用这种方法,我能够为可以找到相关艺术家和专辑的曲目生成以下 JSON:

{
"url": "http://127.0.0.1:8000/api/track/4/",
"name": "Lifeline",
"artist": "http://127.0.0.1:8000/api/artist/neal-morse/",
"album": "http://127.0.0.1:8000/api/album/lifeline/"
}

对于专辑,我可以生成如下所示的 JSON,这样可以找到艺术家和专辑的所有曲目。

{
"url": "http://127.0.0.1:8000/api/album/lifeline/",
"name": "Lifeline",
"artist": "http://127.0.0.1:8000/api/artist/neal-morse/",
"album_tracks": [
    "http://127.0.0.1:8000/api/track/4/",
    "http://127.0.0.1:8000/api/track/5/",
    "http://127.0.0.1:8000/api/track/6/"
]
}

要包含父关系,您只需包含其序列化程序并将其包含在字段列表中。

Class TrackSerializer(ModelSerializer):
    album = AlbumSerializer()

    class Meta:
         model = Track
         fields = ('name', 'year', 'album',)