Primera aplicación dinámica en Django con PyCharm

En este articulo mostramos como desarrollar una primera aplicación web dinámica en Django mediante PyCharm. PyCharm es un IDE de programación que proporciona múltiples herramientas para facilitar el desarrollo de Python. Suponemos que ya hemos descargado e instalado Pycharm en nuestra máquina local.

1. Crear un nuevo proyecto Django en PyCharm.

Seguiremos los siguientes pasos:

  1. En el menú superior de PyCharm, accedemos a File —> New Project.
  2. En el menú que aparece en la barra lateral, seleccionamos Django.
  3. Definimos el directorio de destino del proyecto Django en el campo location. En nuestro caso, sustituimos untitled por MySite.
  4. Abrimos More settings y añadimos el nombre de la aplicación polls.
  5. Pulsamos el botón Create.

De este modo se ha creado un nuevo proyecto Django en Pycharm y una aplicación dentro de él. Podemos ver ambas carpetas en el panel del explorador de proyectos. Así mismo, se habrán creado en /user/PyCharmProjects/MySite/ con el siguiente contenido:

2. Configurar la base de datos

A continuación, configuramos la base de datos. Elegiremos la más sencilla: sqlite3. Para ello, editamos settings.py y buscamos DATABASES. Allí, le damos nombre a la base de datos. Elegimos en este caso MyDatabase.

Con ello habremos creado un nuevo archivo relacionado con la base de datos en el directorio MySite.

3. Lanzamiento del servidor Django

Una vez que la configuración está preparada, puede hacerse la primera prueba. En el menú superior ejecutamos Run -> Run ‘MySite’

Y accediendo al enlace sugerido encontramos la página de prueba lista, indicando que la configuración es correcta:

4. Creación de modelos

Los modelos se incluyen en el archivo models.py. Procedemos a editarlo y añadimos el siguiente código mediante copy/paste:

from django.db import models

# Create your models here.
import datetime
from django.utils import timezone

class Question(models.Model):
question_text = models.CharField(max_length=200)
pub_date = models.DateTimeField('date published')

def __str__(self):
return self.question_text

def was_published_recently(self):
now = timezone.now()
return now - datetime.timedelta(days=1) <= self.pub_date <= now

was_published_recently.admin_order_field = 'pub_date'
was_published_recently.boolean = True
was_published_recently.short_description = 'Published recently?'

class Choice(models.Model):
question = models.ForeignKey(Question, on_delete=models.DO_NOTHING,)
choice_text = models.CharField(max_length=200)
votes = models.IntegerField(default=0)

def __str__(self):
return self.choice_text

5. Creación de la base de datos

Para crear las tablas del modelo anteriormente creado abrimos la consola de manage.py (Tools -> Run manage.py Task ) y ejecutamos el comando makemigrations polls:

De este modo le hemos dicho a Django que se han creado dos nuevos modelos, Choice y Question, y se ha realizado la migración. Podemos ver que se ha creado un nuevo archivo en la carpeta migrations denominado 0001_initial.py:

De nuevo, en la consola de manage.py incluimos el comando

sqlmigrate polls 0001

Y finalmente el comando migrate crea las tablas en la base de datos:

6. Funciones administrativas

En primer lugar creamos un superusuario. Para ello empleamos el comando createsuperuser en la consola de manage.py. Nos pedirá un email y una password. Cuando concluyamos el proceso obtendremos la siguiente confirmación:

Superuser created successfully.

PyCharm habrá modificado entonces el archivo urls.py, donde encontraremos ahora las siguientes líneas:

urlpatterns = [
path('admin/', admin.site.urls),
]

De este modo la url http://127.0.0.1:8000/admin/login/?next=/admin/ ya está operativa, como podemos comprobar en el navegador:

Tras la autenticación, encontramos una pantalla donde aparecen Groups y Users, pero no Polls.

Para asociar la tabla asociada a la aplicación debemos añadir un par de líneas al archivo admin.py:

from .models import Question #this line added
admin.site.register(Question)#this line added

Recargando la página en el navegador, ahora si vemos la tabla Question en la sección Polls.

Para que aparezcan las opciones (Choices) de cada pegunta (Question), debe modificarse admin.py. El archivo debe ser el siguiente:

from django.contrib import admin
from .models import Choice, Question

class ChoiceInline(admin.TabularInline):
    model = Choice
    extra = 3

class QuestionAdmin(admin.ModelAdmin):
    fieldsets = [
            (None,               {'fields': ['question_text']}),
            ('Date information', {'fields': ['pub_date'], 'classes': ['collapse']}),
                ]
    inlines = [ChoiceInline]

admin.site.register(Question, QuestionAdmin)

Esta nueva configuración genera la siguiente vista del administrador:

7. Escribiendo las vistas

Las vistas se crean el el archivo polls/views.py. Una primera vista será un simple Hello world. Para ello abrimos el archivo y escribimos en él el siguiente código:

from django.http import HttpResponse 
def index(request):     
    return HttpResponse("Hello, world. You're at the polls index.")

Hemos definido la vista index. Ahora hay que asociarla a una url. Para ello creamos un archivo nuevo urls.py en la carpeta polls, donde importamos la vista recién creada:

from django.conf.urls import url
from . import views
urlpatterns = [
    url(r'^$', views.index, name='index'),
]

Una vez creada esta url, se añade al archivo mysite/urls.py

from django.conf.urls import include, url
from django.contrib import admin
urlpatterns = [
    url(r'^polls/', include('polls.urls')), #this line added
    url(r'^admin/', admin.site.urls),
]

Y podemos ver el resultado en el navegador en la dirección 127.0.0.1:8000/polls/:

Para crear nuevas vistas, añadimos el siguiente código a polls/views.py:

def detail(request, question_id):
    return HttpResponse("You're looking at question %s." % question_id)

def results(request, question_id):
    response = "You're looking at the results of question %s."
    return HttpResponse(response % question_id)

def vote(request, question_id):
    return HttpResponse("You're voting on question %s." % question_id)

donde hemos definidos tres nuevas vistas, detail, results y vote. Tal como hicimos para vista index, las nuevas urls deben añadirse a polls/urls.py:





url(r'^(?P<question_id>[0-9]+)/$', views.detail, name='detail'),
# ex: /polls/5/results/
url(r'^(?P<question_id>[0-9]+)/results/$', views.results, name='results'),
# ex: /polls/5/vote/
url(r'^(?P<question_id>[0-9]+)/vote/$', views.vote, name='vote'),

Y obtenemos el resultado en el navegador:

8. Creando templates

El resultado de las vistas hasta ahora era el más simple posible y no empleaba ningún tipo de etiqueta html o estilo. Para mejorar las vistas tendremos que llamar a los correspondientes archivos html en cada caso. Esto se realiza modificando el fichero polls/views.py, incluyendo el siguiente código:

from django.http import HttpResponse, HttpResponseRedirect
from django.shortcuts import get_object_or_404, render
from django.urls import reverse

from .models import Question, Choice


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


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


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


def vote(request, question_id):
    question = get_object_or_404(Question, pk=question_id)
    try:
        selected_choice = question.choice_set.get(pk=request.POST['choice'])
    except (KeyError, Choice.DoesNotExist):
        return render(request, 'polls/detail.html', {
            'question': question,
            'error_message': "You didn't select a choice.",
        })
    else:
        selected_choice.votes += 1
        selected_choice.save()
        return HttpResponseRedirect(reverse('polls:results', args=(question.id,)))

Necesitamos a continuación crear los archivos html que estamos invocando. Estos se crearán en la carpeta mysite/templates/polls. Dado que no existe, podemos crearla de antemano o dejar que PyCharm lo haga por nosotros al intentar crear el nuevo template polls/index.html. Una vez creado el archivo, añadimos el siguiente código:

{% load static %}
<link rel="stylesheet" type="text/css" href="{% static 'polls/style.css' %}" />
{% if latest_question_list %}
           <ul>
    {% for question in latest_question_list %}
           <li><a href="{% url 'detail' question.id %}">{{ question.question_text }}</a></li>
    {% endfor %}
       </ul>
{% else %}
           <p>No polls are available.</p>
{% endif %}

El resultado puede verse en la url http://127.0.0.1:8000/polls/

9. Añadir una hoja de estilo CSS

Para añadir una hoja de estilo CSS creamos un directorio static/polls/ dentro de la aplicación. Es decir en la ruta polls/static/polls/. En ese directorio creamos un archivo style.css con la hoja de estilos. Para crearlo en PyCharm podemos ir a File/New/Stylesheet. En el archivo ponemos el siguiente contenido:

li a {
color: green;
text-decoration:none;
}

Para que funcione tenemos que añadir la siguiente línea en settings.py:

STATICFILES_DIRS = (
    os.path.join(BASE_DIR, 'static'),
)

donde BASE_DIR ya se ha definido más arriba en el propio archivo. De este modo, obtenemos una nueva apariencia en el navegador:

10. Test

Para realizar los test necesitamos incluir el código correspondiente en el archivo tests.py de la aplicación. Dicho archivo ya se ha creado con Pycharm, pero de encuentra vacío. De este modo, leañadimos el siguiente código:

import datetime
from django.urls import reverse
from django.test import TestCase
from django.utils import timezone
from .models import Question
def create_question(question_text, days):
   time = timezone.now() + datetime.timedelta(days=days)
   return Question.objects.create(question_text=question_text, pub_date=time)

class QuestionViewTests(TestCase):
   def test_index_view_with_no_questions(self):
       """
       If no questions exist, an appropriate message should be displayed.
       """
       response = self.client.get(reverse('index'))
       self.assertEqual(response.status_code, 200)
       self.assertContains(response, "No polls are available.")
       self.asser

Para ejecutar el test podemos usar el botón derecho aplicado al archivo test.py. El resultado si todo es correcto debe ser el siguiente:

11. Resumen

Hemos creado una primera aplicación Django empleando PyCharm. Se ha empleado el tipo de base de datos más simple SQLLite, que aparece por defecto. Así mismo se han creado vistas simples que recogen información de la base de datos, la cual se maneja empleando el administrador que Django trae por defecto. Así mismo se ha adjuntado una hoja de estilos.

Este es el primer paso para crear aplicaciones más complejas y emplear bases de datos MySQL, como haremos a continuación.