Django Rest Framework - Не вдалося вирішити URL-адресу для гіперпосилання з використанням імені перегляду "user-details"


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

Я не переглядаю детальну інформацію про користувача, і я не бачу, звідки може виникнути ця проблема. Якісь ідеї?

Дякую

Відповіді:


96

Оскільки HyperlinkedModelSerializerваш серіалізатор намагається вирішити URL-адресу для пов’язаних Userіз вами Bottle.
Оскільки у вас немає перегляду деталей користувача, це не може зробити. Звідси виняток.

  1. Чи не просто реєстрація UserViewSetмаршрутизатора вирішить вашу проблему?
  2. Ви можете визначити поле користувача у своєму BottleSerializerявному використанні, UserSerializerа не намагатися вирішити URL-адресу. Див. Документи про серіалізатор щодо роботи з вкладеними об'єктами для цього .

1
Велике спасибі, я прокоментував UserViewSet у своїх маршрутизаторах, що це вирішило!
bpipat

5
ТОЧА МОЖЛИВОСТЬ ---- роби це явно --- багато магії - це багато часу.
andilabs

Чи можете ви вказати, що неправильно налаштовано у моєму проекті ?
JJD

@ GrijeshChauhan - Спасибі! Тепер виправлено.
Карлтон Гібсон

Причина, що вона не працювала, полягала в тому, що django хотів показати пов’язані дані від користувача у вашому поточному представленні для параметра User. Зазвичай він підбирає список доступних значень. Оскільки UserViewSet не був визначений, він не зміг перетягнути дані для візуалізації веб-сторінки. Додавання UserViewSet і перереєстрація в маршрутизатор за замовчуванням робить реальними всі компоненти.
Doogle

65

Я також натрапив на цю помилку і вирішив її так:

Причиною є те, що я забув дати "** - деталі" (view_name, наприклад: user-details) простору імен. Отже, 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_ в маршруті!
Maggie

1
Ключовим тут є префікс простору імен, який запобігає роботі зворотного .....
boatcoder

У мене була така проблема, і ця відповідь вирішила мою проблему через 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')

1
Підводячи підсумок, надання вашого api простору імен викликає помилку в заголовку, ви, ймовірно, не хочете цього робити, якщо ви не хочете змінити його в багатьох місцях.
Марк

працював на мене! мій urls.pyбув двічі вкладений в в моєму newsiteпроекті: (1) newsite/urls.py(створений Джанго) (2) polls/urls.py(3) polls/api/v1/urls.py ............ Я повинен згадати вкладене ім'я з допомогоюurl = serializers.HyperlinkedIdentityField(view_name="polls:polls_api:user-detail")
Grijesh CHAUHAN

12

Ще одна неприємна помилка, яка викликає цю помилку, - це те, що у вашому urls.py необов'язково визначено ім’я base_name. Наприклад:

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

Це призведе до помилки, зазначеної вище. Дістаньте це ім’я base_name та поверніться до робочого API. Нижче наведений код виправить помилку. Ура!

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

Однак ви, ймовірно, не просто довільно додали ім'я base_name, можливо, це зробили, тому що ви визначили власну опцію get_queryset () для перегляду, і тому Django мандати додає ім'я base_name. У цьому випадку вам потрібно буде чітко визначити 'URL' як HyperlinkedIdentityField для відповідного серіалізатора. Зверніть увагу, що ми визначаємо це поле HyperlinkedIdentityField на СЕРІАЛІЗАТОРУ подання, яке видає помилку. Якщо моя помилка була "Не вдалося вирішити URL-адресу для зв’язків із гіперпосиланнями, використовуючи назву перегляду" study-деталь ". Можливо, ви не змогли включити відповідну модель у свій API або неправильно налаштували lookup_fieldатрибут у цьому полі." Я міг би це виправити за допомогою наступного коду.

Мій ModelViewSet (користувацький набір get_queryset, тому я повинен був додати базове ім'я до 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-exteensions 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 =' флакони ') на router.register (r'bottles', views.BottleViewSet). Я не знаю, чому потрібна була ця зміна.
manpikin

4

Я зіткнувся з цією помилкою після додавання простору імен до своєї URL-адреси

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

і додати ім’я_прикладу до мого urls.py

Я вирішив це, вказавши NamespaceVersioning для моєї програми відпочинку в api settings.py мого проекту

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

3

Сьогодні я отримав таку саму помилку і нижче зміни мене врятували.

Зміна

class BottleSerializer(serializers.HyperlinkedModelSerializer):

до:

 class BottleSerializer(serializers.ModelSerializer):

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.


Стара публікація, але ваш коментар "# <- base_name має бути" customuser "замість" user "" - це те, що врятувало мені день. Дякую!
Ганнон Сесар

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
]

У імпортованому файлі URL-адрес

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

Сподіваюся, це допомагає.


0

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

Моє рішення полягало не в коді, а в заміні бази даних.

Різниця між цією установкою та іншими раніше була, коли я створив локальну базу даних.

Цього разу я забігла свою

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

відразу після бігу

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

Замість точного порядку, зазначеного в путівнику.

Я підозрював, що щось не було створено належним чином у БД. Мені не було байдуже до свого dev db, тому я його видалив і запустив ./manage.py migrateкоманду ще раз, створив суперкористувача, переглянув / користувачів і помилка зникла.

Щось було проблематичним із порядком операцій, в яких я налаштовував DRF та db.

Якщо ви використовуєте sqlite і можете перевірити зміну на новий DB, тоді варто спробувати, перш ніж перейти до розбору всього вашого коду.


0

Пляшка = серіалізатори.PrimaryKeyRelatedField (read_only = True)

read_only дозволяє представляти поле без необхідності пов'язувати його з іншим видом моделі.


0

Я отримав цю помилку в DRF 3.7.7, коли значення базі було порожнім (дорівнює '') в базі даних.


0

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


0

Я застряг у цій помилці майже 2 години:

Неправильно налаштовано за адресою / api_users / users / 1 / Не вдалося вирішити URL-адресу для зв’язків із гіперпосиланням, використовуючи назву перегляду "користувач-деталь". Можливо, ви не змогли включити відповідну модель у свій 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')),

]

І я врешті вирішую свою проблему, тому будь-хто може дати мені знати, чому, найкраще.


0

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


0

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

get_absolute_url

Заголовок вхідного значення методу об'єктної моделі (** kwargs). і використовувати точну назву поля в lookup_field

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.