Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
2.5k views
in Technique[技术] by (71.8m points)

django - Improperly configured nested resource using HyperlinkedModelSerializer

I have chosen the Django REST Framework and drf-nested-routers to build an API for Products and ProductReports. Here are the relevant classes:

# models.py
from django.db import models


class Product(models.Model):
    created_at = models.DateTimeField(auto_now_add=True)


class ProductReport(models.Model):
    user_name = models.CharField(max_length=256, blank=False)
    created_at = models.DateTimeField(auto_now_add=True)
    product = models.ForeignKey('Product', default=1)

...

# serializers.py
from rest_framework import serializers
from models import Product, ProductReport


class ProductSerializer(serializers.HyperlinkedModelSerializer):

    class Meta:
        model = Product


class ProductReportSerializer(serializers.HyperlinkedModelSerializer):

    product = ProductSerializer()

    class Meta:
        model = ProductReport

...

# views.py
from django.shortcuts import render
from rest_framework import viewsets, mixins
from rest_framework.response import Response
from models import Product, ProductReport
from serializers import ProductSerializer, ProductReportSerializer


class ProductViewSet(mixins.RetrieveModelMixin,
                   mixins.ListModelMixin,
                   viewsets.GenericViewSet):
    queryset = Product.objects.all()
    serializer_class = ProductSerializer


class ProductReportViewSet(viewsets.ViewSet):
    queryset = ProductReport.objects.all()
    serializer_class = ProductReportSerializer

    def list(self, request, product_pk=None):
        queryset = self.queryset.filter(product=product_pk)
        serializer = ProductReportSerializer(queryset, many=True, context={'request': request})
        return Response(serializer.data)

    def retrieve(self, request, pk=None, product_pk=None):
        queryset = self.queryset.get(pk=pk, product=product_pk)
        serializer = ProductReportSerializer(queryset)
        return Response(serializer.data)

...

# urls.py
from django.conf.urls import patterns, include, url
from django.contrib import admin
from rest_framework import routers
from rest_framework_nested.routers import SimpleRouter, NestedSimpleRouter
from productreports import views

router = routers.SimpleRouter()
router.register(r'products', views.ProductViewSet)

products_router = NestedSimpleRouter(router, r'products', lookup='product')
products_router.register(r'productreports', views.ProductReportViewSet)


urlpatterns = patterns('',
    url(r'^', include(router.urls)),
    url(r'^', include(products_router.urls)),
    url(r'^admin/', include(admin.site.urls)),
    url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework')),
)

When I visit http://localhost:8000/products/1/productreports/ the following error is shown:

ImproperlyConfigured at /products/1/productreports/
Could not resolve URL for hyperlinked relationship using view name "productreport-detail". You may have failed to include the related model in your API, or incorrectly configured the lookup_field attribute on this field.

There are a few things I am unsure about if they are correctly set up:

  • product = models.ForeignKey('Product', default=1)
  • many=True in serializer = ProductReportSerializer(queryset, many=True, context={'request': request}) ... each product can have many product reports
  • The ProductReportSerializer in general
  • lookup='product' in products_router = NestedSimpleRouter(router, r'products', lookup='product')

Update

I noticed that the error only occurs when there is at least one associated productreport for a product. If the productreports table contains no entry for a particular product then the API response is fine.

When I inspect the serializer in ProductReportViewSet#list I get:

ProductReportSerializer([
    <ProductReport: ProductReport object>, <ProductReport: ProductReport object>, 
    <ProductReport: ProductReport object>, <ProductReport: ProductReport object>, 
    <ProductReport: ProductReport object>, <ProductReport: ProductReport object>, 

'...(remaining elements truncated)...'], context={'request': <rest_framework.request.Request object>}, many=True):
        url = HyperlinkedIdentityField(view_name='productreport-detail')
        product = ProductSerializer():
            url = HyperlinkedIdentityField(view_name='product-detail')
            created_at = DateTimeField(read_only=True)
        user_name = CharField(max_length=256)
        created_at = DateTimeField(read_only=True)
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)
Waitting for answers

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...