Django Rest Framework - Impossibile risolvere l'URL per la relazione con collegamento ipertestuale utilizzando il nome della vista "user-detail"


108

Sto costruendo un progetto in Django Rest Framework in cui gli utenti possono accedere per visualizzare la loro cantina. I miei ModelViewSet funzionavano perfettamente e all'improvviso ottengo questo errore frustrante:

Impossibile risolvere l'URL per la relazione con collegamento ipertestuale utilizzando il nome della vista "user-detail". Potresti non aver incluso il modello correlato nella tua API o aver configurato in modo errato l' lookup_fieldattributo in questo campo.

Il traceback mostra:

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

Ho un modello utente di posta elettronica personalizzato e il modello di bottiglia in models.py è:

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

I miei serializzatori:

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

Le mie opinioni:

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

e infine l'url:

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

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

Non ho una visualizzazione dei dettagli dell'utente e non vedo da dove potrebbe derivare questo problema. Qualche idea?

Grazie

Risposte:


96

Perché è un HyperlinkedModelSerializervostro serializzatore sta cercando di risolvere l'URL per il relativo Usersul vostro Bottle.
Poiché non hai la visualizzazione dei dettagli dell'utente, non è possibile farlo. Da qui l'eccezione.

  1. La semplice registrazione di UserViewSetcon il router non risolverebbe il tuo problema?
  2. È possibile definire il campo utente sul proprio BottleSerializerper utilizzare esplicitamente UserSerializerinvece di provare a risolvere l'URL. Vedere i documenti del serializzatore su come gestire gli oggetti nidificati per questo .

1
Grazie mille, avevo commentato UserViewSet nei miei router, che lo ha risolto!
bpipat

5
QUESTO È IL PUNTO - fallo esplicitamente - per molta magia si perde molto tempo.
andilabs

Puoi per favore indicare cosa è configurato male nel mio progetto ?
JJD

@ GrijeshChauhan - Grazie! Ora risolto.
Carlton Gibson

Il motivo per cui non funzionava era perché django voleva mostrare i dati correlati da Utente nella vista corrente per il parametro Utente. Di solito raccoglie un elenco di valori disponibili. Poiché UserViewSet non è stato definito, non è stato possibile estrarre i dettagli per eseguire il rendering della pagina Web. L'aggiunta di UserViewSet e la registrazione nel router predefinito rende l'operazione completa per il rendering di tutti i componenti.
Doogle

65

Mi sono imbattuto anche in questo errore e l'ho risolto come segue:

Il motivo è che ho dimenticato di dare a "** - detail" (view_name, eg: user-detail) uno spazio dei nomi. Quindi, Django Rest Framework non è riuscito a trovare quella vista.

C'è un'app nel mio progetto, supponiamo che il nome del mio progetto sia myprojecte il nome dell'app sia myapp.

Ci sono due file urls.py, uno è myproject/urls.pye l'altro è myapp/urls.py. Assegno all'app uno spazio dei nomi myproject/urls.py, proprio come:

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

Ho registrato il resto dei router del framework myapp/urls.pye poi ho ricevuto questo errore.

La mia soluzione era fornire esplicitamente l'URL con lo spazio dei nomi:

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

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

E ha risolto il mio problema.


@ Boveson, funziona a meraviglia! Grazie hai risolto ore di frustrazione dalla mia parte.
lmiguelvargasf

Anche questo ha funzionato per me. Un altro punto importante da parte mia è stata l'ortografia corretta di base_name nella Rotta!
maggie

1
La chiave qui è il prefisso dello spazio dei nomi che impedisce al reverse di funzionare .....
boatcoder

Ho avuto un problema come questo e questa risposta ha risolto il mio problema dopo 3 ore di ricerca! @bovenson
Whale 52Hz

oppure puoi usare extra_kwargs come consiglia drf:extra_kwargs = {'url': {'view_name': 'myapp:user-detail'}}
ChrisRob il

19

Forse qualcuno può dare un'occhiata a questo: http://www.django-rest-framework.org/api-guide/routers/

Se si utilizza lo spazio dei nomi con i serializzatori con collegamenti ipertestuali, è inoltre necessario assicurarsi che tutti i parametri view_name sui serializzatori riflettano correttamente lo spazio dei nomi. Per esempio:

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

è necessario includere un parametro come view_name='api:user-detail'per i campi del serializzatore con collegamento ipertestuale alla visualizzazione dei dettagli dell'utente.

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

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

1
Riassumendo, dare alla tua API uno spazio dei nomi causa l'errore nel titolo, probabilmente non vuoi farlo a meno che tu non voglia cambiarlo in molti posti.
Marco

ha funzionato per me! il mio urls.pyera doppio annidato nel mio newsiteprogetto: (1) newsite/urls.py(creato da django) (2) polls/urls.py(3) polls/api/v1/urls.py ............ Devo menzionare il nome annidato usandourl = serializers.HyperlinkedIdentityField(view_name="polls:polls_api:user-detail")
Grijesh Chauhan

12

Un altro brutto errore che causa questo errore è avere il nome_base definito inutilmente nel tuo urls.py. Per esempio:

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

Ciò causerà l'errore annotato sopra. Prendi quel nome_base da lì e torna a un'API funzionante. Il codice seguente risolverà l'errore. Evviva!

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

Tuttavia, probabilmente non hai semplicemente aggiunto arbitrariamente base_name, potresti averlo fatto perché hai definito un def get_queryset () personalizzato per la vista e quindi Django ti impone di aggiungere base_name. In questo caso dovrai definire esplicitamente l '"url" come HyperlinkedIdentityField per il serializzatore in questione. Si noti che stiamo definendo questo HyperlinkedIdentityField SUL SERIALIZER della vista che genera l'errore. Se il mio errore fosse "Impossibile risolvere l'URL per la relazione con collegamento ipertestuale utilizzando il nome della vista" studio-dettaglio ". Potresti non aver incluso il modello correlato nella tua API o aver configurato in modo errato l' lookup_fieldattributo in questo campo." Potrei risolvere questo problema con il seguente codice.

My ModelViewSet (il get_queryset personalizzato è il motivo per cui ho dovuto aggiungere base_name a router.register () in primo luogo):

class StudyViewSet(viewsets.ModelViewSet):
    serializer_class = StudySerializer

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

Registrazione del mio router per questo ModelViewSet in urls.py:

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

ED ECCO DOVE SONO I SOLDI! Quindi potrei risolverlo in questo modo:

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

Sì. È necessario definire esplicitamente questo HyperlinkedIdentityField su se stesso affinché funzioni. E devi assicurarti che il view_namedefinito in HyperlinkedIdentityField sia lo stesso che hai definito base_namein urls.py con un '-detail' aggiunto dopo.


2
Questo ha funzionato per me, tuttavia ho dovuto tracciare il percorso completo <app_name>:studies-detail. Ad esempio my, se la mia app viene chiamata tanks, il percorso completo sarebbe HyperlinkedIdentityField(view_name="tanks:studies-detail"). Per capirlo ho usato il comando django-exensions show_urls , per vedere il percorso completo e l'etichetta che il router stava creando automaticamente.
dtasev

10

Anche questo codice dovrebbe funzionare.

class BottleSerializer(serializers.HyperlinkedModelSerializer):

  user = UserSerializer()

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

3
Da notare che UserSerializerdeve essere implementato (non è pronto per l'importazione), come mostrato in django-rest-framework.org/api-guide/serializers
Caumons

Questo ha funzionato per me, ma perché funzionasse ho dovuto cambiare router.register (r'bottles ', views.BottleViewSet, base_name =' Bottle ') in router.register (r'bottles', views.BottleViewSet). Non so perché sia ​​stato richiesto questo cambiamento.
manichino

4

Mi sono imbattuto in questo errore dopo aver aggiunto lo spazio dei nomi al mio URL

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

e aggiungendo app_name al mio urls.py

Ho risolto questo problema specificando NamespaceVersioning per la mia API rest framework in settings.py del mio progetto

REST_FRAMEWORK = {
    'DEFAULT_VERSIONING_CLASS':'rest_framework.versioning.NamespaceVersioning'}

3

Oggi ho ricevuto lo stesso errore e le modifiche di seguito mi hanno salvato.

Modificare

class BottleSerializer(serializers.HyperlinkedModelSerializer):

per:

 class BottleSerializer(serializers.ModelSerializer):

2

Stesso errore, ma motivo diverso:

Definisco un modello utente personalizzato, niente di nuovo campo:

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

Questa è la mia funzione di visualizzazione:

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

Dato che non ho ceduto querysetdirettamente UserViewSet, devo impostare base_namequando registro questo set di visualizzazioni. Qui è dove il mio messaggio di errore causato dal urls.pyfile:

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'

Hai bisogno dello base_namestesso nome del tuo modello - customuser.


Vecchio post, ma il tuo commento "# <- base_name deve essere 'customuser' invece di 'user'" è ciò che mi ha salvato la giornata. Grazie!
Hannon César

1

Se stai estendendo le classi GenericViewSet e ListModelMixin e hai lo stesso errore quando aggiungi il campo URL nella visualizzazione elenco, è perché non stai definendo la visualizzazione dettagli. Assicurati di estendere il mixin RetrieveModelMixin :

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

1

Sembra che HyperlinkedModelSerializernon sia d'accordo con avere un percorso namespace. Nella mia domanda ho apportato due modifiche.

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

Nel file URL importato

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

Spero che questo ti aiuti.


0

Mi sono imbattuto nello stesso errore mentre stavo seguendo la guida rapida DRF http://www.django-rest-framework.org/tutorial/quickstart/ e quindi tentavo di navigare in / users. Ho eseguito questa configurazione molte volte in passato senza problemi.

La mia soluzione non era nel codice ma nella sostituzione del database.

La differenza tra questa installazione e le altre precedenti era quando ho creato il database locale.

Questa volta ho eseguito il mio

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

subito dopo la corsa

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

Invece dell'esatto ordine elencato nella guida.

Sospettavo che qualcosa non fosse stato creato correttamente nel DB. Non mi importava del mio dev db, quindi l'ho cancellato e ho eseguito il file./manage.py migrate comando, creato un super utente, navigato su / users e l'errore è sparito.

Qualcosa era problematico con l'ordine delle operazioni in cui ho configurato DRF e il db.

Se stai usando sqlite e sei in grado di provare il passaggio a un nuovo DB, vale la pena provare prima di analizzare tutto il codice.


0

Bottle = serializers.PrimaryKeyRelatedField (read_only = True)

read_only ti consente di rappresentare il campo senza doverlo collegare a un'altra vista del modello.


0

Ho ricevuto quell'errore su DRF 3.7.7 quando un valore di slug era vuoto (uguale a "") nel database.


0

Mi sono imbattuto in questo stesso problema e l'ho risolto aggiungendo generics.RetrieveAPIViewcome classe base al mio set di visualizzazioni.


0

Sono rimasto bloccato in questo errore per quasi 2 ore:

ImproperlyConfigured at / api_users / users / 1 / Impossibile risolvere l'URL per la relazione con collegamento ipertestuale utilizzando il nome della vista "utenti-dettaglio". Potresti non aver incluso il modello correlato nella tua API o aver configurato in modo errato l' lookup_fieldattributo in questo campo.

Quando finalmente ottengo la soluzione ma non capisco perché, quindi il mio codice è:

#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)),
]

ma nei miei URL principali era:

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

]

Quindi, finalmente risolvo il problema cancellando lo spazio dei nomi:

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

]

E finalmente risolvo il mio problema, quindi chiunque può farmi sapere perché, meglio.


0

Se ometti i campi "id" e "url" dal serializzatore non avrai alcun problema. Puoi accedere ai post utilizzando comunque l'id che viene restituito nell'oggetto json, il che rende ancora più semplice implementare il tuo frontend.


0

Ho avuto lo stesso problema, penso che dovresti controllare il tuo

get_absolute_url

valore di input del metodo del modello a oggetti (** kwargs) titolo. e usa il nome del campo esatto in lookup_field

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.