Curso Python. Volumen XIX: Framework Django. Parte X

Bienvenidos un día más al curso de Python, en este capítulo  vamos a enseñaros a utilizar los espacios de nombres y cómo podemos lanzar errores desde nuestra aplicación. Seguiremos con el ejemplo que empezamos, es decir, nuestra aplicación de encuestas que está siendo creada con el framework Django. Así que pongámonos manos a la obra.

Espacio de nombre en las plantillas

Cuando “Django” tiene que coger una plantilla siempre escoge la primera que coincida con el nombre que se busca, esto quiere decir que, si tenemos en otra aplicación una plantilla con el mismo nombre puede que no escoja la que queremos en ese momento. Por este motivo tenemos que hacer que “Django” sea capaz de distinguir qué plantilla queremos que use, y esto lo conseguimos creando una estructura de carpetas adecuadas.

En el capítulo anterior os dijimos de crear “polls/templates/polls/” para guardar aquí la plantilla de nuestra aplicación, de este modo es como utiliza los espacios de nombre Django. Como podéis comprobar es muy sencillo de aplicar.

Una vez dicho esto, nos dirigimos a esta carpeta y editaremos el fichero “index.xml” del siguiente modo:

polls/templates/polls/index.html 

{% if latest_question_list %}
<ul>
{% for question in latest_question_list %}
<li><a href="/polls/{{ question.id }}/">{{ question.texto_pregunta }}</a></li>
{% endfor %}
</ul>
{% else %}
<p>No polls are available.</p>
{% endif %}

Después de editarlo tendremos que actualizar nuestra vista “index” en “polls/views.py” para que utilice la plantilla que acabamos de crear:

polls/views.py 
from django.http import HttpResponse
from django.template import RequestContext, loader
from .models import Pregunta

def index(request):
latest_question_list = Pregunta.objects.order_by('-pub_date')[:5]
template = loader.get_template('polls/index.html')
context = RequestContext(request, {
'latest_question_list': latest_question_list,
})
return HttpResponse(template.render(context))

El código se encarga de cargar la plantilla que acabamos de crear: “polls/index.html” y le pasa un contexto. El contexto es un diccionario que mapea nombres de variable a objetos Python. Vamos a cargar la página en nuestro navegador abriendo la dirección “/polls/”, y ahora deberíamos ver una lista con las preguntas que teníamos almacenadas en nuestra base de datos.

Un atajo: render()

La acción de cargar una plantilla, cargar un contexto y devolver un objeto HttpResponse con el resultado de renderizar la plantilla, es muy común. Por esta razón “Django” nos provee de un atajo. A continuación, está la vista index() reescrita utilizando este atajo:

polls/views.py 

from django.shortcuts import render
from .models import Pregunta

def index(request):
latest_question_list = Pregunta.objects.order_by('-pub_date')[:5]
context = {'latest_question_list': latest_question_list}
return render(request, 'polls/index.html', context)

Una vez realizado este cambio en todas las visitas, ya no tendremos que importar “loader”, “RequestContext” y “HttpResponse” (es verdad que será necesario mantener HttpResponse si es que todavía tenemos métodos “stub” para detail, results y vote).

La función “render()” toma un objeto “request” como primer argumento, un nombre de platilla como segundo argumento y un diccionario como tercer argumento, este último es opcional. Esta función nos devolverá un objeto HttpResponse con la plantilla “renderizada” con el contexto dado.

Levantando un error 404

Ahora veamos la vista de detalle para una pregunta, es decir, la página que muestra el texto de la pregunta.

polls/views.py 

from django.http import Http404
from django.shortcuts import render
from .models import Pregunta

# ...

def detail(request, question_id):
try:
question = Pregunta.objects.get(pk=question_id)
except Pregunta.DoesNotExist:
raise Http404("La pregunta no existe")
return render(request, 'polls/detail.html', {'question': question})

Como podéis comprobar, hemos añadido en la vista la instrucción “raise”, esta instrucción lo que hace es lanzar una excepción en este caso “Http404” si la pregunta que deseamos ver no existe.

Un atajo: get_object_or_404()

Es muy normal encontrar el método “get()” controlado por un bloque “try…except”, para lanzar una excepción “Http404” en caso de que el objeto no exista en Python. Por eso el framework “Django” nos proporciona un método para hacernos más fácil su uso. A continuación, os mostramos cómo quedaría el fichero “poll/views.py”:

poll/views.py 
from django.shortcuts import get_object_or_404, render
from .models import Pregunta

# ...

def detail(request, question_id):
question = get_object_or_404(Pregunta, pk=question_id)
return render(request, 'polls/detail.html', {'question': question})

Es recomendable utilizar este tipo de funciones ya que nos permite mantener un nivel de dependencia bajo entre capas. Que es una de los objetivos que persigue “Django”, aunque es cierto que con el módulo “django.shortcuts” se genera cierta dependencia.

Usando el sistema de plantillas

Tenemos una variable de contexto en nuestra vista “detail()” que es “question” a continuación, os vamos a mostrar cómo la podríais utilizar en la plantilla “polls/detail.html”:

polls/templates/polls/detail.html 

<h1>{{ question.texto_pregunta }}</h1>
<ul>
{% for choice in question.opcion_set.all %}
<li>{{ choice.texto_opcion }}</li>
{% endfor %}
</ul>

La sintaxis que utilizamos en las plantillas para acceder a los atributos de las variables es con el punto “.”. Como podréis ver en el código anterior hemos utilizado “{{ question.texto_pregunta }}”, esto sirve para que Django nos busque el atributo “texto_pregunta” dentro del objeto “question”.

También podemos realizar una llamada a un método como podemos ver en el bucle “for”, que hemos llamado a la siguiente función: “question.opcion_set.all”. Esto lo interpreta como el código Python “question.opcion_set.all()”, que devuelve un iterable de objetos “Opcion” que podrá utilizar el bucle “for”.

Borrando URLs escritas explícitamente en plantillas

Recordemos que cuando escribimos el enlace a una encuesta en la plantilla “polls/index.html”, el enlace estaba parcialmente escrito “a mano”:

<li><a href="/polls/{{ question.id }}/">{{ question.texto_pregunta }}</a></li>

Esta solución estaba bien para aprender, pero es cierto que no es muy recomendable de usar debido a que si quisiéramos cambiar la URL, tendríamos que cambias todas las plantillas que tuvieran esta línea a mano. Pero si os acordáis definimos el argumento “name” en las llamadas a url() en el módulo “polls.urls”, por lo que podemos eliminar la dependencia de URLs fijas usando la etiqueta {% url %} dentro de las plantillas:

<li><a href="{% url 'detail' question.id %}">{{ question.texto_pregunta }}</a></li>

La forma en que esto funciona es buscando la definición de la URL especificada en el módulo “polls.urls”. Podemos ver dónde se define el nombre ‘detail’ de la URL aquí:

... 

# the 'name' value as called by the {% url %} template tag
url(r'^(?P<question_id>[0-9]+)/$', views.detail, name='detail'),

...

Si uno quisiera cambiar la URL de la vista de detalle de pregunta a algo distinto, tal vez algo como “polls/specifics/12/”, en lugar de hacerlo en la plantilla o plantillas, bastaría con cambiarlo en “polls/urls.py”:

... 

# added the word 'specifics'
url(r'^specifics/(?P<question_id>[0-9]+)/$', views.detail, name='detail'),

...

Espacio de nombres en URLs

En este tutorial sólo estamos creando una aplicación, polls. Pero normalmente se crea más de una aplicación dentro de un proyecto. Y se puede dar el caso de que existan dos vistas con el mismo nombre. Para poder diferenciar en que vista tenemos que resolver la URL tendremos que usar los espacios de nombres. De este modo Django sabrá en todo momento a qué vista pertenece la URL que está resolviendo.

Los espacios de nombres tendremos que añadirlos al “configurador de URLs” principal. Porque abrimos el archivo “mysite/urls.py” e incluimos los espacios de nombres:

mysite/urls.py 
from django.conf.urls import include, url
from django.contrib import admin

urlpatterns = [
url(r'^polls/', include('polls.urls', namespace="polls")),
url(r'^admin/', include(admin.site.urls)),
]

Después de realizar este cambio, nos dirigimos a “template polls/index.html” que debería estar del siguiente modo:

polls/templates/polls/index.html 

<li><a href="{% url 'detail' question.id %}">{{ question.texto_pregunta }}</a></li>

Y lo modificamos para que apunte a la vista de detalle con el espacio de nombres:

polls/templates/polls/index.html 

<li><a href="{% url 'polls:detail' question.id %}">{{ question. texto_pregunta }}</a></li>

Esto es todo por hoy. Os invitamos como siempre a que sigáis explorando este framework y probando. Y para todos los que se acaban de incorporar indicarles que tenemos un índice con todos los capítulos del curso, ya que nunca es tarde para empezar.

 



Via: www.redeszone.net
Curso Python. Volumen XIX: Framework Django. Parte X Curso Python. Volumen XIX: Framework Django. Parte X Reviewed by Lydecker Black on 13:05 Rating: 5