创建后URL不存在

时间:2019-12-11 09:06:21

标签: 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

还有我的 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'))
]

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

编辑:
请原谅我,我对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)

urls.py 中:

path('language/<int:language_id>', views.frameworks_from_language, name='getframeworks')

因此整个流程将是:

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

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

2 个答案:

答案 0 :(得分:5)

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

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

在您的SelectedLanguageViewSet.get_queryset中,您尝试返回与某个Framework相关的所有Language实例(您认为应该从language_id查询参数中获取该实例)。该视图集适用于Language模型,至多您应该在queryset内部的默认get_queryset上进行一些过滤;绝对不要从另一个模型返回完全不同的查询集。传递/language/1/时会发生什么(固定URL之后)? (根据您当前的设计,1将是Language ID还是Framework ID?提示:。它将引用一个Framework实例ID)。

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


修改答案:

要在DRF中实现该功能,您可以仅使用frameworks字段为语言定义一个序列化器:

from viewsets import ReadOnlyModelViewSet

class SelectedLanguageViewSet(ReadOnlyModelViewSet):
    queryset = Language.objects.all()
    serializer_class = LangaugeRelationSerializer 

仅应支持listretrieve操作,因此这些操作是从ReadOnlyModelViewSet继承的。

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

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

    class Meta:
        model = Language
        fields = ('frameworks',)

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

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

    class Meta:
        model = Language
        fields = ('frameworks',)

由于PrimaryKeyRelatedField是默认设置,因此您还可以在source中定义Meta.extra_kwargs(以免您自己编写字段定义):

class LangaugeRelationSerializer(serializers.ModelSerializer):

    class Meta:
        model = Language
        fields = ('frameworks',)
        extra_kwargs = {
            'frameworks': {
                'source': 'framework_set',
                'many': True,
            },
        }

答案 1 :(得分:1)

您是否尝试过将URL作为/language/id-of-language而不是id-of-language传递整数,即db中语言的ID。