简体   繁体   中英

URL doesn't exist after creating

Here's my 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

And my 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'))
]

However, only languages and frameworks work. language doesn't exists. Is this because of the get_queryset ? I even tried removing the <int:language_id> in the url params but it still won't show up.

EDIT:
Forgive my naiveness, I'm quite new to django and DRF

Update

What I meant to do was like this (without DRF):
In the 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)

And in urls.py :

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

So the whole flow would be:

  1. User clicks a language
  2. Fire a get request based on the id of the selected language
  3. Return an object of frameworks that is related to the language

This is working on a normal template-based Django. However I have no idea how to execute something like this on DRF, with all the viewsets etc.

Yes, it's because of your get_queryset (and your URL definitions).

At first, drop <int:language_id> from URL prefix, as DRF router generates the list and detail URL endpoints for you automatically. Moreover, as you're using Regex path language/<int:language_id> is taken literally ( <int:language_id> has a meaning while using path , not re_path ).

In your SelectedLanguageViewSet.get_queryset , you're trying to return all Framework instances related with a certain Language (you thought you would take that from language_id query param). The viewset is for Language model, and at most you should do some filtering on the default queryset inside get_queryset ; absolutely don't return a whole different queryset from another model. What will happen (after fixing your URL) when you pass /language/1/ ? (Will 1 be a Language ID or a Framework ID ? Hint: as per you current design it would refer a Framework instance ID).

FWIW, the URL captures come as kwargs attribute in a viewset instance (ie self.kwargs ), not via the query string.


Answer to edits:

To implement that in DRF, you can define a serializer for language with only the frameworks field:

from viewsets import ReadOnlyModelViewSet

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

only list and retrieve actions should be supported, hence inherited from ReadOnlyModelViewSet .

Now, the serializer (with only one field -- frameworks ):

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

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

By default ModelSerializer sets the related fields as PrimaryKeyRelatedField , so the related objects are represented as their primary keys. If you want that instead of using the FrameworkSerializer :

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

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

As PrimaryKeyRelatedField is the default, you can also define the source in Meta.extra_kwargs (to save you from writing the field definition yourself):

class LangaugeRelationSerializer(serializers.ModelSerializer):

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

您是否尝试过将 url 作为/language/id-of-language代替id-of-language传递整数,即数据库中语言的 id。

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM