Django Rest Framework - URL für Hyperlink-Beziehung mit Ansichtsname "Benutzerdetail" konnte nicht aufgelöst werden.

108

Ich baue ein Projekt in Django Rest Framework auf, in dem sich Benutzer anmelden können, um ihren Weinkeller anzuzeigen. Meine ModelViewSets funktionierten einwandfrei und plötzlich erhalte ich diesen frustrierenden Fehler:

URL für Hyperlink-Beziehung mit Ansichtsname "Benutzerdetail" konnte nicht aufgelöst werden. Möglicherweise haben Sie das zugehörige Modell nicht in Ihre API aufgenommen oder das lookup_fieldAttribut in diesem Feld falsch konfiguriert .

Der Traceback zeigt:

    [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.

Ich habe ein benutzerdefiniertes E-Mail-Benutzermodell und das Flaschenmodell in models.py lautet:

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

Meine Serialisierer:

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')

Meine Ansichten:

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

und schließlich die URL:

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

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

Ich habe keine Benutzerdetailansicht und sehe nicht, woher dieses Problem kommen könnte. Irgendwelche Ideen?

Vielen Dank

bpipat
quelle

Antworten:

96

Weil es eine HyperlinkedModelSerializerIhre Serializer versucht , die URL für den Bezug zu lösen Userauf Bottle.
Da Sie nicht über die Benutzerdetailansicht verfügen, ist dies nicht möglich. Daher die Ausnahme.

  1. Würde nicht nur die Registrierung UserViewSetbeim Router Ihr Problem lösen?
  2. Sie können das Benutzerfeld in Ihrem definieren, um das BottleSerializerexplizit zu verwenden, UserSerializeranstatt zu versuchen, die URL aufzulösen. Informationen dazu finden Sie in den Serializer-Dokumenten zum Umgang mit verschachtelten Objekten .
Carlton Gibson
quelle
1
Vielen Dank, ich hatte das UserViewSet in meinen Routern auskommentiert, das hat es gelöst!
Bpipat
5
DAS IST DER PUNKT ---- mach es explizit --- zu viel Magie ist zu viel Zeit verloren.
Andilabs
Können Sie bitte darauf hinweisen, was in meinem Projekt falsch konfiguriert ist ?
JJD
@ GrijeshChauhan - Danke! Jetzt behoben.
Carlton Gibson
Der Grund, warum es nicht funktionierte, war, dass django verwandte Daten von User in Ihrer aktuellen Ansicht für den Parameter User anzeigen wollte. Normalerweise wird eine Liste der verfügbaren Werte abgerufen. Da UserViewSet nicht definiert wurde, konnten die Details zum Rendern der Webseite nicht abgerufen werden. Durch Hinzufügen von UserViewSet und erneutes Registrieren unter dem Standardrouter wird das Rendern aller Komponenten abgeschlossen.
Doogle
65

Ich bin auch auf diesen Fehler gestoßen und habe ihn wie folgt gelöst:

Der Grund ist, dass ich vergessen habe, "** - detail" (Ansichtsname, zB: Benutzerdetail) einen Namespace zu geben. Daher konnte Django Rest Framework diese Ansicht nicht finden.

In meinem Projekt befindet sich eine App. Angenommen, mein Projektname lautet myprojectund der App-Name lautet myapp.

Es gibt zwei urls.py-Dateien, eine ist myproject/urls.pyund die andere ist myapp/urls.py. Ich gebe der App einen Namespace myproject/urls.py, genau wie:

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

Ich habe die restlichen Framework-Router in registriert myapp/urls.pyund dann diesen Fehler erhalten.

Meine Lösung bestand darin, URL explizit mit einem Namespace zu versehen:

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

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

Und es hat mein Problem gelöst.

Bovenson
quelle
@ Boveson, das funktioniert wie ein Zauber! Danke, du hast Stunden der Frustration auf meiner Seite gelöst.
lmiguelvargasf
Das hat es auch für mich zum Laufen gebracht. Ein wichtiger Punkt auf meiner Seite war auch die korrekte Schreibweise des Basisnamens in der Route!
Maggie
1
Der Schlüssel hier ist das Namespace-Präfix, das verhindert, dass die Umkehrung funktioniert .....
Bootscodierer
Ich hatte ein solches Problem und diese Antwort hat mein Problem nach 3 Stunden Suche behoben! @ovenson
Wal 52Hz
oder Sie können extra_kwargs verwenden, wie drf empfiehlt:extra_kwargs = {'url': {'view_name': 'myapp:user-detail'}}
ChrisRob
19

Vielleicht kann sich jemand das ansehen: http://www.django-rest-framework.org/api-guide/routers/

Wenn Sie den Namespace mit Hyperlink-Serialisierern verwenden, müssen Sie auch sicherstellen, dass alle view_name-Parameter auf den Serialisierern den Namespace korrekt wiedergeben. Beispielsweise:

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

Sie müssen einen Parameter einfügen, z. B. view_name='api:user-detail'für Serializer-Felder, die mit der Benutzerdetailansicht verlinkt sind.

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

class Meta:
    model = User
    fields = ('url', 'username')
JackPy
quelle
1
Zusammenfassend lässt sich sagen, dass das Vergeben eines Namespace für Ihre API den Fehler im Titel verursacht. Sie möchten dies wahrscheinlich nur tun, wenn Sie ihn an vielen Stellen ändern möchten.
Mark
hat für mich gearbeitet! Mein urls.pywurde in meinem newsiteProjekt doppelt verschachtelt : (1) newsite/urls.py(erstellt von Django) (2) polls/urls.py(3) polls/api/v1/urls.py ............ Ich muss den verschachtelten Namen miturl = serializers.HyperlinkedIdentityField(view_name="polls:polls_api:user-detail")
Grijesh Chauhan
12

Ein weiterer böser Fehler, der diesen Fehler verursacht, besteht darin, dass der Basisname in Ihrer urls.py unnötig definiert ist. Beispielsweise:

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

Dies führt zu dem oben angegebenen Fehler. Holen Sie sich diesen Basisnamen heraus und kehren Sie zu einer funktionierenden API zurück. Der folgende Code würde den Fehler beheben. Hurra!

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

Wahrscheinlich haben Sie den Basisnamen jedoch nicht willkürlich hinzugefügt, sondern möglicherweise, weil Sie ein benutzerdefiniertes def get_queryset () für die Ansicht definiert haben und Django daher das Hinzufügen des Basisnamens vorschreibt. In diesem Fall müssen Sie die 'URL' explizit als HyperlinkedIdentityField für den betreffenden Serializer definieren. Beachten Sie, dass wir dieses HyperlinkedIdentityField auf dem SERIALIZER der Ansicht definieren, die den Fehler auslöst. Wenn mein Fehler lautete: "URL für Hyperlink-Beziehung mit Ansichtsname" Studiendetail "konnte nicht aufgelöst werden. Möglicherweise haben Sie das zugehörige Modell nicht in Ihre API aufgenommen oder das lookup_fieldAttribut in diesem Feld falsch konfiguriert ." Ich könnte dies mit dem folgenden Code beheben.

Mein ModelViewSet (das benutzerdefinierte get_queryset ist der Grund, warum ich den base_name zuerst zum router.register () hinzufügen musste):

class StudyViewSet(viewsets.ModelViewSet):
    serializer_class = StudySerializer

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

Meine Router-Registrierung für dieses ModelViewSet in urls.py:

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

UND HIER IST DAS GELD! Dann könnte ich es so lösen:

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

Ja. Sie müssen dieses HyperlinkedIdentityField explizit für sich selbst definieren, damit es funktioniert. Und Sie müssen sicherstellen, dass das view_nameim HyperlinkedIdentityField definierte base_nameElement mit dem in der in urls.py definierten übereinstimmt, gefolgt von einem '-detail'.

Colton Hicks
quelle
2
Das hat bei mir funktioniert, aber ich musste den vollen Weg gehen <app_name>:studies-detail. Wenn zum Beispiel meine App aufgerufen wird tanks, ist der vollständige Pfad HyperlinkedIdentityField(view_name="tanks:studies-detail"). Um das herauszufinden, habe ich den Befehl django-exensions verwendet show_urls , um die vollständige Route und die Bezeichnung zu sehen, die der Router automatisch erstellt hat.
dtasev
10

Dieser Code sollte auch funktionieren.

class BottleSerializer(serializers.HyperlinkedModelSerializer):

  user = UserSerializer()

  class Meta:
    model = Bottle
    fields = ('url', 'wine', 'user')
Caglar
quelle
3
UserSerializerEs ist erwähnenswert
Caumons
Dies funktionierte für mich, aber damit es funktionierte, musste ich router.register (r'bottles ', views.BottleViewSet, base_name =' flags ') in router.register (r'bottles', views.BottleViewSet) ändern. Ich weiß nicht, warum diese Änderung erforderlich war.
Manpikin
4

Ich bin auf diesen Fehler gestoßen, nachdem ich meiner URL einen Namespace hinzugefügt habe

 url('api/v2/', include('api.urls', namespace='v2')),

und Hinzufügen von app_name zu meiner urls.py

Ich habe dieses Problem behoben, indem ich NamespaceVersioning für meine Rest-Framework-API in settings.py meines Projekts angegeben habe

REST_FRAMEWORK = {
    'DEFAULT_VERSIONING_CLASS':'rest_framework.versioning.NamespaceVersioning'}
Kelechukwu Nwosu
quelle
3

Heute habe ich den gleichen Fehler bekommen und die folgenden Änderungen retten mich.

Veränderung

class BottleSerializer(serializers.HyperlinkedModelSerializer):

zu:

 class BottleSerializer(serializers.ModelSerializer):
Manish Pal
quelle
2

Gleicher Fehler, aber anderer Grund:

Ich definiere ein benutzerdefiniertes Benutzermodell, nichts neues Feld:

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

Dies ist meine Ansichtsfunktion:

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

Da ich nicht querysetdirekt nachgegeben habe UserViewSet, muss ich festlegen, base_namewann ich dieses Viewset registriere. Hier ist meine Fehlermeldung durch urls.pyDatei verursacht :

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'

Sie benötigen das base_namegleiche wie Ihr Modellname - customuser.

Belter
quelle
Alter Beitrag, aber Ihr Kommentar "# <- base_name muss 'customuser' anstelle von 'user' sein" hat meinen Tag gerettet. Vielen Dank!
Hannon César
1

Wenn Sie die Klassen GenericViewSet und ListModelMixin erweitern und beim Hinzufügen der Klassen den gleichen Fehler haben URL- Felds in der , liegt dies daran, dass Sie die Detailansicht nicht definieren. Stellen Sie sicher, dass Sie das RetrieveModelMixin- Mixin erweitern:

class UserViewSet (mixins.ListModelMixin,
                   mixins.RetrieveModelMixin,
                   viewsets.GenericViewSet):
Rowinson Gallego
quelle
1

Es scheint, dass HyperlinkedModelSerializernicht mit einem Pfad einverstanden sind namespace. In meiner Bewerbung habe ich zwei Änderungen vorgenommen.

# rootapp/urls.py
urlpatterns = [
    # path('api/', include('izzi.api.urls', namespace='api'))
    path('api/', include('izzi.api.urls')) # removed namespace
]

In der importierten URL-Datei

# app/urls.py
app_name = 'api' // removed the app_name

Hoffe das hilft.

Cody Wikman
quelle
0

Ich bin auf denselben Fehler gestoßen, als ich der DRF-Kurzanleitung http://www.django-rest-framework.org/tutorial/quickstart/ gefolgt bin und dann versucht habe, zu / users zu navigieren . Ich habe dieses Setup schon oft ohne Probleme durchgeführt.

Meine Lösung bestand nicht im Code, sondern im Ersetzen der Datenbank.

Der Unterschied zwischen dieser Installation und den anderen zuvor bestand darin, dass ich die lokale Datenbank erstellt habe.

Diesmal lief ich meine

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

sofort nach dem Laufen

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

Anstelle der genauen Reihenfolge in der Anleitung aufgeführt.

Ich vermutete, dass etwas in der Datenbank nicht richtig erstellt wurde. Ich habe mich nicht um meine Entwickler-Datenbank gekümmert, also habe ich sie gelöscht und die ausgeführt./manage.py migrate Befehl erneut ausgeführt, einen Superuser erstellt, zu / users navigiert und der Fehler war verschwunden.

Etwas war problematisch mit der Reihenfolge der Operationen, in denen ich DRF und die Datenbank konfiguriert habe.

Wenn Sie SQLite verwenden und den Wechsel zu einer neuen Datenbank testen können, ist es einen Versuch wert, bevor Sie Ihren gesamten Code zerlegen.

Ben Havilland
quelle
0

Bottle = serializers.PrimaryKeyRelatedField (read_only = True)

Mit read_only können Sie das Feld darstellen, ohne es mit einer anderen Ansicht des Modells verknüpfen zu müssen.

Cristian Fernando
quelle
0

Ich habe diesen Fehler in DRF 3.7.7 erhalten, als ein Slug-Wert in der Datenbank leer war (gleich '').

mrmuggles
quelle
0

Ich bin auf dasselbe Problem generics.RetrieveAPIViewgestoßen und habe es behoben, indem ich meinem Viewset eine Basisklasse hinzugefügt habe.

Jace Browning
quelle
0

Ich war fast 2 Stunden in diesem Fehler gefangen:

Unsachgemäß konfiguriert unter / api_users / users / 1 / URL für Hyperlink-Beziehung mit Ansichtsname "Benutzerdetail" konnte nicht aufgelöst werden. Möglicherweise haben Sie das zugehörige Modell nicht in Ihre API aufgenommen oder das lookup_fieldAttribut in diesem Feld falsch konfiguriert .

Wenn ich endlich die Lösung bekomme, aber nicht verstehe warum, lautet mein Code:

#models.py
class Users(models.Model):
    id          = models.AutoField(primary_key=True)
    name        = models.CharField(max_length=50, blank=False, null=False)
    email       = models.EmailField(null=False, blank=False) 
    class Meta:
        verbose_name = "Usuario"
        verbose_name_plural = "Usuarios"

    def __str__(self):
        return str(self.name)


#serializers.py
class UserSerializer(serializers.HyperlinkedModelSerializer):
    class Meta:
        model = Users
        fields = (
            'id',
            'url',
            'name',        
            'email',       
            'description', 
            'active',      
            'age',         
            'some_date',   
            'timestamp',
            )
#views.py
class UserViewSet(viewsets.ModelViewSet):
    queryset = Users.objects.all()
    serializer_class = UserSerializer

#urls_api.py
router = routers.DefaultRouter()
router.register(r'users',UserViewSet, base_name='users')

urlpatterns = [ 
        url(r'^', include(router.urls)),
]

aber in meinen Haupt-URLs war es:

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    #api users
    url(r'^api_users/', include('usersApi.users_urls', namespace='api')),

]

Um das Problem beim Löschen des Namespace endgültig zu lösen:

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    #api users
    url(r'^api_users/', include('usersApi.users_urls')),

]

Und ich löse endlich mein Problem, so dass jeder mich wissen lassen kann, warum, am besten.

Cam T.
quelle
0

Wenn Sie die Felder 'id' und 'url' in Ihrem Serializer weglassen, haben Sie kein Problem. Sie können auf die Beiträge zugreifen, indem Sie die ID verwenden, die sowieso im json-Objekt zurückgegeben wird, was die Implementierung Ihres Frontends noch einfacher macht.

Eduardo A. Fernández Díaz
quelle
0

Ich hatte das gleiche Problem, ich denke, Sie sollten Ihre überprüfen

get_absolute_url

Titel des Methodeneingabewerts (** kwargs) des Objektmodells. und verwenden Sie den genauen Feldnamen in lookup_field

hassanzadeh.sd
quelle