创建后网址不存在

Dra*_*Dev 2 python django django-rest-framework

这是我的views.py

class LanguageViewSet(viewsets.ModelViewSet):
    queryset = Language.objects.all().order_by('name')
    serializer_class = LanguageSerializer


class FrameworkViewSet(viewsets.ModelViewSet):
    queryset = Framework.objects.all()
    serializer_class = FrameworkSerializer


class SelectedLanguageViewSet(viewsets.ModelViewSet):
    queryset = Language.objects.all()
    serializer_class = FrameworkSerializer

    def get_queryset(self):
        request = self.request
        language_id = request.query_params.get('language_id')
        language = Language.objects.filter(id=language_id)
        self.queryset = language.framework_set.all()
        return self.queryset
Run Code Online (Sandbox Code Playgroud)

还有我的urls.py

router = routers.DefaultRouter()

router.register(r'languages', views.LanguageViewSet)
router.register(r'frameworks', views.FrameworkViewSet)
router.register(r'language/<int:language_id>', views.SelectedLanguageViewSet)

urlpatterns = [
    path('', include(router.urls)),
    path('api-auth/', include('rest_framework.urls', namespace='rest_framework'))
]
Run Code Online (Sandbox Code Playgroud)

然而,只有languagesframeworks工作。language不存在。这是因为get_queryset? 我什至尝试删除<int:language_id>url 参数中的 ,但它仍然不会显示。

编辑:请
原谅我的天真,我对 django 和 DRF 还是很陌生

更新

我的意思是这样的(没有 DRF):
views.py 中

def frameworks_from_language(request, language_id):
    language = Language.objects.get(pk=language_id)

    if language == None:
        # Do some stuffs

    frameworks = language.framework_set.all()
    template = 'app/language.html'
    context = {
        'frameworks': frameworks
    }
    return render(request, template, context)
Run Code Online (Sandbox Code Playgroud)

urls.py 中

path('language/<int:language_id>', views.frameworks_from_language, name='getframeworks')
Run Code Online (Sandbox Code Playgroud)

所以整个流程是:

  1. 用户点击一种语言
  2. 根据所选语言的 id 触发 get 请求
  3. 返回与语言相关的框架对象

这是在一个普通的基于模板的 Django 上工作的。但是我不知道如何在 DRF 上使用所有视图集等执行这样的操作。

hee*_*ayl 5

是的,这是因为您的get_queryset(和您的 URL 定义)。

首先,<int:language_id>从 URL 前缀中删除,因为 DRF 路由器会自动为您生成列表和详细 URL 端点。此外,当您使用正则表达式时,路径language/<int:language_id>是按字面意思理解的(在使用时<int:language_id>有含义,而path不是re_path)。

在您的 中SelectedLanguageViewSet.get_queryset,您试图返回Framework与某个相关的所有实例Language(您认为您会从language_id查询参数中获取该实例)。viewset 是用于Language模型的,最多你应该对queryset里面的默认值做一些过滤get_queryset;绝对不要从另一个模型返回完全不同的查询集。当你通过时会发生什么(在修复你的 URL 之后)/language/1/?(1 是LanguageID 还是FrameworkID?提示:根据您当前的设计,它会引用Framework实例 ID)。

FWIW,URL 捕获作为kwargs视图集实例(即self.kwargs)中的属性,而不是通过查询字符串。


回复编辑:

要在 DRF 中实现它,您可以为仅包含frameworks字段的语言定义序列化程序:

from viewsets import ReadOnlyModelViewSet

class SelectedLanguageViewSet(ReadOnlyModelViewSet):
    queryset = Language.objects.all()
    serializer_class = LangaugeRelationSerializer 
Run Code Online (Sandbox Code Playgroud)

仅应支持listretrieve操作,因此继承自ReadOnlyModelViewSet.

现在,序列化程序(只有一个字段 -- frameworks):

class LangaugeRelationSerializer(serializers.ModelSerializer):
    frameworks = FrameworkSerializer(source='framework_set', many=True)

    class Meta:
        model = Language
        fields = ('frameworks',)
Run Code Online (Sandbox Code Playgroud)

默认情况下,ModelSerializer将相关字段设置为PrimaryKeyRelatedField,因此相关对象表示为其主键。如果你想要而不是使用FrameworkSerializer

class LangaugeRelationSerializer(serializers.ModelSerializer):
    frameworks = serializers.PrimaryKeyRelatedField(source='framework_set', many=True)

    class Meta:
        model = Language
        fields = ('frameworks',)
Run Code Online (Sandbox Code Playgroud)

作为PrimaryKeyRelatedField默认设置,您还可以定义sourcein Meta.extra_kwargs(以免您自己编写字段定义):

class LangaugeRelationSerializer(serializers.ModelSerializer):

    class Meta:
        model = Language
        fields = ('frameworks',)
        extra_kwargs = {
            'frameworks': {
                'source': 'framework_set',
                'many': True,
            },
        }
Run Code Online (Sandbox Code Playgroud)