25👍
You can do this by creating a field on your TrackSerializer
that has a custom source
that retrieves the album name.
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’).
So in your case, the field album_name
would need to be added with the custom source
set
class TrackSerializer(serializers.ModelSerializer):
album_name = serializers.CharField(read_only=True, source="album.name")
class Meta:
model = Track
fields = ("album_name", )
This will include the album name in the output under the key album_name
.
9👍
To include the parent relation you only need to include its serializer and include it in the fields list.
Class TrackSerializer(ModelSerializer):
album = AlbumSerializer()
class Meta:
model = Track
fields = ('name', 'year', 'album',)
- [Django]-How to add Search_fields in Django
- [Django]-How can I correctly set DJANGO_SETTINGS_MODULE for my Django project (I am using virtualenv)?
- [Django]-Filtering ListAPIView in django-rest-framework
2👍
I wanted to create a browseable api for one of my Django 2.0 projects, one that would allow a api user to drill down with hyperlinks into the children and then back again, or even start with a child and find the parent or grandparent through a hyperlinks. Also, instead of using the pk
number, I wanted to use a slug field for finding the relations.
I could not find any complete solution for what I wanted to do, just bits and pieces, but I was finally able to putting a working api together. I hope that someone will find the solution that, extends the ‘Album – Track’ example, useful.
I apologise for all the code, but by copying and pasting you should be able to put together a working example.
This is this content in my models.py
file. Please note the “related_name” parameter in the ForeignKey-fields. It is really important to make the whole setup work.
#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()
Below is serializers.py
. This is where I struggled the most with the error 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. The key to getting the url for the parents lie in the queryset
parameter of the HyperlinkRelatedField
serializer along with lookup_field= 'slug'
. Below is my serializer classes.
#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')
Here the content of my 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'),
]
Next views.py
. Please note the lookup_field='slug'
in the ...Detail(RetrieveUpdateDestroyAPIView):
classes.
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
Using this approach I was able to product the following JSON for tracks from where one can find both the related artist and album:
{
"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/"
}
And for the albums I am able to generate JSON that looks like below, which allows one to find the artist and all the tracks of the album.
{
"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/"
]
}
- [Django]-How to customize the auth.User Admin page in Django CRUD?
- [Django]-Distributed task queues (Ex. Celery) vs crontab scripts
- [Django]-How do I set user field in form to the currently logged in user?
0👍
You can do it this way (making use of Python dynamism):
def create_serializer(target_class, fields):
class ModelSerializer(serializers.ModelSerializer):
class Meta:
model = target_class
fields = fields
return ModelSerializer
So, a Track serializer can be created using this approach:
TrackSerializer = create_serializer(Track, ('album__name',))
Also, be careful of (‘album__name’), which is a parenthesized string expression and not a tuple as you probably intended. To declare it as a tuple, add a comma after it, like this:
fields = ('album__name',)
- [Django]-How can I set the field unique in django?
- [Django]-How to remove all of the data in a table using Django
- [Django]-Manage.py runserver
-4👍
Looks like you need You need Serializer relations.
It also appears a question very similar to this has been asked already: django rest framework view does'nt show related table data
- [Django]-What does "'tests' module incorrectly imported" mean?
- [Django]-Redirect after POST django rest framework
- [Django]-Site matching query does not exist