2015-01-01 6 views
7

Meine Django Projektstruktur:Django REST: Wie benutzt man Router in der Anwendungsebene urls.py?

mysite/ 
    mysite/ 
     ... 
     urls.py 
    scradeweb/ 
     ... 
     models.py 
     serializers.py 
     views.py 
     urls.py 
    manage.py 

Wenn ich Django REST router in der Projektebene urls.py (mysite/urls.py) wie unten verwenden, funktioniert alles einwandfrei:

# mysite/urls.py 
from django.conf.urls import patterns, include, url 
from django.contrib import admin 
from .settings import USER_CREATED_APPS 
from rest_framework.routers import DefaultRouter 
from scradeweb import views 

router = DefaultRouter() 
router.register(r'threads', views.ThreadViewSet,) 
router.register(r'posts', views.PostViewSet) 

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

ich meine Bewerbung alle gerne halten (scradeweb) bezogenen Code in seinem Verzeichnis, so bewege ich mich router zu scradeweb/urls.py:

# scradeweb/urls.py 
from django.conf.urls import url, patterns, include 
from scradeweb import views 
from rest_framework.routers import DefaultRouter 


router = DefaultRouter() 
router.register(r'threads', views.ThreadViewSet,) 
router.register(r'posts', views.PostViewSet) 

urlpatterns = router.urls 

Als ich nach http://127.0.0.1:8000/scradeweb/posts/ gehen, hebt sie die Ausnahme:

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

Warum funktioniert es nicht?

Hier ist meine scradeweb/models.py

class Thread(models.Model): 

    thread_id = models.IntegerField() 
    sticky = models.NullBooleanField() 
    prefix = models.CharField(max_length=255) 
    title = models.CharField(max_length=255) 
    start_time = models.DateTimeField() 
    author = models.CharField(max_length=255) 
    url = models.URLField(unique=True) 
    forum = models.ForeignKey(Forum, related_name='threads') 

    class Meta: 
     ordering = ('start_time',) 


class Post(models.Model): 

    post_id = models.IntegerField() 
    url = models.URLField(unique=True) 
    post_number = models.IntegerField() 
    start_time = models.DateTimeField(blank=True) 
    last_edited_time = models.DateTimeField(blank=True, null=True) 
    author = models.CharField(max_length=255, blank=True) 
    content = models.TextField(blank=True) 
    thread = models.ForeignKey(Thread, related_name='posts') 

    class Meta: 
     ordering = ('post_number',) 

scradeweb/serializers.py:

from rest_framework import serializers 
from scradeweb.models import Thread, Post 


class ThreadSerializer(serializers.HyperlinkedModelSerializer): 

    posts = \ 
     serializers.HyperlinkedRelatedField(
      many=True, 
      read_only=True, 
      view_name='post-detail', 
     ) 

    class Meta: 

     model = Thread 
     fields = ('pk', 'thread_id', 'title', 'url', 'posts') 
     read_only_fields = ('thread_id',) 


class PostSerializer(serializers.HyperlinkedModelSerializer): 
    class Meta: 
     model = Post 

scradeweb/views.py:

... 

class ThreadViewSet(viewsets.ReadOnlyModelViewSet): 

    queryset = Thread.objects.all() 
    serializer_class = ThreadSerializer 


class PostViewSet(viewsets.ModelViewSet): 

    queryset = Post.objects.all() 
    serializer_class = PostSerializer 
+0

Wo ist die Ansicht => 'thread-detail'? –

+0

@LearningNeverStops erzeugt der [Router] (http://www.django-rest-framework.org/api-guide/routers/) 'thread-detail',' thread-list', 'post-detail',' Post-Liste "aus den ViewSets. – Hieu

+0

Haben Sie srcradeweb/urls.py in Ihre URLs meiner Website aufgenommen? – DAKZH

Antwort

11

Das hier Problem ist, dass Sie mit einem Namensraum Django REST-Framework verwenden. Viele Komponenten funktionieren nicht gut mit ihnen, die bedeutet nicht, dass sie nicht verwendet werden können, so dass Sie die Probleme umgehen müssen, indem Sie eine Menge manuelle Arbeit. Das Hauptproblem ist mit Hyperlink-Beziehungen (Hyperlinked*Field s), da sie Ansichten umkehren müssen, und das erfordert, dass der Namespace angegeben ist.

Der erste Ort zum Starten ist der Router-Level , der derzeit Namespaces nicht unterstützt. Dies ist nur ein Problem für die DefaultRouter, da es die Indexseite ausbildet, die eine Liste umgekehrter URLs enthält, die sofort Fehler auslösen wird. Dies wurde behoben in the upcoming release, aber jetzt bist du ohne es fest. Im besten Fall (DRF 3.0+) ist die Indexseite komplett leer (oder zeigt auf falsche URLs), im schlimmsten Fall (DRF 2.x) wird immer ein interner Serverfehler ausgelöst.

Der zweite zu betrachtende Punkt sind die Serializerfelder. Standardmäßig generiert HyperlinkedModelSerializer automatisch HyperlinkedRelatedField und HyperlinkedIdentityField Felder mit URLs nicht Namespaced. Wenn Sie Namespaces verwenden, müssen Sie alle diese automatisch generierten Felder überschreiben. Dies bedeutet im Allgemeinen, dass es besser ist, wenn Sie einfach keine HyperlinkedModelSerializer verwenden, und stattdessen die Ausgabe mit einer ModelSerializer steuern.

Die erste (und einfachste) zu reparierende Stelle ist das Feld url, das automatisch für alle Objekte generiert wird. Dies wird automatisch generiert mit view_name auf die Detailseite gesetzt (thread-detail in diesem Fall), ohne einen Namespace. Sie müssen die view_name überschreiben und den Namespace davor einfügen (also scradeweb:thread-detail in diesem Fall).

class ThreadSerializer(serializers.ModelSerializer): 
    url = serializers.HyperlinkedIdentityField(
     view_name="scradeweb:thread-detail", 
    ) 

Sie müssen auch alle automatisch generierten verwandten Felder überschreiben. Dies ist etwas schwieriger für beschreibbare Felder, aber ich würde immer empfehlen, in diesen Fällen repr(MySerializer()) zu betrachten, um die Argumente für die automatisch erzeugten Felder zu sehen. Für schreibgeschützte Felder müssen nur die Standardargumente kopiert und die view_name erneut geändert werden.

class ThreadSerializer(serializers.ModelSerializer): 
    posts = serializers.HyperlinkedRelatedField(
     many=True, 
     read_only=True, 
     view_name='scradeweb:post-detail', 
    ) 

Diese müssen für alle Felder, durchgeführt werden und es wie Django REST-Framework sieht nicht die Fähigkeit werden, indem es in naher Zukunft automatisch zu tun. Während dies zunächst nicht angenehm sein wird, gibt es Ihnen eine großartige Gelegenheit, alles zu würdigen, was DRF früher automatisch für Sie getan hat.

Verwandte Themen