如何在 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',)
我有这个型号:
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',)