django 休息框架通过 OneToOneField 查找字段

问题描述 投票:0回答:5

https://gist.github.com/ranman/3d97ea9054c984bca75e

期望的行为
用户查找通过用户名进行:

/api/users/randall

发言者查找也通过用户名进行:
/api/speakers/randall

限制
并非所有用户都是演讲者。所有发言者都是用户。

模型.py

from django.contrib.auth.models import User

class Speaker(models.Model):
    user = models.OneToOneField(User)

序列化器.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"

我尝试了各种不同的lookup_field 和序列化器类型的调用,但没有成功。如果没有更多代码,这可能是不可能的。我只是想知道我可以采取什么方向。

python django rest django-rest-framework
5个回答
13
投票

这就是我成功破解它的方法

模型.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

序列化器.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'

视图.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'

1
投票

我对您的代码进行的唯一更改是通过使用用户名而不是默认的

get_object
进行过滤来覆盖
pk
方法。我还将
lookup_field
更改为描述性名称,并在
ModelSerializer
中使用了
StringRelated
serializer.py

模型.py

class Speaker(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE)

序列化器.py

class SpeakerSerializer(serializers.ModelSerializer):
    user = serializers.StringRelatedField(read_only=True)

    class Meta:
        model = Speaker
        lookup_field = "username"
        fields = "__all__"

views.py

class SpeakerViewSet(ModelViewSet):
    queryset = Speaker.objects.all().select_related("user")
    serializer_class = SpeakerSerializer
    lookup_field = "username"

    def get_object(self):
        """Return the object for this view."""
        return get_object_or_404(self.queryset, user__username=self.kwargs["username"])

urlconf

 api/ ^speaker/$ [name='speaker-list']
 api/ ^speaker\.(?P<format>[a-z0-9]+)/?$ [name='speaker-list']
 api/ ^speaker/(?P<username>[^/.]+)/$ [name='speaker-detail']
 api/ ^speaker/(?P<username>[^/.]+)\.(?P<format>[a-z0-9]+)/?$ [name='speaker-detail'] 

0
投票

你尝试过这种方法吗?

class SpeakerViewSet(viewsets.ModelViewSet):
    queryset = Speaker.objects.all().select_related('user')
    serializer_class = SpeakerSerializer
    filter_backends = (filters.DjangoFilterBackend,)
    filter_fields = ('user', 'user__username',)

0
投票

我正在使用用户 ID 获取用户的设置 [GET / Update]


urls.py

path('user/<int:user_id>/settings/preferences/', UserPreferenceSettingsView.as_view(), name="settings_preferences")

模型.py

class UserSetting(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    adult_lock = models.BooleanField(default=False)
    child_lock = models.BooleanField(default=False)
    promotional_email = models.BooleanField(default=True)
    update_email = models.BooleanField(default=True)
    updated_at = models.DateTimeField(auto_now=True)

views.py

class UserPreferenceSettingsView(generics.RetrieveUpdateAPIView):
    http_method_names = ['get', 'patch']    
    serializer_class = UserPreferenceSettingsSerializer

    def get_object(self):
        lookup_field = self.kwargs["user_id"]
        return get_object_or_404(UserSetting, user__pk=lookup_field)

如果您需要从

username
获取,只需将
user_id to username
和 url
<int:user_id>
替换为
<username> or <str:username>


0
投票

我偶然发现了这个问题,所提供的答案都无法解决我的问题,API 请求仍然在用户字段中显示“pk”而不是用户名。

我设法让它工作,只需添加一个字段到

serializer.py

class PublicationSerializer(serializers.ModelSerializer):
    #Field I had to add
    author = serializers.SlugRelatedField(
        many=False,
        read_only=True,
        slug_field='username'
    )

    class Meta:
        model = Publication
        fields = '__all__'

我的

viewsets.py
不需要任何新东西:

class PublicationViewSet(viewsets.ModelViewSet):
    queryset = Publication.objects.all()
    serializer_class = PublicationSerializer
    permission_classes = [IsAuthenticated]

还有我的

models.py

class Publication(models.Model):
    title= models.CharField(max_length=100)
    message = models.CharField(max_length=1000)
    author = models.ForeignKey(User, on_delete=models.CASCADE, blank=True)
© www.soinside.com 2019 - 2024. All rights reserved.