Django Rest Framework - не удалось разрешить URL-адрес для гиперссылки с использованием имени представления «подробности пользователя».

108

Я создаю проект в Django Rest Framework, где пользователи могут войти в систему, чтобы просмотреть свой винный погреб. Мои ModelViewSets работали нормально, и внезапно я получаю эту неприятную ошибку:

Не удалось разрешить URL-адрес для связи с гиперссылкой с использованием имени представления «сведения о пользователе». Возможно, вы не смогли включить связанную модель в свой API или неправильно настроили lookup_fieldатрибут в этом поле.

Трассировка показывает:

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

У меня есть пользовательская модель электронной почты, а модель бутылки в models.py:

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

Мои сериализаторы:

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

Мои взгляды:

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

и, наконец, URL:

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

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

У меня нет представления сведений о пользователе, и я не понимаю, откуда могла возникнуть эта проблема. Любые идеи?

Спасибо

bpipat
источник

Ответы:

96

Поскольку HyperlinkedModelSerializerваш сериализатор пытается разрешить URL-адрес, связанный Userс вашим Bottle.
Поскольку у вас нет подробного представления пользователя, он не может этого сделать. Отсюда исключение.

  1. Не UserViewSetрешит ли вашу проблему простая регистрация на маршрутизаторе?
  2. Вы можете определить пользовательское поле на своем, BottleSerializerчтобы явно использовать, UserSerializerа не пытаться разрешить URL. См. Документацию по сериализатору о работе с вложенными объектами .
Карлтон Гибсон
источник
1
Большое спасибо, я закомментировал UserViewSet в своих роутерах, и это решило!
bpipat
5
ЭТО ТОЧКА - делайте это явно - для большого количества магии теряется много времени.
andilabs
Не могли бы вы указать, что в моем проекте неправильно настроено ?
JJD
@ GrijeshChauhan - Спасибо! Теперь исправлено.
Карлтон Гибсон
Причина, по которой он не работал, заключалась в том, что django хотел показать связанные данные от пользователя в вашем текущем представлении для параметра User. Обычно он выбирает список доступных значений. Поскольку UserViewSet не был определен, он не смог извлечь детали для отображения веб-страницы. Добавление UserViewSet и регистрация в маршрутизаторе по умолчанию завершает процесс визуализации всех компонентов.
Doogle
66

Я тоже столкнулся с этой ошибкой и решил ее следующим образом:

Причина в том, что я забыл указать "** - detail" (view_name, например: user-detail) пространство имен. Итак, Django Rest Framework не смог найти это представление.

В моем проекте есть одно приложение, предположим, что мое имя проекта myproject, а имя приложения myapp.

Есть два файла urls.py, один myproject/urls.pyи другой myapp/urls.py. Я даю приложению пространство имен myproject/urls.py, например:

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

Я зарегистрировал остальные маршрутизаторы фреймворка myapp/urls.py, а затем получил эту ошибку.

Мое решение заключалось в том, чтобы явно указать URL-адрес с пространством имен:

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

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

И это решило мою проблему.

Бовенсон
источник
@boveson, это прекрасно работает! Спасибо, что преодолели часы разочарования на моей стороне.
lmiguelvargasf
Это тоже помогло мне. Еще одним важным моментом с моей стороны было правильное написание base_name в Route!
Мэгги
1
Ключевым моментом здесь является префикс пространства имен, предотвращающий работу реверса ...
boatcoder 01
У меня была такая проблема, и этот ответ устранил мою проблему после 3 часов поиска! @bovenson
Whale 52Hz
или вы можете использовать extra_kwargs, как рекомендует extra_kwargs = {'url': {'view_name': 'myapp:user-detail'}}
drf
19

Может быть, кто-то может взглянуть на это: http://www.django-rest-framework.org/api-guide/routers/

При использовании пространства имен с сериализаторами с гиперссылками вам также необходимо убедиться, что любые параметры view_name в сериализаторах правильно отражают пространство имен. Например:

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

вам нужно будет включить параметр, например, view_name='api:user-detail'для полей сериализатора, гиперссылки на представление сведений о пользователе.

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

class Meta:
    model = User
    fields = ('url', 'username')
JackPy
источник
1
Подводя итог, предоставление вашему api пространства имен вызывает ошибку в заголовке, вы, вероятно, не захотите этого делать, если вы не захотите изменить его во многих местах.
Марк
у меня сработало! my urls.pyбыл дважды вложен в мой newsiteпроект: (1) newsite/urls.py(created by django) (2) polls/urls.py(3) polls/api/v1/urls.py ............ Я должен упомянуть использование вложенного имениurl = serializers.HyperlinkedIdentityField(view_name="polls:polls_api:user-detail")
Grijesh Chauhan
12

Еще одна неприятная ошибка, которая вызывает эту ошибку, - это необязательное определение base_name в вашем urls.py. Например:

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

Это вызовет указанную выше ошибку. Извлеките это base_name и вернитесь к работающему API. Приведенный ниже код исправит ошибку. Ура!

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

Однако вы, вероятно, не просто произвольно добавили base_name, вы могли это сделать, потому что вы определили собственный def get_queryset () для View, и поэтому Django требует, чтобы вы добавили base_name. В этом случае вам нужно явно определить url как HyperlinkedIdentityField для рассматриваемого сериализатора. Обратите внимание, что мы определяем это поле HyperlinkedIdentityField НА СЕРИАЛИЗАТОРЕ представления, которое выдает ошибку. Если бы моя ошибка была «Не удалось разрешить URL-адрес для связи с гиперссылкой с использованием имени представления« исследование-деталь ». Возможно, вы не смогли включить связанную модель в свой API или неправильно настроили lookup_fieldатрибут в этом поле». Я мог бы исправить это с помощью следующего кода.

Мой ModelViewSet (пользовательский get_queryset - вот почему мне в первую очередь пришлось добавить base_name в router.register ()):

class StudyViewSet(viewsets.ModelViewSet):
    serializer_class = StudySerializer

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

Регистрация моего маршрутизатора для этого ModelViewSet в urls.py:

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

И ВОТ ГДЕ ДЕНЬГИ! Тогда я мог бы решить это так:

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

Ага. Вы должны явно определить этот HyperlinkedIdentityField на самом себе, чтобы он работал. И вам необходимо убедиться, что значение, view_nameопределенное в HyperlinkedIdentityField, совпадает с тем, которое вы определили base_nameв urls.py с добавленным после него «-detail».

Колтон Хикс
источник
2
Это сработало для меня, однако мне пришлось проложить полный маршрут <app_name>:studies-detail. Например, если вызывается мое приложение tanks, полный путь будет HyperlinkedIdentityField(view_name="tanks:studies-detail"). Чтобы понять это, я использовал команду django-exensions show_urls , чтобы увидеть полный маршрут и метку, которую маршрутизатор создавал автоматически.
dtasev
10

Этот код тоже должен работать.

class BottleSerializer(serializers.HyperlinkedModelSerializer):

  user = UserSerializer()

  class Meta:
    model = Bottle
    fields = ('url', 'wine', 'user')
крик
источник
3
Стоит отметить, что это UserSerializerдолжно быть реализовано (оно не готово к импорту), как показано в django-rest-framework.org/api-guide/serializers
Caumons
Это сработало для меня, но для того, чтобы он работал, мне пришлось изменить router.register (r'bottles ', views.BottleViewSet, base_name =' Bottle ') на router.register (r'bottles', views.BottleViewSet). Я не знаю, почему потребовалось это изменение.
manpikin
4

Я столкнулся с этой ошибкой после добавления пространства имен к моему URL-адресу

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

и добавление app_name в мой urls.py

Я решил это, указав NamespaceVersioning для API моей остальной инфраструктуры в settings.py моего проекта.

REST_FRAMEWORK = {
    'DEFAULT_VERSIONING_CLASS':'rest_framework.versioning.NamespaceVersioning'}
Келечукву Нвосу
источник
3

Сегодня я получил ту же ошибку, и ниже меня спасают изменения.

+ Изменить

class BottleSerializer(serializers.HyperlinkedModelSerializer):

кому:

 class BottleSerializer(serializers.ModelSerializer):
Manish Pal
источник
2

Та же ошибка, но другая причина:

Я определяю настраиваемую модель пользователя, ничего нового в поле:

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

Это моя функция просмотра:

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

Поскольку я не сдавался querysetнапрямую UserViewSet, я должен установить это base_nameпри регистрации этого набора просмотров. Вот где мое сообщение об ошибке вызвано urls.pyфайлом:

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'

Вам нужно такое base_nameже, как и название вашей модели - customuser.

Belter
источник
Старый пост, но ваш комментарий «# <- base_name должен быть 'customuser' вместо 'user'» - вот что спасло меня. Спасибо!
Hannon César,
1

Если вы расширяете классы GenericViewSet и ListModelMixin и имеете ту же ошибку при добавлении поля URL- адреса в представление списка, это потому, что вы не определяете подробное представление. Убедитесь, что вы расширяете миксин RetrieveModelMixin :

class UserViewSet (mixins.ListModelMixin,
                   mixins.RetrieveModelMixin,
                   viewsets.GenericViewSet):
Ровинсон Гальего
источник
1

Похоже, что HyperlinkedModelSerializerне согласен с тем, чтобы иметь путь namespace. В своем приложении я внес два изменения.

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

В импортированном файле urls

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

Надеюсь это поможет.

Коди Викман
источник
0

Я столкнулся с той же ошибкой, когда следил за кратким руководством по DRF http://www.django-rest-framework.org/tutorial/quickstart/ а затем пытался перейти к / users. Я уже много раз делал эту настройку без проблем.

Мое решение заключалось не в коде, а в замене базы данных.

Разница между этой установкой и предыдущими установками заключалась в том, что я создал локальную базу данных.

На этот раз я запустил свой

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

сразу после бега

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

Вместо точного порядка, указанного в руководстве.

Я подозревал, что что-то неправильно создано в БД. Меня не волновала моя база данных разработчика, поэтому я удалил ее и запустил./manage.py migrate команду, создал суперпользователя, просмотрел / users, и ошибка исчезла.

Что-то было проблематично с порядком операций, в котором я настроил DRF и db.

Если вы используете sqlite и можете протестировать переход на новую БД, то стоит попробовать, прежде чем анализировать весь свой код.

Бен Хэвилленд
источник
0

Бутылка = сериализаторы.PrimaryKeyRelatedField (read_only = True)

read_only позволяет вам представлять поле без необходимости связывать его с другим видом модели.

Кристиан Фернандо
источник
0

Я получил эту ошибку в DRF 3.7.7, когда значение слага было пустым (равно "") в базе данных.

mrmuggles
источник
0

Я столкнулся с той же проблемой и решил ее, добавив generics.RetrieveAPIViewв качестве базового класса свой набор представлений.

Джейс Браунинг
источник
0

Я застрял в этой ошибке почти 2 часа:

Неправильно настроен в / api_users / users / 1 / Не удалось разрешить URL-адрес для связи с гиперссылкой с использованием имени представления "users-detail". Возможно, вы не смогли включить связанную модель в свой API или неправильно настроилиlookup_field атрибут в этом поле.

Когда я наконец получил решение, но не понимаю почему, мой код:

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

но в моих основных URL-адресах это было:

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

]

Итак, чтобы наконец решить проблему с удалением пространства имен:

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

]

И я наконец решил свою проблему, так что любой может сообщить мне почему, бест.

Cam T
источник
0

Если вы опустите поля id и url в сериализаторе, у вас не будет никаких проблем. В любом случае вы можете получить доступ к сообщениям, используя идентификатор, который возвращается в объекте json, что еще больше упрощает реализацию вашего интерфейса.

Эдуардо А. Фернандес Диас
источник
0

У меня была такая же проблема, думаю, вам стоит проверить свой

get_absolute_url

входное значение метода объектной модели (** kwargs) title. и используйте точное имя поля в lookup_field

hassanzadeh.sd
источник