Django REST框架 - 仅针对经过身份验证的用户的查询集筛选器

时间:2018-05-15 14:57:42

标签: django django-rest-framework

我是Django REST Framework的新手。我想我已经搞砸了,因为有时感觉DRF很容易理解,但后来它搞砸了。

我有一个contacts申请。

联系人/ models.py

class Contact(models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE)
    first_name = models.CharField(max_length=100)
    last_name = models.CharField(max_length=100, blank=True, null=True)
    date_of_birth = models.DateField(blank=True, null=True)


class ContactEmail(models.Model):
    contact = models.ForeignKey(Contact, on_delete=models.CASCADE)
    email = models.EmailField()


class ContactPhoneNumber(models.Model):
    contact = models.ForeignKey(Contact, on_delete=models.CASCADE)
    phone = models.CharField(max_length=100)

每个联系人都与一些经过身份验证的用户相关。

联系人/ serializers.py

class ContactPhoneNumberSerializer(serializers.ModelSerializer):
    class Meta:
        model = ContactPhoneNumber
        fields = ('id', 'phone')


class ContactEmailSerializer(serializers.ModelSerializer):
    class Meta:
        model = ContactEmail
        fields = ('id', 'email')


class ContactSerializer(serializers.HyperlinkedModelSerializer):
    phone_numbers = ContactPhoneNumberSerializer(source='contactphonenumber_set', many=True)
    emails = ContactEmailSerializer(source='contactemail_set', many=True)

    class Meta:
        model = Contact
        fields = ('url', 'id', 'first_name', 'last_name', 'date_of_birth',
                   'phone_numbers', 'emails')

contacts / views.py

class ContactViewSet(viewsets.ModelViewSet):
    queryset = Contact.objects.all()
    serializer_class = ContactSerializer
    permission_classes = (IsAuthenticated, AdminAuthenticationPermission,)

    def perform_create(self, serializer):
        serializer.save(user_id=self.request.user)
到目前为止,我遵循Django REST Framework的文档,但它显示了所有联系人,而不是仅显示用户的联系人。

为此,我添加了get_queryset()

class ContactViewSet(viewsets.ModelViewSet):
    # queryset = Contact.objects.all()
    ...
    def get_queryset(self):
        return Contact.objects.filter(user=self.request.user)
    ...

但它开始给出错误

assert queryset is not None, '`base_name` argument not specified, and could ' \
AssertionError: `base_name` argument not specified, and could not automatically determine the name from the viewset, as it does not have a `.queryset` attribute.

在做了一些研究后,我发现在路由器

中添加了第三个参数

应用/ urls.py

router = routers.DefaultRouter()
router.register(r'contacts', ContactViewSet, 'contacts') # added 'contacts' here

urlpatterns = [
    path('api/', include(router.urls))
]

但不是解决问题,而是产生了新的错误

django.core.exceptions.ImproperlyConfigured: Could not resolve URL for hyperlinked 
relationship using view name "contact-detail". 
You may have failed to include the related model in your API, or incorrectly configured the `lookup_field` attribute on this field.

在做了一些研究之后,找到了在url中定义searializers.py的解决方案。所以,我更新了contacts/serializers.py

class ContactSerializer(serializers.HyperlinkedModelSerializer):
    phone_numbers = ...
    emails = ...

    url = serializers.HyperlinkedRelatedField(
        view_name='contacts:detail'
    )

    class Meta:
        model = Contact
        fields = ('url', 'id', 'first_name', 'last_name', 'date_of_birth',
                   'phone_numbers', 'emails')

但现在,它已经开始发出新的错误

'Relational field must provide a `queryset` argument, '
AssertionError: Relational field must provide a `queryset` argument, override `get_queryset`, or set read_only=`True`.

由于我的应用程序是基于用户的,并且每个经过身份验证的用户都可以查看/编辑/删除自己的数据,因此只有基于request.user过滤对象的简单方法。 < / p>

此外,有没有办法让这个问题得到解决,因为我在这里混淆了哪个关系字段?

2 个答案:

答案 0 :(得分:0)

我没有使用ModelViewSet。 但是在常规APIView中,你可以这样做:

class SingleProject(APIView):
    def get(self, request):
        project_id = request.query_params.get('id')
        ans = Project.objects.filter(id=project_id)
        serializer = EagerGetProjectSerializer(qs, many=True)
        return Response(serializer.data, status=status.HTTP_200_OK)

所以也许是这样的:

class ContactViewSet(viewsets.ModelViewSet):
    queryset = Contact.objects.filter(user=self.request.user)
    serializer_class = ContactSerializer
    permission_classes = (IsAuthenticated, AdminAuthenticationPermission,)

答案 1 :(得分:0)

这解决了我的问题

read_only=True设为url

url = serializers.HyperlinkedRelatedField(
    view_name='contacts:detail',
    read_only=True
)