目無(wú)法調(diào)用 swagger.json 接口數(shù)據(jù)的問(wèn)題)
在 Django REST Framework (DRF) 項(xiàng)目中Swagger (drf-yasg) 解析get_queryset()時(shí)如果get_queryset()返回list而不是QuerySet會(huì)導(dǎo)致AttributeError: list object has no attribute model錯(cuò)誤。本文記錄該問(wèn)題的調(diào)試過(guò)程及最終解決方案。Traceback(most recent call last):FileG:\MyGitProject\venv\dv3admin\lib\site-packages\rest_framework\views.py,line506,indispatch responsehandler(request,*args,**kwargs)FileG:\MyGitProject\venv\dv3admin\lib\site-packages\drf_yasg\views.py,line96,inget schemagenerator.get_schema(request,self.public)FileG:\MyGitProject\MyTools\MyToolsBak\MyToolsBak-HostServer\dvadmin\utils\swagger.py,line39,inget_schema swaggersuper().get_schema(request,public)FileG:\MyGitProject\venv\dv3admin\lib\site-packages\drf_yasg\generators.py,line276,inget_schema paths,prefixself.get_paths(endpoints,components,request,public)FileG:\MyGitProject\venv\dv3admin\lib\site-packages\drf_yasg\generators.py,line482,inget_paths operationself.get_operation(view,path,prefix,method,components,request)FileG:\MyGitProject\venv\dv3admin\lib\site-packages\drf_yasg\generators.py,line524,inget_operation operationview_inspector.get_operation(operation_keys)FileG:\MyGitProject\venv\dv3admin\lib\site-packages\drf_yasg\inspectors\view.py,line33,inget_operation queryself.get_query_parameters()FileG:\MyGitProject\venv\dv3admin\lib\site-packages\drf_yasg\inspectors\view.py,line293,inget_query_parameters natural_parametersself.get_filter_parameters()self.get_pagination_parameters()FileG:\MyGitProject\venv\dv3admin\lib\site-packages\drf_yasg\inspectors\base.py,line409,inget_filter_parameters fieldsself.probe_inspectors(self.filter_inspectors,get_filter_parameters,filter_backend())or[]FileG:\MyGitProject\venv\dv3admin\lib\site-packages\drf_yasg\inspectors\base.py,line110,inprobe_inspectors resultmethod(obj,**kwargs)FileG:\MyGitProject\venv\dv3admin\lib\site-packages\drf_yasg\inspectors\query.py,line42,inget_filter_parametersreturnlist(map(self.param_to_schema,filter_backend.get_schema_operation_parameters(self.view)))FileG:\MyGitProject\venv\dv3admin\lib\site-packages\django_filters\rest_framework\backends.py,line146,inget_schema_operation_parameters filterset_classself.get_filterset_class(view,queryset)FileG:\MyGitProject\venv\dv3admin\lib\site-packages\django_filters\rest_framework\backends.py,line40,inget_filterset_class queryset.model,filterset_model AttributeError:listobjecthas no attributemodel該錯(cuò)誤發(fā)生在drf-yasg解析 Swagger API 文檔時(shí)表明某個(gè)ViewSet的get_queryset()方法返回了list而 Swagger 期望QuerySet。錯(cuò)誤代碼示例# ? 錯(cuò)誤示例返回 listdefget_queryset(self):fixed_ids[11,12]fixed_recordsArticleTag.objects.filter(id__infixed_ids)remaining_recordsArticleTag.objects.exclude(id__infixed_ids)random_recordsremaining_records.order_by(?)[:5]querysetlist(fixed_records)list(random_records)# ? 把 QuerySet 變成了 listreturnqueryset# ? Swagger 解析失敗比如我的代碼里是這樣的仔細(xì)看發(fā)布時(shí)發(fā)現(xiàn)問(wèn)題了。defget_queryset(self):# 獲取固定的記錄fixed_ids[11,12]fixed_recordsArticleTag.objects.filter(id__infixed_ids)# 獲取其余的記錄remaining_recordsArticleTag.objects.exclude(id__infixed_ids)# 隨機(jī)選擇5個(gè)記錄random_recordsremaining_records.order_by(?)[:5]# 合并固定記錄和隨機(jī)記錄querysetlist(fixed_records)list(random_records)returnqueryset確保get_queryset()返回QuerySet使用union()合并多個(gè)QuerySet# ? 正確示例使用 union()defget_queryset(self):fixed_ids[11,12]fixed_recordsArticleTag.objects.filter(id__infixed_ids)remaining_recordsArticleTag.objects.exclude(id__infixed_ids)random_recordsremaining_records.order_by(?)[:5]querysetfixed_records.union(random_records)# ? 確保返回 QuerySetreturnqueryset?union()組合兩個(gè)QuerySet避免list類型錯(cuò)誤。如何調(diào)試get_queryset()返回類型手動(dòng)打印get_queryset()返回值類型# 在所有 ViewSet 里加入調(diào)試代碼importlogging loggerlogging.getLogger(__name__)defget_queryset(self):querysetArticleTag.objects.all()logger.debug(f 調(diào)試:{self.__class__.__name__}.get_queryset() 返回{type(queryset)})returnqueryset執(zhí)行 Swagger 請(qǐng)求 (http://127.0.0.1:8000/swagger.json) 后檢查django.log里打印的queryset類型。在 Django Shell 里手動(dòng)測(cè)試python manage.py shell然后執(zhí)行fromapp.viewsimportExampleViewSet viewExampleViewSet()print(type(view.get_queryset()))# 如果輸出 class list說(shuō)明有問(wèn)題如果get_queryset()返回list則需要修改代碼確保它返回QuerySet。? 其他常見(jiàn)問(wèn)題 解決方案問(wèn)題錯(cuò)誤代碼解決方案get_queryset()直接返回了listreturn list(queryset)改成QuerySet如queryset.union(another_queryset).values()或.values_list(..., flatTrue)可能導(dǎo)致listqueryset.values(field)改成.values_list(field, flatTrue)解析 Swagger 時(shí)找不到出錯(cuò)的 APIswagger.py解析失敗在swagger.py里logger.error(Swagger 解析失敗: {e})Django Shell 運(yùn)行view.get_queryset()發(fā)現(xiàn)返回listpython manage.py shell修復(fù)get_queryset()確保返回QuerySet總結(jié)如何防止AttributeError: list object has no attribute model錯(cuò)誤1??確保get_queryset()返回QuerySet而不是list2??使用union()代替list list3??檢查.values()是否返回list改成.values_list(..., flatTrue)4??用print(type(queryset))或 Django Shell 調(diào)試這樣Swagger 解析不會(huì)再出錯(cuò)API 文檔可以正常生成