Kerangka Kerja Django - Tidak dapat menyelesaikan URL untuk hubungan hyperlink menggunakan nama tampilan "detail-pengguna"

108

Saya sedang membangun sebuah proyek dalam Django Rest Framework di mana pengguna dapat masuk untuk melihat gudang anggur mereka. ModelViewSets saya berfungsi dengan baik dan tiba-tiba saya mendapatkan kesalahan yang membuat frustrasi ini:

Tidak dapat menyelesaikan URL untuk hubungan hyperlink menggunakan nama tampilan "detail pengguna". Anda mungkin gagal memasukkan model terkait di API Anda, atau salah mengonfigurasi lookup_fieldatribut di bidang ini.

Traceback menunjukkan:

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

Saya memiliki model pengguna email ubahsuaian dan model botol di models.py adalah:

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

Serializers saya:

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

Pandangan saya:

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

dan terakhir url:

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

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

Saya tidak memiliki tampilan detail pengguna dan saya tidak melihat dari mana masalah ini bisa berasal. Ada ide?

Terima kasih

bpipat
sumber

Jawaban:

96

Karena itu HyperlinkedModelSerializerserializer Anda mencoba untuk menyelesaikan URL terkait Userdi Anda Bottle.
Karena Anda tidak memiliki tampilan detail pengguna, itu tidak dapat melakukan ini. Karenanya pengecualian.

  1. Bukankah hanya mendaftar UserViewSetdengan router menyelesaikan masalah Anda?
  2. Anda dapat menentukan bidang pengguna pada Anda BottleSerializeruntuk menggunakan secara eksplisit UserSerializerdaripada mencoba untuk menyelesaikan URL. Lihat dokumen serializer tentang menangani objek bersarang untuk itu .
Carlton Gibson
sumber
1
Terima kasih banyak, saya telah mengomentari UserViewSet di router saya, itu menyelesaikannya!
bpipat
5
ITULAH TITIKNYA ---- lakukan secara eksplisit --- terlalu banyak sihir berarti menghabiskan banyak waktu.
andilabs
Bisakah Anda menunjukkan apa yang salah konfigurasi pada proyek saya ?
JJD
@ GrijeshChauhan— Terima kasih! Sekarang sudah diperbaiki.
Carlton Gibson
Alasan tidak bekerja adalah karena django ingin menampilkan data terkait dari Pengguna dalam tampilan Anda saat ini untuk parameter Pengguna. Biasanya itu mengambil daftar nilai yang tersedia. Karena UserViewSet tidak ditentukan, ia tidak dapat menarik detail untuk merender halaman web. Menambahkan UserViewSet dan mendaftar di bawah router default membuat semuanya lengkap untuk membuat semua komponen.
Doogle
65

Saya menemukan kesalahan ini juga dan menyelesaikannya sebagai berikut:

Alasannya adalah saya lupa memberikan namespace "** - detail" (view_name, misalnya: user-detail). Jadi, Kerangka Istirahat Django tidak dapat menemukan tampilan itu.

Ada satu aplikasi dalam proyek saya, anggaplah nama proyek saya adalah myproject, dan nama aplikasinya adalah myapp.

Ada dua file urls.py, satu adalah myproject/urls.pydan yang lainnya adalah myapp/urls.py. Saya memberi aplikasi ruang nama myproject/urls.py, seperti:

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

Saya mendaftarkan router kerangka kerja lainnya myapp/urls.py, dan kemudian mendapatkan kesalahan ini.

Solusi saya adalah memberikan url dengan namespace secara eksplisit:

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

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

Dan itu memecahkan masalah saya.

bovenson
sumber
@boveson, ini berfungsi seperti pesona! Terima kasih Anda telah menyelesaikan berjam-jam frustrasi di pihak saya.
lmiguelvargasf
Ini juga membuatnya berhasil untuk saya. Satu hal penting juga di pihak saya adalah ejaan yang benar dari base_name di Route!
maggie
1
Kuncinya di sini adalah awalan namespace mencegah reverse bekerja .....
boatcoder
Saya mengalami masalah seperti ini dan jawaban ini memperbaiki masalah saya setelah 3 jam pencarian! @bovenson
Paus 52Hz
atau Anda dapat menggunakan extra_kwargs sebagai rekomendasi drf:extra_kwargs = {'url': {'view_name': 'myapp:user-detail'}}
ChrisRob
19

Mungkin seseorang dapat melihat ini: http://www.django-rest-framework.org/api-guide/routers/

Jika menggunakan namespacing dengan serializers hyperlink, Anda juga harus memastikan bahwa parameter view_name pada serializers mencerminkan namespace dengan benar. Sebagai contoh:

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

Anda harus menyertakan parameter seperti view_name='api:user-detail'untuk bidang serializer yang memiliki hyperlink ke tampilan detail pengguna.

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

class Meta:
    model = User
    fields = ('url', 'username')
JackPy
sumber
1
Ringkasnya, memberi api Anda namespace menyebabkan kesalahan pada judul, Anda mungkin tidak ingin melakukannya kecuali Anda ingin mengubahnya di banyak tempat.
Tandai
bekerja untuk saya! saya urls.pybersarang ganda dalam newsiteproyek saya : (1) newsite/urls.py(dibuat oleh django) (2) polls/urls.py(3) polls/api/v1/urls.py ............ Saya harus menyebutkan nama bersarang menggunakanurl = serializers.HyperlinkedIdentityField(view_name="polls:polls_api:user-detail")
Grijesh Chauhan
12

Kesalahan besar lainnya yang menyebabkan kesalahan ini adalah membuat base_name tidak perlu didefinisikan di urls.py. Sebagai contoh:

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

Ini akan menyebabkan kesalahan yang disebutkan di atas. Keluarkan base_name itu dari sana dan kembali ke API yang berfungsi. Kode di bawah ini akan memperbaiki kesalahan tersebut. Hore!

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

Bagaimanapun, anda mungkin tidak hanya menambahkan base_name secara sembarangan, anda mungkin telah melakukannya karena anda mendefinisikan sebuah def get_queryset () kustom untuk View dan Django mengamanatkan anda menambahkan base_name. Dalam hal ini Anda harus secara eksplisit mendefinisikan 'url' sebagai HyperlinkedIdentityField untuk serializer yang dimaksud. Perhatikan bahwa kita mendefinisikan HyperlinkedIdentityField ini PADA SERIALIZER tampilan yang menampilkan kesalahan. Jika kesalahan saya adalah "Tidak dapat menyelesaikan URL untuk hubungan hyperlink menggunakan nama tampilan" study-detail ". Anda mungkin gagal memasukkan model terkait di API Anda, atau salah mengonfigurasi lookup_fieldatribut di bidang ini." Saya bisa memperbaikinya dengan kode berikut.

ModelViewSet saya (get_queryset khusus adalah mengapa saya harus menambahkan base_name ke router.register () di tempat pertama):

class StudyViewSet(viewsets.ModelViewSet):
    serializer_class = StudySerializer

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

Pendaftaran router saya untuk ModelViewSet ini di urls.py:

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

DAN DI SINI DIMANA UANG INI! Kemudian saya bisa menyelesaikannya seperti ini:

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

Ya. Anda harus secara eksplisit mendefinisikan HyperlinkedIdentityField ini pada dirinya sendiri agar dapat berfungsi. Dan Anda perlu memastikan bahwa view_namedefinisi di HyperlinkedIdentityField sama seperti yang Anda definisikan di base_namedalam urls.py dengan '-detail' ditambahkan setelahnya.

Colton Hicks
sumber
2
Ini berhasil untuk saya, namun saya harus mengambil rute penuh <app_name>:studies-detail. Misalnya saya jika aplikasi saya dipanggil tanks, maka jalur lengkapnya adalah HyperlinkedIdentityField(view_name="tanks:studies-detail"). Untuk mengetahuinya saya menggunakan perintah django-exensions show_urls , untuk melihat rute lengkap dan label yang dibuat oleh router secara otomatis.
dtasev
10

Kode ini juga harus berfungsi.

class BottleSerializer(serializers.HyperlinkedModelSerializer):

  user = UserSerializer()

  class Meta:
    model = Bottle
    fields = ('url', 'wine', 'user')
caglar
sumber
3
Perlu dicatat bahwa UserSerializerharus diterapkan (belum siap untuk diimpor), seperti yang ditunjukkan di django-rest-framework.org/api-guide/serializers
Caumons
Ini berhasil untuk saya, tetapi agar berfungsi, saya harus mengubah router.register (r'bottles ', views.BottleViewSet, base_name =' bottles ') menjadi router.register (r'bottles', views.BottleViewSet). Saya tidak tahu mengapa perubahan ini diperlukan.
manpikin
4

Saya mengalami kesalahan ini setelah menambahkan namespace ke url saya

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

dan menambahkan app_name ke urls.py saya

Saya menyelesaikan ini dengan menentukan NamespaceVersioning untuk api kerangka istirahat saya di settings.py dari proyek saya

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

Hari ini, saya mendapat kesalahan yang sama dan perubahan di bawah menyelamatkan saya.

Perubahan

class BottleSerializer(serializers.HyperlinkedModelSerializer):

untuk:

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

Kesalahan yang sama, tetapi alasan berbeda:

Saya mendefinisikan model pengguna khusus, tidak ada bidang baru:

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

Ini adalah fungsi tampilan saya:

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

Karena saya tidak querysetlangsung menyerah UserViewSet, saya harus mengatur base_namekapan saya mendaftarkan viewset ini. Di sinilah pesan kesalahan saya disebabkan oleh 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'

Anda membutuhkan nama yang base_namesama dengan model Anda - customuser.

Belter
sumber
Posting lama, tapi komentar Anda "# <- base_name harus 'customuser' bukan 'user'" adalah yang menyelamatkan hari saya. Terima kasih!
Hannon César
1

Jika Anda memperluas kelas GenericViewSet dan ListModelMixin , dan mengalami kesalahan yang sama saat menambahkan bidang url dalam tampilan daftar, itu karena Anda tidak mendefinisikan tampilan detail. Pastikan Anda memperluas mixin RetrieveModelMixin :

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

Tampaknya HyperlinkedModelSerializertidak setuju dengan memiliki jalan namespace. Dalam aplikasi saya, saya membuat dua perubahan.

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

Di file url yang diimpor

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

Semoga ini membantu.

Cody Wikman
sumber
0

Saya mengalami kesalahan yang sama ketika saya mengikuti panduan mulai cepat DRF http://www.django-rest-framework.org/tutorial/quickstart/ dan kemudian mencoba menjelajah ke / users. Saya telah melakukan pengaturan ini berkali-kali sebelumnya tanpa masalah.

Solusi saya bukan dalam kode tetapi dalam mengganti database.

Perbedaan antara instalasi ini dan yang lainnya sebelumnya adalah ketika saya membuat database lokal.

Kali ini saya berlari

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

segera setelah berlari

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

Alih-alih urutan persis yang tercantum dalam panduan.

Saya curiga ada sesuatu yang tidak dibuat dengan benar di DB. Saya tidak peduli dengan dev db saya jadi saya menghapusnya dan menjalankan ./manage.py migrateperintah sekali lagi, membuat pengguna super, menjelajahi / users dan kesalahannya hilang.

Ada yang bermasalah dengan urutan operasi yang saya konfigurasikan DRF dan db.

Jika Anda menggunakan sqlite dan dapat menguji perubahan ke DB baru, maka patut dicoba sebelum Anda membedah semua kode Anda.

Ben Havilland
sumber
0

Bottle = serializers.PrimaryKeyRelatedField (read_only = True)

read_only memungkinkan Anda untuk mewakili bidang tanpa harus menautkannya ke tampilan lain dari model.

Cristian Fernando
sumber
0

Saya mendapat kesalahan itu di DRF 3.7.7 ketika nilai siput kosong (sama dengan '') di database.

mrmuggles
sumber
0

Saya mengalami masalah yang sama ini dan mengatasinya dengan menambahkan generics.RetrieveAPIViewsebagai kelas dasar ke kumpulan tampilan saya.

Jace Browning
sumber
0

Saya terjebak dalam kesalahan ini selama hampir 2 jam:

Tidak Sesuai Dikonfigurasi di / api_users / users / 1 / Tidak dapat menyelesaikan URL untuk hubungan hyperlink menggunakan nama tampilan "detail pengguna". Anda mungkin gagal memasukkan model terkait di API Anda, atau salah mengonfigurasi lookup_fieldatribut di bidang ini.

Ketika saya akhirnya mendapatkan solusinya tetapi saya tidak mengerti mengapa, jadi kode saya adalah:

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

tetapi di URL utama saya, itu adalah:

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

]

Jadi untuk akhirnya saya menyelesaikan masalah menghapus namespace:

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

]

Dan saya akhirnya menyelesaikan masalah saya, jadi siapa pun dapat memberi tahu saya alasannya, yang terbaik.

Cam T
sumber
0

Jika Anda menghilangkan field 'id' dan 'url' dari serializer Anda, Anda tidak akan mengalami masalah. Anda dapat mengakses posting dengan menggunakan id yang dikembalikan di objek json, yang membuatnya lebih mudah untuk mengimplementasikan frontend Anda.

Eduardo A. Fernández Díaz
sumber
0

Saya memiliki masalah yang sama, saya pikir Anda harus memeriksa

get_absolute_url

judul metode input nilai model objek (** kwargs). dan gunakan nama bidang yang tepat di lookup_field

hassanzadeh.sd
sumber