Django Rest Framework: no se pudo resolver la URL para la relación de hipervínculo usando el nombre de vista "detalle de usuario"

108

Estoy construyendo un proyecto en Django Rest Framework donde los usuarios pueden iniciar sesión para ver su bodega. Mis ModelViewSets funcionaban bien y, de repente, aparece este frustrante error:

No se pudo resolver la URL para la relación de hipervínculo usando el nombre de vista "detalles de usuario". Es posible que no haya incluido el modelo relacionado en su API o haya configurado incorrectamente el lookup_fieldatributo en este campo.

El rastreo muestra:

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

Tengo un modelo de usuario de correo electrónico personalizado y el modelo de botella en models.py es:

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

Mis serializadores:

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

Mis puntos de vista:

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

y finalmente la url:

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

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

No tengo una vista de detalles de usuario y no veo de dónde podría venir este problema. ¿Algunas ideas?

Gracias

bpipat
fuente

Respuestas:

96

Debido a que es un HyperlinkedModelSerializerserializador que está tratando de resolver la URL del archivo relacionado Useren su Bottle.
Como no tiene la vista de detalles del usuario, no puede hacer esto. De ahí la excepción.

  1. ¿No UserViewSetresolvería su problema simplemente registrar el con el enrutador?
  2. Puede definir el campo de usuario en su BottleSerializerpara usar explícitamente el en UserSerializerlugar de intentar resolver la URL. Consulte los documentos del serializador sobre cómo tratar con objetos anidados para eso .
Carlton Gibson
fuente
1
Muchas gracias, había comentado el UserViewSet en mis enrutadores, ¡eso lo resolvió!
bpipat
5
ESE ES EL PUNTO --- hazlo explícitamente --- mucha magia es mucho tiempo perdido.
andilabs
¿Puede señalar qué está mal configurado en mi proyecto ?
JJD
@ GrijeshChauhan— ¡Gracias! Ahora arreglado.
Carlton Gibson
La razón por la que no funcionaba era porque django quería mostrar datos relacionados del Usuario en su vista actual para el parámetro Usuario. Por lo general, recoge una lista de valores disponibles. Dado que UserViewSet no se definió, no pudo extraer los detalles para representar la página web. Agregar UserViewSet y registrarse bajo el enrutador predeterminado hace que todo se complete para renderizar todos los componentes.
Doogle
65

También encontré este error y lo resolví de la siguiente manera:

La razón es que olvidé dar "** - detalle" (view_name, por ejemplo: user-detail) un espacio de nombres. Entonces, Django Rest Framework no pudo encontrar esa vista.

Hay una aplicación en mi proyecto, supongamos que el nombre de mi proyecto es myprojecty el nombre de la aplicación es myapp.

Hay dos archivos urls.py, uno es myproject/urls.pyy el otro es myapp/urls.py. Le doy a la aplicación un espacio de nombres myproject/urls.py, como:

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

Registré el resto de los enrutadores del marco myapp/urls.pyy luego recibí este error.

Mi solución fue proporcionar URL con espacio de nombres explícitamente:

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

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

Y resolvió mi problema.

Bovenson
fuente
@boveson, ¡esto funciona de maravilla! Gracias, resolviste horas de frustración de mi lado.
lmiguelvargasf
Esto también lo hizo funcionar para mí. ¡Otro punto importante de mi lado fue la ortografía correcta del nombre_base en la Ruta!
maggie
1
La clave aquí es el prefijo de espacio impide inversa funcione .....
boatcoder
¡Tuve un problema como este y esta respuesta solucionó mi problema después de 3 horas de búsqueda! @bovenson
Whale 52Hz
o puede hacer uso de extra_kwargs como recomienda drf:extra_kwargs = {'url': {'view_name': 'myapp:user-detail'}}
ChrisRob
19

Tal vez alguien pueda echarle un vistazo a esto: http://www.django-rest-framework.org/api-guide/routers/

Si usa espacio de nombres con serializadores hipervínculos, también deberá asegurarse de que cualquier parámetro view_name en los serializadores refleje correctamente el espacio de nombres. Por ejemplo:

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

Debería incluir un parámetro como, view_name='api:user-detail'por ejemplo, para los campos del serializador hipervinculados a la vista de detalles del usuario.

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

class Meta:
    model = User
    fields = ('url', 'username')
JackPy
fuente
1
En resumen, darle a su api un espacio de nombres causa el error en el título, probablemente no quiera hacerlo a menos que quiera cambiarlo en muchos lugares.
Mark
¡trabajó para mi! mi urls.pyfue anidado doblemente en mi newsiteproyecto: (1) newsite/urls.py(creado por django) (2) polls/urls.py(3) polls/api/v1/urls.py ............ Tengo que mencionar el nombre anidado usandourl = serializers.HyperlinkedIdentityField(view_name="polls:polls_api:user-detail")
Grijesh Chauhan
12

Otro error desagradable que causa este error es tener el nombre_base definido innecesariamente en su urls.py. Por ejemplo:

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

Esto provocará el error mencionado anteriormente. Saca ese nombre_base de ahí y vuelve a una API que funcione. El siguiente código solucionaría el error. ¡Hurra!

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

Sin embargo, probablemente no solo agregó arbitrariamente el nombre_base, es posible que lo haya hecho porque definió un def get_queryset () personalizado para la Vista, por lo que Django exige que agregue el nombre_base. En este caso, deberá definir explícitamente la 'url' como HyperlinkedIdentityField para el serializador en cuestión. Observe que estamos definiendo este HyperlinkedIdentityField EN EL SERIALIZER de la vista que arroja el error. Si mi error fuera "No se pudo resolver la URL para la relación de hipervínculo usando el nombre de vista" estudio-detalle ". Es posible que no haya incluido el modelo relacionado en su API o haya configurado incorrectamente el lookup_fieldatributo en este campo". Podría arreglar esto con el siguiente código.

Mi ModelViewSet (el get_queryset personalizado es la razón por la que tuve que agregar el base_name al router.register () en primer lugar):

class StudyViewSet(viewsets.ModelViewSet):
    serializer_class = StudySerializer

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

Mi registro de enrutador para este ModelViewSet en urls.py:

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

¡Y AQUÍ ESTÁ EL DINERO! Entonces podría resolverlo así:

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í. Debe definir explícitamente este HyperlinkedIdentityField en sí mismo para que funcione. Y debe asegurarse de que lo view_namedefinido en HyperlinkedIdentityField sea el mismo que definió base_nameen urls.py con un '-detail' agregado después.

Colton Hicks
fuente
2
Esto funcionó para mí, sin embargo tuve que poner la ruta completa <app_name>:studies-detail. Por ejemplo, si se llama a mi aplicación tanks, entonces la ruta completa sería HyperlinkedIdentityField(view_name="tanks:studies-detail"). Para averiguarlo , usé el show_urls comando django-exensions , para ver la ruta completa y la etiqueta que el enrutador estaba haciendo automáticamente.
dtasev
10

Este código también debería funcionar.

class BottleSerializer(serializers.HyperlinkedModelSerializer):

  user = UserSerializer()

  class Meta:
    model = Bottle
    fields = ('url', 'wine', 'user')
caglar
fuente
3
Vale la pena señalar que UserSerializerdebe implementarse (no está listo para importar), como se muestra en django-rest-framework.org/api-guide/serializers
Caumons
Esto funcionó para mí, pero para que funcionara tuve que cambiar router.register (r'bottles ', views.BottleViewSet, base_name =' bottle ') a router.register (r'bottles', views.BottleViewSet). No sé por qué se requirió este cambio.
manpikin
4

Me encontré con este error después de agregar un espacio de nombres a mi url

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

y agregando app_name a mi urls.py

Resolví esto especificando NamespaceVersioning para mi api de marco de descanso en settings.py de mi proyecto

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

Hoy, tengo el mismo error y los cambios a continuación me rescatan.

Cambio

class BottleSerializer(serializers.HyperlinkedModelSerializer):

a:

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

Mismo error, pero diferente razón:

Defino un modelo de usuario personalizado, nada nuevo 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

Esta es mi función de vista:

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

Como no me rendí querysetdirectamente UserViewSet, tengo que establecer base_namecuándo registro este conjunto de vistas. Aquí es donde mi mensaje de error causado por el urls.pyarchivo:

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'

Necesita lo base_namemismo que el nombre de su modelo - customuser.

Belter
fuente
Publicación anterior, pero tu comentario "# <- base_name debe ser 'customuser' en lugar de 'user'" es lo que me salvó el día. ¡Gracias!
Hannon César
1

Si está extendiendo los GenericViewSet y ListModelMixin clases, y tienen el mismo error al añadir la url campo en la vista de lista, es porque no estás definiendo la vista de detalle. Asegúrese de extender el mixin RetrieveModelMixin :

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

Parece que HyperlinkedModelSerializerno estoy de acuerdo con tener un camino namespace. En mi aplicación hice dos cambios.

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

En el archivo de URL importado

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

Espero que esto ayude.

Cody Wikman
fuente
0

Me encontré con el mismo error mientras seguía la guía de inicio rápido de DRF http://www.django-rest-framework.org/tutorial/quickstart/ y luego intentaba navegar a / users. He hecho esta configuración muchas veces antes sin problemas.

Mi solución no estaba en el código sino en reemplazar la base de datos.

La diferencia entre esta instalación y las otras anteriores fue cuando creé la base de datos local.

Esta vez corrí mi

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

inmediatamente después de correr

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

En lugar del orden exacto que aparece en la guía.

Sospeché que algo no se creó correctamente en la base de datos. No me importaba mi db de desarrollo, así que lo eliminé y ejecuté el./manage.py migrate comando una vez más, creé un superusuario, navegué hasta / users y el error desapareció.

Algo fue problemático con el orden de operaciones en el que configuré DRF y la base de datos.

Si está utilizando sqlite y puede probar el cambio a una base de datos nueva, vale la pena intentarlo antes de analizar todo su código.

Ben Havilland
fuente
0

Botella = serializadores.PrimaryKeyRelatedField (read_only = True)

read_only le permite representar el campo sin tener que vincularlo a otra vista del modelo.

Cristian fernando
fuente
0

Recibí ese error en DRF 3.7.7 cuando un valor de slug estaba vacío (igual a '') en la base de datos.

mrmuggles
fuente
0

Me encontré con este mismo problema y lo resolví agregando generics.RetrieveAPIViewcomo clase base a mi conjunto de vistas.

Jace Browning
fuente
0

Estuve atrapado en este error durante casi 2 horas:

Configurado incorrectamente en / api_users / users / 1 / No se pudo resolver la URL para la relación de hipervínculo usando el nombre de vista "detalles de usuarios". Es posible que no haya incluido el modelo relacionado en su API o haya configurado incorrectamente el lookup_fieldatributo en este campo.

Cuando finalmente obtengo la solución pero no entiendo por qué, entonces mi código es:

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

pero en mis URL principales, era:

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

]

Entonces, para finalmente resolver el problema de borrar el espacio de nombres:

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

]

Y finalmente resuelvo mi problema, para que cualquiera pueda decirme por qué, mejor.

Cam T
fuente
0

Si omite los campos 'id' y 'url' de su serializador, no tendrá ningún problema. Puede acceder a las publicaciones utilizando la identificación que se devuelve en el objeto json de todos modos, lo que facilita aún más la implementación de su interfaz.

Eduardo A. Fernández Díaz
fuente
0

Tuve el mismo problema, creo que deberías revisar tu

get_absolute_url

título del valor de entrada del método del modelo de objeto (** kwargs). y use el nombre de campo exacto en lookup_field

hassanzadeh.sd
fuente