django rest framework lookup_field through OneToOneField
This is how I managed to hack it
models.py
from django.db import models
from django.contrib.auth.models import User
class Speaker(models.Model):
user = models.OneToOneField(User)
@property
def user__username(self):
return self.user.username
def __unicode__(self):
return self.user.username
serializers.py
from .models import Speaker
from rest_framework import serializers
from django.contrib.auth.models import User
class UserSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = User
fields = ('url', 'username', 'email', 'groups')
lookup_field = 'username'
class SpeakerSerializer(serializers.HyperlinkedModelSerializer):
user = serializers.HyperlinkedRelatedField(
view_name='user-detail',
read_only=True,
lookup_field='username'
)
class Meta:
model = Speaker
fields = ('url', 'user')
lookup_field = 'user__username'
view.py
from .models import Speaker
from .serializers import SpeakerSerializer, UserSerializer
from rest_framework import viewsets
from django.contrib.auth.models import User
class UserViewSet(viewsets.ModelViewSet):
queryset = User.objects.all()
serializer_class = UserSerializer
lookup_field = 'username'
class SpeakerViewSet(viewsets.ModelViewSet):
queryset = Speaker.objects.all().select_related('user')
serializer_class = SpeakerSerializer
lookup_field = 'user__username'
Related videos on Youtube
Randall Hunt
Randall Hunt is a Senior Technical Evangelist and Software Engineer at Amazon Web Services in Los Angeles. Randall spends most of his time building demos and writing about new services and launches. Python is his favorite programming language but he can sometimes be found in the dark realm of C++. Prior to working at AWS, Randall launched rockets at NASA and SpaceX but he found his programming passion at MongoDB. He is a total space nerd. Randall has dealt with a wide range of both business and technical issues across many different verticals based on his experiences at SpaceX, MongoDB, AWS, and NASA. Thanks to these experiences Randall has gained a deep understanding of deploying large-scale technical solutions in cloud environments. As a Sr. Technical Evangelist, Randall often speaks at conferences and events across the world where he helps developers maximize their productivity in the cloud. He's particularly interested in AI, databases, serverless, and DevOps. He holds all AWS certifications.
Updated on July 09, 2022Comments
-
Randall Hunt almost 2 years
https://gist.github.com/ranman/3d97ea9054c984bca75e
Desired Behavior
User lookup happens by the username:/api/users/randall
Speaker lookup happens by the username as well:/api/speakers/randall
Constraints
Not all users are speakers. All speakers are users.models.py
from django.contrib.auth.models import User class Speaker(models.Model): user = models.OneToOneField(User)
serializers.py
class UserSerializer(serializers.HyperlinkedModelSerializer): class Meta: model = User fields = ('url', 'username', 'email', 'groups') lookup_field = 'username' class SpeakerSerializer(serializers.HyperlinkedModelSerializer): user = serializers.HyperlinkedRelatedField( view_name='user-detail', read_only=True, lookup_field='username' ) class Meta: model = Speaker lookup_field = 'user'
views.py
class UserViewSet(viewsets.ModelViewSet): queryset = User.objects.all() serializer_class = UserSerializer lookup_field = 'username' class SpeakerViewSet(viewsets.ModelViewSet): queryset = Speaker.objects.all().select_related('user') serializer_class = SpeakerSerializer lookup_field = "user"
I've tried various different invocations of lookup_field and serializer types to get this working to no avail. It may not be possible without a lot more code. I'm just wondering what direction I can take.
-
Kevin Brown-Silva about 9 yearsHave you tried using double underscores in the
lookup_field
to see if that can work? It'd be similar to a queryset filter. -
Randall Hunt about 9 yearsI've tried using
lookup_field = "user__username"
and it doesn't work. I've tried using that on both the model and the view to no avail :('Speaker' object has no attribute 'user__username'
-
levi about 9 years@ranman what do you want ? do you want to serialize a related object ?
-
Randall Hunt about 9 yearsI want to be able to lookup the speaker object by the username on the user associated with the speaker
-
-
Randall Hunt about 9 years
'Speaker' object has no attribute 'user__username'
doesn't seem to work. I might have implemented it incorrectly. -
Randall Hunt about 9 yearsActually it doesn't work -- for some reason this doesn't allow 2 things: the user field is no longer able to be written to when you create a new speaker, the speaker is no longer renderable on items that have relations to it
-
Todor about 9 yearsHow can i reproduce your errors? I mean I tried to create a new
speaker
via the python shell and it pass with no problems, if you try to create aspeaker
via theapi
, well theuser
field is marked asread-only
, that's why it doesn't work. I also created a dummy model havingOneToOneField
to thespeaker
, this also worked with bothModelSerializer
andHyperlinkedModelSerializer
with the 2nd one i just had to redefine thespeaker
field with asHyperlinkedRelatedField
withlookup_field='user__username'
(the same thing was done in theSpeakerSerializer
for theuser
field.