2015-08-25 9 views
21

È possibile utilizzare lo slug di un oggetto (o qualsiasi altro campo) per accedere ai dettagli di un oggetto, invece di utilizzare l'ID?Django Rest Framework: accedi al dettaglio dell'oggetto tramite slug invece dell'ID

Ad esempio, se si dispone di un elemento con lo slug "lorem" e ID 1. Per impostazione predefinita l'URL è http://localhost:9999/items/1/. Voglio accedervi tramite http://localhost:9999/items/lorem/ invece.

L'aggiunta di lookup_field nella classe Meta del serializzatore non ha fatto nulla per modificare l'URL generato automaticamente né mi ha consentito di accedere all'elemento scrivendo manualmente lo slug anziché l'ID nell'URL.

models.py

class Item(models.Model): 
    slug = models.CharField(max_length=100, unique=True) 
    title = models.CharField(max_length=100, blank=True, default='') 
    # An arbitrary, user provided, URL 
    item_url = models.URLField(unique=True) 

serializers.py

class ClassItemSerializer(serializers.HyperlinkedModelSerializer): 
    class Meta: 
     model = Item 
     fields = ('url', 'slug', 'title', 'item_url') 

views.py

class ItemViewSet(viewsets.ModelViewSet): 
    queryset = Item.objects.all() 
    serializer_class = ItemSerializer 

urls.py

router = DefaultRouter() 
router.register(r'items', views.ItemViewSet) 

urlpatterns = [ 
    url(r'^', include(router.urls)), 
] 

JSON Generated:

[ 
    { 
     "url": "http://localhost:9999/items/1/", 
     "slug": "lorem", 
     "title": "Lorem", 
     "item_url": "http://example.com" 
    } 
] 
+0

Non c'è tempo per una risposta completa, ma si possono trovare quello che stai cercando per il [pagina di router Documenti per DRF] (http: //www.django-rest-framework .org/api-guida/router/# simplerouter). In particolare, nella parte inferiore della sezione collegata per 'SimpleRouter', guarda l'esempio con' classe MyModelViewSet'. Penso che questo ti permetta di cambiare il valore di ricerca in qualunque cosa tu voglia. Potrebbe essere un buon punto di partenza. – eykanal

+0

Notate che state usando 'DefaultRouter', non' SimpleRouter' ... Non sono sicuro quale sia questa funzionalità in entrambe le classi. – eykanal

risposta

32

È necessario impostare lookup_field nel vostro serializzatore:

class ItemSerializer(serializers.HyperlinkedModelSerializer): 
    class Meta: 
     model = Item 
     fields = ('url', 'slug', 'title', 'item_url') 
     lookup_field = 'slug' 
     extra_kwargs = { 
      'url': {'lookup_field': 'slug'} 
     } 

e nella vista:

class ItemViewSet(viewsets.ModelViewSet): 
    queryset = Item.objects.all() 
    serializer_class = ItemSerializer 
    lookup_field = 'slug' 

ho ottenuto questo risultato:

~ curl http://127.0.0.1:8000/items/testslug/ | python -mjson.tool 
{ 
    "item_url": "https://example.com/", 
    "slug": "testslug", 
    "title": "Test Title", 
    "url": "http://127.0.0.1:8000/items/testslug/" 
} 
+1

Volevo solo notare che con l'aggiunta di 'extra_kwargs = {'url': {'lookup_field': 'slug'}}', ho ricevuto il seguente errore: ** TypeError: __init __() ha ottenuto un argomento di parole chiave non previsto 'lookup_field '**. Una volta rimosso, funzionava perfettamente. – Michael

+0

La stessa cosa è successo a me, grazie per il tuo commento. Altrimenti avrei perso più tempo. – javed

+1

Ciò è accaduto perché non stavo usando il campo 'url' nella tupla dei campi della classe Serializer Meta. Dopo aver aggiunto il campo 'url' ho usato: extra_kwargs = {'url': {'lookup_field:' slug ''}} – javed

2

In alcuni scenari potrebbe essere necessario avere sia il valore "basso livello" pk sia il più semantico slug. Mi piace avere entrambe le opzioni personalmente e farlo impostando lo lookup_field in un secondo momento nel metodo di visualizzazione as_view() nel mio urls.py.

Note: the following defaults to pk with an optional slug lookup. To combine this with previous answer you would change the lookup_field below to be "pk" instead of "slug".

from django.conf.urls import * 
from rest_framework.urlpatterns import format_suffix_patterns 

from myobjects import views as myviews 


# simplify the view definitions by splitting out the options 
REQDICT = { 
    'get': 'retrieve', 
    'put': 'update', 
    'patch': 'partial_update', 
    'delete': 'destroy' 
} 


# define the pk detail view 
myobject_detail = myviews.MyObjectViewset.as_view(REQDICT) 
# define the slug detail view 
myobject_slug_detail = myviews.MyObjectViewset.as_view(REQDICT, lookup_field='slug') 


urlpatterns = [ 
    url(r"^myobjects/(?P<pk>\d*)/$", 
      myobject_detail, 
      name = 'myobject-detail'), 
    url(r"^myobjects/(?P<slug>[-\w]+)/$", 
      myobject_slug_detail, 
      name = 'myobject-slug-detail'), 
] 

urlpatterns = format_suffix_patterns(urlpatterns) 

This could also be in your views.py - my preference is to see it beside the urlpatterns list.

Problemi correlati