martes, 1 de abril de 2014

API REST con Django REST Framework (2 de 2)

Una vez ya escritos los modelos y después de haber interactuado con ellos en el administrador es momento de crear recursos para que pueden ser consumidos por una aplicación móvil o página web.

El primer paso es añadir la aplicación 'rest_framework' al settings.py. Después de esto hay que crear un nuevo archivo al cual le llamaremos (por convención) serializers.py el cual contendrá lo siguiente:

from rest_framework import serializers
from peliculas.models import *

class DirectorSerializer(serializers.ModelSerializer):
class Meta:
model = Director
fields = ('nombreDirector','pais')

class ActorSerializer(serializers.ModelSerializer):
class Meta:
model = Actor
fields = ('nombreActor','pais')

class PeliculaSerializer(serializers.ModelSerializer):
actor = serializers.HyperlinkedRelatedField(many = True, read_only = True, view_name = 'actor-detail')
director = serializers.HyperlinkedRelatedField(many = True, read_only = True, view_name = 'director-detail')
critica = serializers.HyperlinkedRelatedField(many = True, read_only = True, view_name = 'critica-detail')
class Meta:
model = Pelicula
fields = ('nombre','anio','sinopsis','director','actor','critica')

class CriticaSerializer(serializers.ModelSerializer):
criticas = serializers.RelatedField(many = True)
class Meta:
model = Critica
fields = ('pelicula','critica','pelicula')

Como pueden observar, aquí se define la forma en que se serializará nuestro modelo al ser enviado como response en forma de json. Después de esto, es momento de crear las vistas, es decir, la forma en que mostrará la información. Entonces en el archivo views.py escribimos lo siguiente:

from django.shortcuts import render
from peliculas.models import *
from serializers import *
from rest_framework import viewsets, generics, filters

class DirectorViewSet(viewsets.ModelViewSet):
queryset = Director.objects.all()
serializer_class = DirectorSerializer

class PeliculaViewSet(viewsets.ModelViewSet):
queryset = Pelicula.objects.all()
serializer_class = PeliculaSerializer
filter_backends = (filters.DjangoFilterBackend,)
filter_fields = ('director',)

class ActorViewSet(viewsets.ModelViewSet):
queryset = Actor.objects.all()
serializer_class = ActorSerializer

class CriticaPeliculaViewSet(viewsets.ModelViewSet):
queryset = Critica.objects.all()
serializer_class = CriticaSerializer

Aquí especificamos la consulta que hará la vista así como que tipo de serialización usará. De igual forma podemos definir filtros como el de PeliculaViewSet que nos servirá para filtrar las películas por director.
Ahora, para poder realmente usarlas necesitamos configurar las URL's a las que harán solicitudes las apps y páginas web. Eso lo definimos en el archivo urls.py que se encuentra en la carpeta principal de proyecto, es decir, EIMBackendTutorial:

Debe quedarnos así:

from django.conf.urls import patterns, include, url
from rest_framework import routers
from peliculas.views import *
from albums.views import *
from django.contrib import admin
admin.autodiscover()

router = routers.SimpleRouter()
router.register(r'directores', DirectorViewSet)
router.register(r'actores', ActorViewSet)
router.register(r'peliculas', PeliculaViewSet)
router.register(r'criticas', CriticaPeliculaViewSet)
router.register(r'albums',AlbumViewSet)
router.register(r'tracks',TrackViewSet)

urlpatterns = patterns('',
    url(r'^admin/', include(admin.site.urls)),
    url(r'api/v1/', include(router.urls)),
    url(r'api-auth/', include('rest_framework.urls', namespace='rest_framework'))
)

Donde el router sirve para organizar las rutas a las que se dirigirán las requests así como los recursos de los que harán uso. Finalmente estás url's las podemos agrupar bajo un mismo prefijo el cual, en este caso es '/api/v1/'.

Ahora bien. Correremos el proyecto y nos en el explorador abriremos la siguiente dirección:

Seguro nos va a marcar un error, el cual es porque no hemos configurado las opciones de REST_FRAMEWORK en el settings.py. Dichas opciones se añaden agregando lo siguiente al final del settings.py:

REST_FRAMEWORK = { 
'DEFAULT_FILTER_BACKENDS': ('rest_framework.filters.DjangoFilterBackend',),
}

Nos mostrará un formulario y un área de visualización semejante al administrador de Django. Desde ahí podemos agregar información y visualizarla en formato JSON.  Esa misma url sirve para hacer post y get usando ajax de jquery como se muestra en el ejemplo que adjunto en la carpeta AjaxExample.
Sin embargo, si ustedes lo prueban se darán cuenta que la consola del explorador marca error de CSRF. Esto ocurre porque no hemos especificado la configuración de conexiones entrantes, es decir, tal cual está nuestro proyecto solo nosotros podemos hacer post, get, put y delete. 

Para dar acceso a cualquier otra conexión o desde cualquier otra aplicación hacemos uso de la libreria django-cors-headers la cual sirve para esto. Lo único que tenemos que hacer es instalarla, lo cual ya hicimos al momento de instalar lo que venia en requirements.txt. Ahora para configurar los accesos tenemos que agregar a las apps del settings.py la app 'corsheaders' y en la sección de middlewarer_classes añadimos la siguiente línea: 'corsheaders.middleware.CorsMiddleware'. No olviden la coma al final.

Por último, al final de nuestro archivo settings.py añadimos lo siguiente:
CORS_ORIGIN_ALLOW_ALL = True 

Ya con eso es suficiente para aceptar cualquier conexión. Si desean saber más acerca de como configurar las conexiones entrantes lean la documentación de Django-cors-headers.

Finalmente, si desean desactivar el explorador por defecto del rest-framework añadimos a las opciones de rest-framework lo siguiente:

'DEFAULT_RENDERER_CLASSES': (#con esta configuracion desactivo el visor por defecto de rest_framework en todo el sistema
'rest_framework.renderers.JSONRenderer',
),

Con eso el explorador por default no estará disponible.

Hasta aquí las dos partes del tutorial

Todo el código lo pueden descargar de aquí:
https://bitbucket.org/Lvcios/eimtutorial/src


PRIMERA PARTE
NOTA: Estos tutoriales estarán en video, aumentados y corregidos en la página del EIM proxiamente.