暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

Django Rest Framework:「故障排除」'str' object is not callable

Nephilim 2024-05-13
100

Tips:一些记录,一些笔记



2024/05/13

MONDAY

「王嘉一」在《给我》中唱到:


所有的安,所有的乱

天命尚未过半,

我怎么把酒言欢。


借我十个胆,与红尘纠缠

要几次爱恨才够离合悲欢


借我十个胆,过余生的关

就算这人心的弯连成环


借我十个胆,求此生无憾

所有答案都等在对岸


我借星几盏,借风为帆

借梦入万重山。




01

错误详情


如题所示的错误发生在Django配置了DRF(Django RestFramework)之后,通过序列化类与类视图访问数据模型类的时候。


具体错误如下:

    TypeError at api/category/
    'str' object is not callable
    Request Method: GET
    Request URL: http://localhost:8000/api/category/
    Django Version: 5.0.6
    Exception Type: TypeError
    Exception Value:
    'str' object is not callable
    Exception Location: /Users/adamhuan/PycharmProjects/django_daily_media/venv/lib/python3.11/site-packages/rest_framework/generics.py, line 154, in filter_queryset
    Raised during: movie.views.CategoryViewSet
    Python Executable: /Users/adamhuan/PycharmProjects/django_daily_media/venv/bin/python
    Python Version: 3.11.5
    Python Path:
    ['/Users/adamhuan/PycharmProjects/django_daily_media',
    '/Users/adamhuan/PycharmProjects/django_daily_media',
    '/Applications/PyCharm.app/Contents/plugins/python/helpers/pycharm_display',
    '/Users/adamhuan/anaconda3/lib/python311.zip',
    '/Users/adamhuan/anaconda3/lib/python3.11',
    '/Users/adamhuan/anaconda3/lib/python3.11/lib-dynload',
    '/Users/adamhuan/PycharmProjects/django_daily_media/venv/lib/python3.11/site-packages',
    '/Applications/PyCharm.app/Contents/plugins/python/helpers/pycharm_matplotlib_backend']
    Server time: Mon, 13 May 2024 22:23:20 +0800


    发生该错误的时候,和该错误直接的文件:

    • 全局配置文件「settings.py」

    • 相关应用的视图「views.py」


    其他的相关文件:

    • 相关应用的数据模型「models.py」

    • 相关应用的序列化类「serializers.py」

    • 全局路由配置文件「urls.py」


    一、先来看看「相关文件」


    数据模型类「models.py」:

      from django.db import models


      # Create your models here.


      # 地区
      Region = [
      (1,'中国大陆'),
      (2,'中国香港'),
      (3,'中国台湾'),
      (4,'美国'),
      (5,'韩国'),
      (6,'日本'),
      (7,'其他')
      ]
      # 清晰度
      Quality = [
      (1, '720P'),
      (2, '1080P'),
      (3, '4K')
      ]


      # 热门精选
      Hot = [
      (False,'否'),
      (True,'是')
      ]
      # 置顶
      Top = [
      (False,'否'),
      (True,'是')
      ]
      # 是否显示
      SHOW = [
      (False, '否'),
      (True, '是')
      ]
      # 是否免费
      FREE = [
      (False, '否'),
      (True, '是')
      ]


      # 分类信息
      class Category(models.Model):
      # 分类信息
      id = models.AutoField(primary_key=True)
      category_name = models.CharField(max_length=100,verbose_name='分类名')


      class Meta:
      verbose_name = '分类管理'
      verbose_name_plural = '分类管理'


      def __str__(self):
      return self.category_name



      序列化类「serializers.py」

        #!/usr/bin/env python
        # -*- coding: UTF-8 -*-


        # ——————————————————
        # 脚本说明:
        # xxxxxxxxx
        # ——————————————————


        # ========================================
        # 开始
        # ))))))))) 模块包导入
        from rest_framework import serializers


        from movie.models import *


        # ))))))))) 类名


        class CategorySerializer(serializers.ModelSerializer):
        class Meta:
        model = Category
        fields = "__all__"


        # ))))))))) 执行阶段


        # ))))))))) 结束


        # ========================================
        # 结束



        全局路由配置文件「urls.py

          """
          URL configuration for django_daily_media project.


          The `urlpatterns` list routes URLs to views. For more information please see:
          https://docs.djangoproject.com/en/5.0/topics/http/urls/
          Examples:
          Function views
          1. Add an import: from my_app import views
          2. Add a URL to urlpatterns: path('', views.home, name='home')
          Class-based views
          1. Add an import: from other_app.views import Home
          2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
          Including another URLconf
          1. Import the include() function: from django.urls import include, path
          2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
          """
          from django.contrib import admin
          from django.urls import path, include


          # 视图
          from movie.views import *


          # Django Rest Framework
          from rest_framework.routers import DefaultRouter
          router = DefaultRouter()


          router.register("category", CategoryViewSet)


          # Django 路由
          urlpatterns = [
          # Django 后台管理
          path("admin/", admin.site.urls),
          # Django Rest Framework
          path("api/", include(router.urls)),
          ]



          二、再来看看「直接导致错误」的文件的配置


          全局配置文件「settings.py」

          可以看到,Django集成了Django RestFramework。

          在全局配置文件中,可以看到集成的Django RestFramework启用了:

          • 分页

          • 过滤器


          问题出现在「FILTER」的设置


          再来看看视图的设置「views.py」

            from django.shortcuts import render


            from rest_framework import viewsets
            from django_filters import rest_framework as filters


            from movie.models import *
            from movie.serializers import *


            # Create your views here.


            class CategoryFilter(filters.FilterSet):
            category_name = filters.CharFilter(lookup_expr='icontains')
            class Meta:
            model = Category
            fields = "__all__"


            class CategoryViewSet(viewsets.ModelViewSet):
            queryset = Category.objects.all()
            serializer_class = CategorySerializer
            # filter_backends = (filters.DjangoFilterBackend,)
            # filterset_class = CategoryFilter


            上面代码的状态是「发生错误」的时候的状态。


            可以看到:

            当你的Django RestFramework启用了Filter策略后,定义的「ModelViewSet」必须定义「Filter」的相关配置:

            • filter_backends

            • filterset_class / filterset_fields


            否则你就会遇到如题所示的错误:

              'str' object is not callable


              02

              解决方法


              如果要保留Django Rest Framework的Filter功能,你需要修改的是具体应用的视图「views.py」的设置;

              为每个ModelViewSet实现「Filter」的相关定义。


              在我的这个案例中,将「views.py」修改为下列状态:

                from django.shortcuts import render


                from rest_framework import viewsets
                from django_filters import rest_framework as filters


                from movie.models import *
                from movie.serializers import *


                # Create your views here.


                class CategoryFilter(filters.FilterSet):
                category_name = filters.CharFilter(lookup_expr='icontains')
                class Meta:
                model = Category
                fields = "__all__"


                class CategoryViewSet(viewsets.ModelViewSet):
                queryset = Category.objects.all()
                serializer_class = CategorySerializer
                filter_backends = (filters.DjangoFilterBackend,)
                filterset_class = CategoryFilter



                然后,再访问前端页面,就没问题了:

                http://localhost:8000/api/


                http://localhost:8000/api/category/





                END




                温馨提示



                如果你喜欢本文,请分享到朋友圈,想要获得更多信息,请关注我。


                文章转载自Nephilim,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

                评论