2013-12-12 7 views
54

Buduję projekt w Django Rest Framework, gdzie użytkownicy mogą się zalogować, aby wyświetlić ich piwnicę z winami. Moi ModelViewSets pracowali dobrze i nagle otrzymuję ten frustrujący błąd:Django Rest Framework - Nie można rozwiązać adresu URL dla relacji hiperłącza przy użyciu nazwy widoku "user-detail"

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

traceback Wystawy:

[12/Dec/2013 18:35:29] "GET /bottles/ HTTP/1.1" 500 76677 
Internal Server Error: /bottles/ 
Traceback (most recent call last): 
    File "/Users/bpipat/.virtualenvs/usertest2/lib/python2.7/site-packages/django/core/handlers/base.py", line 114, in get_response 
    response = wrapped_callback(request, *callback_args, **callback_kwargs) 
    File "/Users/bpipat/.virtualenvs/usertest2/lib/python2.7/site-packages/rest_framework/viewsets.py", line 78, in view 
    return self.dispatch(request, *args, **kwargs) 
    File "/Users/bpipat/.virtualenvs/usertest2/lib/python2.7/site-packages/django/views/decorators/csrf.py", line 57, in wrapped_view 
    return view_func(*args, **kwargs) 
    File "/Users/bpipat/.virtualenvs/usertest2/lib/python2.7/site-packages/rest_framework/views.py", line 399, in dispatch 
    response = self.handle_exception(exc) 
    File "/Users/bpipat/.virtualenvs/usertest2/lib/python2.7/site-packages/rest_framework/views.py", line 396, in dispatch 
    response = handler(request, *args, **kwargs) 
    File "/Users/bpipat/.virtualenvs/usertest2/lib/python2.7/site-packages/rest_framework/mixins.py", line 96, in list 
    return Response(serializer.data) 
    File "/Users/bpipat/.virtualenvs/usertest2/lib/python2.7/site-packages/rest_framework/serializers.py", line 535, in data 
    self._data = [self.to_native(item) for item in obj] 
    File "/Users/bpipat/.virtualenvs/usertest2/lib/python2.7/site-packages/rest_framework/serializers.py", line 325, in to_native 
    value = field.field_to_native(obj, field_name) 
    File "/Users/bpipat/.virtualenvs/usertest2/lib/python2.7/site-packages/rest_framework/relations.py", line 153, in field_to_native 
    return self.to_native(value) 
    File "/Users/bpipat/.virtualenvs/usertest2/lib/python2.7/site-packages/rest_framework/relations.py", line 452, in to_native 
    raise Exception(msg % view_name) 
Exception: Could not resolve URL for hyperlinked relationship using view 
name "user-detail". You may have failed to include the related model in 
your API, or incorrectly configured the `lookup_field` attribute on this 
field. 

Mam modelu użytkownika niestandardowego e-mail i model butelki w modelach. py to:

class Bottle(models.Model):  
     wine = models.ForeignKey(Wine, null=False) 
     user = models.ForeignKey(User, null=False, related_name='bottles') 

Moi serializers:

class BottleSerializer(serializers.HyperlinkedModelSerializer): 

    class Meta: 
     model = Bottle 
     fields = ('url', 'wine', 'user') 

class UserSerializer(serializers.ModelSerializer): 

    class Meta: 
     model = User 
     fields = ('email', 'first_name', 'last_name', 'password', 'is_superuser') 

Moje poglądy:

class BottleViewSet(viewsets.ModelViewSet): 
    """ 
    API endpoint that allows bottles to be viewed or edited. 
    """ 
    queryset = Bottle.objects.all() 
    serializer_class = BottleSerializer 

class UserViewSet(ListCreateAPIView): 
    """ 
    API endpoint that allows users to be viewed or edited. 
    """ 
    queryset = User.objects.all() 
    serializer_class = UserSerializer 

a na końcu URL:

router = routers.DefaultRouter() 
router.register(r'bottles', views.BottleViewSet, base_name='bottles') 

urlpatterns = patterns('', 
    url(r'^', include(router.urls)), 
    # ... 

nie mam widok szczegółowości użytkownika i nie widzę, gdzie kwestia ta mogłaby pochodzić. Jakieś pomysły?

Dzięki

Odpowiedz

56

Bo to HyperlinkedModelSerializer Twój serializer próbuje rozwiązać adres URL związanego User na Bottle.
Ponieważ nie masz widoku szczegółów użytkownika, nie można tego zrobić. Stąd wyjątek.

  1. Nie tylko rejestracja UserViewSet za pomocą routera rozwiązuje problem?
  2. Możesz zdefiniować pole użytkownika na swoim BottleSerializer, aby jawnie używać wartości UserSerializer, zamiast próbować rozwiązać adres URL. Zobacz serializer docs on dealing with nested objects for that.
+1

Wielkie dzięki, ja skomentował zewnątrz UserViewSet w moich routerów, które go rozwiązać! – bpipat

+2

TO PUNKT ---- rób to wyraźnie - na wiele magii jest dużo czasu straconego. – andi

+0

Czy możesz wskazać, co jest źle skonfigurowane w [mój projekt] (http://stackoverflow.com/questions/29126707/improperly-configured-nested-resource-using-hyperlinkedmodelserializer)? – JJD

8

Ten kod również powinien działać.

class BottleSerializer(serializers.HyperlinkedModelSerializer): 

    user = UserSerializer() 

    class Meta: 
    model = Bottle 
    fields = ('url', 'wine', 'user') 
+0

Warto zauważyć, że 'UserSerializer' musi być zaimplementowany (nie jest gotowy do importu), jak pokazano na stronie http://www.django-rest-framework.org/api-guide/serializers/ – Caumons

0

wpadłem na ten sam błąd, a ja zgodnie z instrukcjami QuickStart DRF http://www.django-rest-framework.org/tutorial/quickstart/ a następnie próbuje przejść do/użytkowników. Zrobiłem tę konfigurację wiele razy wcześniej, bez problemów.

Moje rozwiązanie nie było w kodzie, ale w zastępstwie bazy danych.

Różnica między tą instalacją a innymi wcześniej była taka, kiedy utworzyłem lokalną bazę danych.

Tym razem wpadłem mój

./manage.py migrate 
./manage.py createsuperuser 

natychmiast po uruchomieniu

virtualenv venv 
. venv/bin/activate 
pip install django 
pip install djangorestframework 

zamiast dokładnej kolejności podanej w instrukcji.

Podejrzewałem, że coś nie zostało poprawnie utworzone w DB.Nie dbałem o mój dev db, więc usunąłem go i raz jeszcze uruchomiłem komendę ./manage.py migrate, utworzyłem superużytkownika, przeglądałem/użytkowników i błąd zniknął.

Wystąpił problem z kolejnością operacji, w których skonfigurowałem DRF i db.

Jeśli używasz sqlite i jesteś w stanie przetestować zmianę na świeżą DB, to warto spróbować, zanim przejrzysz cały kod.

25

natknąłem tego błędu zbyt i rozwiązać go w następujący sposób:

Powodem jest Zapomniałam dając "** - detal" (view_name, np .: użytkownik-detail) przestrzeni nazw. Tak więc Django Rest Framework nie mógł znaleźć tego widoku.

Jest jedna aplikacja w moim projekcie, przypuśćmy, że moja nazwa projektu to myproject, a nazwa aplikacji to myapp.

Istnieje dwa pliki urls.py, jeden to myproject/urls.py, a drugi to myapp/urls.py. Daję App przestrzeń nazw w myproject/urls.py, podobnie jak:

url(r'', include(myapp.urls, namespace="myapp")), 

Zarejestrowałem routery ramowych reszta w myapp/urls.py, a następnie dostał ten błąd.

Moje rozwiązanie było dostarczenie URL z nazw extenso:

class UserSerializer(serializers.HyperlinkedModelSerializer): 
    url = serializers.HyperlinkedIdentityField(view_name="myapp:user-detail") 

    class Meta: 
     model = User 
     fields = ('url', 'username') 

I rozwiązać mój problem.

8

Może ktoś może rzucić okiem na to: http://www.django-rest-framework.org/api-guide/routers/

przypadku korzystania z przestrzeni nazw z hiperłączami serializers Trzeba także do zapewnienia, że ​​wszelkie parametry VIEW_NAME na serializers prawidłowo odzwierciedlają nazw. Na przykład:

urlpatterns = [ 
    url(r'^forgot-password/$', ForgotPasswordFormView.as_view()), 
    url(r'^api/', include(router.urls, namespace='api')), 
] 

trzeba by to parametr taki jak view_name='api:user-detail' dla pól serializer hiperłącze do widoku szczegółów użytkownika.

class UserSerializer(serializers.HyperlinkedModelSerializer): 
    url = serializers.HyperlinkedIdentityField(view_name="api:user-detail") 

class Meta: 
    model = User 
    fields = ('url', 'username') 
+0

Podsumowany, podając api Przestrzeń nazw powoduje błąd w tytule, prawdopodobnie nie chcesz tego robić, chyba że chcesz go zmienić w wielu miejscach. – Mark

4

Kolejny przykry błąd, który powoduje, że błąd ten jest posiadanie base_name niepotrzebnie zdefiniowany w urls.py. Na przykład:

router.register(r'{pathname}, views.{ViewName}ViewSet, base_name='pathname') 

Spowoduje to błąd opisany powyżej. Pobierz tam nazwę base_name i wróć do działającego interfejsu API. Poniższy kod naprawiłby błąd. Brawo!

router.register(r'{pathname}, views.{ViewName}ViewSet) 

Jednakże, prawdopodobnie nie tylko dowolnie dodawać base_name, można to zrobić, ponieważ zdefiniował get_queryset zwyczaj def() dla widoku i tak Django mandatów że dodasz base_name. W takim przypadku musisz jawnie zdefiniować "URL" jako HyperlinkedIdentityField dla danego serializera. Zauważ, że definiujemy to pole HyperlinkedIdentityField w SERIALIZERrze widoku, który rzuca błąd. Jeśli wystąpił błąd "Nie można rozwiązać adresu URL dla powiązania hiperłącza przy użyciu nazwy widoku" szczegóły badania ". Możliwe, że nie udało się dołączyć do interfejsu API powiązanego modelu lub nieprawidłowo skonfigurowano atrybut lookup_field w tym polu." Mogę to naprawić za pomocą następującego kodu.

My ModelViewSet (zwyczaj get_queryset dlatego musiałem dodać base_name do router.register() w pierwszej kolejności):

class StudyViewSet(viewsets.ModelViewSet): 
    serializer_class = StudySerializer 

    '''custom get_queryset''' 
    def get_queryset(self): 
     queryset = Study.objects.all() 
     return queryset 

moją rejestrację routera do tego ModelViewSet w urls.py:

router.register(r'studies', views.StudyViewSet, base_name='studies') 

I TUTAJ, GDZIE JEST PIENIĄDZE! Wtedy mógłbym rozwiązać to tak:

class StudySerializer(serializers.HyperlinkedModelSerializer): 
    url = serializers.HyperlinkedIdentityField(view_name="studies-detail") 
    class Meta: 
     model = Study 
     fields = ('url', 'name', 'active', 'created', 
       'time_zone', 'user', 'surveys') 

Tak. Musisz samodzielnie zdefiniować tę HiperlinkedIdentityField, aby działała. Musisz się upewnić, że view_name zdefiniowany na HyperlinkedIdentityField jest taki sam jak zdefiniowałeś na base_name w urls.py z dodanym po nim "-detailem".

0

Butelka = serializers.PrimaryKeyRelatedField (READ_ONLY = True)

READ_ONLY pozwala reprezentować pole bez konieczności podłączenia go do innego widoku modelu.

0

sam błąd, ale z innego powodu:

zdefiniować niestandardowy model obsługi, nic nowego pola:

from django.contrib.auth.models import (AbstractUser) 
class CustomUser(AbstractUser): 
    """ 
    custom user, reference below example 
    https://github.com/jonathanchu/django-custom-user-example/blob/master/customuser/accounts/models.py 

    # original User class has all I need 
    # Just add __str__, not rewrite other field 
    - id 
    - username 
    - password 
    - email 
    - is_active 
    - date_joined 
    - method, email_user 
    """ 

    def __str__(self): 
     return self.username 

To jest mój widok funkcja:

from rest_framework import permissions 
from rest_framework import viewsets 
from .models import (CustomUser) 
class UserViewSet(viewsets.ModelViewSet): 
    permission_classes = (permissions.AllowAny,) 
    serializer_class = UserSerializer 

    def get_queryset(self): 
     queryset = CustomUser.objects.filter(id=self.request.user.id) 
     if self.request.user.is_superuser: 
      queryset = CustomUser.objects.all() 
     return queryset 

Ponieważ nie zrobił” t dać queryset bezpośrednio w UserViewSet, muszę ustawić base_name po zarejestrowaniu tego zestawu widoków. To gdzie mój komunikat błędu spowodowane przez urls.py pliku:

from myapp.views import (UserViewSet) 
from rest_framework.routers import DefaultRouter 
router = DefaultRouter() 
router.register(r'users', UserViewSet, base_name='customuser') # <--base_name needs to be 'customuser' instead of 'user' 

trzeba base_name sama jak nazwa modelu - customuser.

0

Jeśli rozszerzenie GenericViewSet i ListModelMixin klas i mają ten sam błąd przy dodawaniu pole URL w widoku listy, to dlatego, że nie jesteś definiowania widoku szczegółów. Mieć pewność, że rozszerzenie RetrieveModelMixin mixin:

class UserViewSet (mixins.ListModelMixin, 
        mixins.RetrieveModelMixin, 
        viewsets.GenericViewSet):