简体   繁体   中英

Django REST POST with PK to HyperlinkedModelSerializer, how to translate PK to URL?

I'm new to Django and Django REST. I have been creating a simple practice project.

Models:

class Locker(models.Model):
    locker_owner = models.ForeignKey(User, related_name='lockers', on_delete=models.CASCADE)
    locker_desc = models.CharField(max_length=100)
    locker_rating = models.IntegerField(default=0)

Serializers:

class LockerSerializer(serializers.ModelSerializer):
    locker_owner = serializers.HyperlinkedRelatedField(
        view_name='user-detail',
        lookup_field='id',
        queryset=User.objects.all())
    # how to add locker owner with id?

class Meta:
    model = Locker
    fields = ('url', 'locker_desc', 'locker_rating', 'locker_owner')

class UserSerializer(serializers.HyperlinkedModelSerializer):
    class Meta:
        model = User
        fields = ('url', 'id', 'username', 'email', 'groups')

Views:

class UserViewSet(viewsets.ModelViewSet):
    """
    API endpoint that allows users to be viewed or edited.
    """
    queryset = User.objects.all().order_by('-date_joined')
    serializer_class = UserSerializer

class LockerViewSet(viewsets.ModelViewSet):
    """
    API endpoint that allows lockers to be viewed or edited.
    """
    # def create(self, request):
    queryset = Locker.objects.all()
    serializer_class = LockerSerializer

I use this to POST:

ttp -f POST localhost:8000/lockers/ locker_owner_id=2 locker_desc='desc of locker 3' locker_rating=150

But then the response is

"locker_owner": [ "This field is required." ]

Main Point: I would like to create a new locker , and use User id as its locker_owner, yet still maintain the HyperlinkedModelSerializer . It won't let me, since they need url for locker_owner. Once I use hyperlink in the locker_owner of my POST request it works, but I don't know how to translate locker_owner=2 to it's url.

Any help would be appreciated. I have been looking for answers in days. Thank you!

This is not something you can do out-of-the-box. You will need to implement your own custom serializer Field, and override the to_representation method:

serializers.py

from rest_framework.reverse import reverse


class CustomRelatedField(serializers.PrimaryKeyRelatedField):

    def to_representation(self, value):
         return reverse('<your-user-detail-view-name>', args=(value.pk,), request=self.context['request'])


class LockerSerializer(serializers.ModelSerializer):
    locker_owner = CustomRelatedField(queryset=User.objects.all())

    class Meta:
       model = Locker
       fields = ('url', 'locker_desc', 'locker_rating', 'locker_owner')

You can then simply POST a simple JSON to create a new Locker object:

{
    "locker_owner": 2,
    "locker_desc": 'desc of locker 3',
    "locker_rating": 150
}

I have found the solution myself looking at the tutorials available. The other answers have not really answered the question fully.

For those wanting to get url of a foreign key to be saved, here, locker_owner, just get them using hyperlinked related field

In my serializer:

class LockerSerializer(serializers.HyperlinkedModelSerializer):
    locker_owner=serializers.HyperlinkedRelatedField(
        read_only=True,
        view_name='user-detail')

    class Meta:
        model = Locker
        fields = ('locker_desc', 'locker_rating', 'locker_owner')

I was trying to get the id in the lookup field, but actually the lookup field is searching the id from my url. That's why it could not find it. Simple and done. Thank you for all the answers.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM