Mostrando entradas con la etiqueta python. Mostrar todas las entradas
Mostrando entradas con la etiqueta python. Mostrar todas las entradas

sábado, 1 de noviembre de 2014

Probando Django 1.7 con Python 3

Django desde la versión 1.5 es compatible con Python 3, muchos programadores han estado probando y portando sus aplicaciones de Django a esta nueva versión por las ventajas que ofrece.

¡Usa la ultima versión estable!

La última versión estable es la 3.4.2, al momento de escribir este articulo, la versión de Ubuntu 14.04 viene con la 3.4.0, es la que usare para este tutorial.

Entorno Virtual con Python 3

$ pyvenv-3.4 --without-pip py3  # py3 es el nombre del virtualenv
 Activar el entorno vitual:
$ cd py3
$ source bin/activate
(py3) $ 
Verifica que el entorno virtual esta en Python 3:
(py3) $ python --version
 Python 3.4.0
Instalar pip:
(py3) $ curl https://raw.githubusercontent.com/pypa/pip/master/contrib/get-pip.py | python

Django

(py3) $ pip install django
Crear un proyecto:
(py3) $  django-admin startproject demo
(py3) $  cd demo
Crear la base de datos en Django 1.7
(py3) $ python manage.py migrate

Servidor de Desarrollo

Probamos nuestro servidor de desarrollo a ver si todo va bien hasta ahora
 (py3) $ python manage.py runserver
Performing system checks...

System check identified no issues (0 silenced).
November 01, 2014 - 03:00:12
Django version 1.7.1, using settings 'demo.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.
Probamos en la dirección http://127.0.0.1:8000

Creado una Aplicación

Vamos a crear una aplicación:
 (py3) $ python manage.py startapp main
Creamos el modelo de la Aplicación en main/models.py
from django.db import models

class Persona(models.Model):
    nombre = models.CharField(max_length=100)
    apellido = models.CharField(max_length=100)

    def __str__(self):
        return self.nombre
Como podrán ver se usa el método __str__ en vez de __unicode__, ya que es uno de los cambios en Python 3

Agregamos main en demo/settings.py en INSTALLED_APPS
INSTALLED_APPS = (
   'django.contrib.admin',
   'django.contrib.auth',
   'django.contrib.contenttypes',
   'django.contrib.sessions',
   'django.contrib.messages',
   'django.contrib.staticfiles',
   'main',
)
Ahora ejecutamos:
(py3) $ python manage.py makemigrations main
Mediante la ejecución de makemigrations, le decimos a Django que se han hecho algunos cambios en el modelo (en este caso, son nuevos) y que desea que los cambios se guarden como una migración.

Ahora, ejecute migrate de nuevo para crear las tablas del modelo en la base de datos
(py3) $ python manage.py migrate

Creando el usuario Administrador

Para crear un usuario que puede iniciar sesión en el sitio de administración. Ejecute el siguiente comando:
(py3) $ python manage.py createsuperuser
Como podrás ver, hasta aquí hemos creado una aplicación básica de Django usando Python 3, te recomiendo que revises la documentación para la creación de sitios web con Django.

¡Consideraciones Importantes!

  • Chequea siempre si los paquetes que vas a utilizar desde PyPi son compatibles con Python 3
  • En un proyecto Django, compruebe en los modelos, los métodos  __str __ (). Si los tiene, es un buen indicador de que es compatible con Python 3.
  • Utilice 2to3 para escanear el código de problemas de compatibilidad.
  • Revisa el sitio donde va correr en producción tu aplicación, en el caso de Linux, la mayoría de las distribuciones ya tienen Python 3 instalado, y es accesible a los usuarios finales. En general, la eliminación de Python 2 por defecto, ha sido gradual. Sin embargo, hay algunos módulos clave que pueden requerir el uso de Python 2 en lugar de Python 3
  • Ya existen cerca de 500 paquetes de Django compatibles con Python3, eso lo puedes revisar en la pagina de Django Packages.

Aunque la mayoría del código Python está escrito para Python 2.x, Python 3 es el presente y futuro de este lenguaje de programación.

Python 2.7.8 fue lanzado en Octubre de 2014. La rama 2.x no tendrá más lanzamientos importantes, aunque la versión 2.7 en su vida útil tendrá un período prolongado de correcciones de errores y huecos de seguridad.

Python 3.x continúa siendo desarrollado activamente. El lanzamiento más reciente de Python 3.4, fue el 6 de Octubre del 2014.

Recursos útiles

Los siguientes enlaces son recursos que pueden revisar a fin de tener mas información sobre Python 3 y como portar sus aplicaciones a esta versión del lenguaje.

Para concluir aclaro que este articulo es con fines didácticos y siempre depende de usted el buscar la mejor alternativa para su aplicación web con Django. Python 2 aún tiene soporte y lo va mantener por mucho tiempo, espero que con este artículo le ayude a crear su propia estrategia de desarrollo con Django.

domingo, 22 de junio de 2014

Registro de Usuarios para un sitio web con Django 1.6 usando Class Based Views y reCAPTCHA

En esta nueva entrada veremos como registrar usuarios en un sitio web creado con Django 1.6 y utilizando las vistas basadas en clases (Class Based Views), es importante recordar que desde la versión 1.5 Django introduce soporte para un modelo de usuario configurable, donde el modelo básico sigue presente, solo que ahora podemos especificar nuestro propio modelo y el sistema de autenticación de Django lo usa perfectamente.

Hay un cambio de paradigma total en este aspecto, si eres un programador de versiones anteriores a la 1.5, donde completabas el modelo del usuario con perfiles, esto ha quedado oficialmente desaprobado en la versión 1.6 en favor de modelos de usuarios personalizados. Dichos modelos deben ser configurados en la creación inicial del proyecto. les invito a ver la documentación para ampliar mas este tema.

También se aprovecha al  máximo el uso de las vistas basadas en clases (CBV), yo voy asumir que quienes están siguiendo este tutorial debe tener los conocimientos básicos del uso de Django.

También utilizaremos ReCaptcha que nos ayudara a prevenir el abuso automatizado del sitio web (por ejemplo, los comentarios no deseados o registros falsos) usando un CAPTCHA, garantizamos que sólo los seres humanos realizan estas acciones. Nos apoyaremos con una aplicación llamada django-recaptcha, para facilitarnos esta tarea.

La aplicación de registro le permitirá a un usuario ingresar sus datos y correo electrónico donde recibirá un enlace con una clave que activara su cuenta. Así de sencillo, quizás algunos se pregunten, ¿Por qué no utilizar django-registration? primero, esto lo hago con fines didácticos, segundo, si alguien quiere tener mas el control de su código esta es la mejor manera, de todas formas estoy abierto a sugerencias y mejoras. Bien, luego de esta breve introducción empecemos con el tutorial.

1.- Requisitos de Instalación: 

Para este ejemplo utilizare algunos programas para facilitar la realización del tutorial, en este caso utilizare django-bootstrap3 para instalar mas sencillo el framework de css bootstrap con filtros y tags de Django templates. Y por supuesto como dije previamente instalar django-recaptcha para el captcha en el formulario de registro. Es importante cumplir con los requisitos de recaptcha y generar sus claves para tu sitio web, también puedes crearlas para tu ambiente de desarrollo. ve la documentación de recaptcha. Para instalar estas aplicaciones solo tienes que instalarlas via pip.
pip install django-bootstrap3 django-recaptcha
Revisa la documentación de ambas aplicaciones si quieres obtener mas información.

2.- Creación del modelo:

Supongamos que hemos creado el proyecto de Django y dentro de el una aplicación llamada "registro", y basándonos en la nueva forma de crear modelos de usuario, creamos models.py
from django.db import models
from django.contrib.auth.models import AbstractUser

class UserRegister(AbstractUser):
    activation_key = models.CharField(max_length=30)
En este caso solo le hemos agregado a la clase abstracta de User un campo adicional, como he comentado brevemente, ustedes pueden crear sus propios modelos de usuario, de acuerdo a sus necesidades. En este caso, solo necesito un campo adicional de los que trae por defecto Django y es un campo para guardar la clave de registro. Luego se agrega el siguiente campo en el archivo settings.py:
AUTH_USER_MODEL = 'registro.UserRegister'
Revisamos que tenemos agregadas las aplicaciones que vamos a utilizar en INSTALLED_APPS como por ejemplo:
INSTALLED_APPS = (
    ...
    'bootstrap3',
    'registrar',
    'captcha',
)
Se crea el archivo admin.py, para poder seguir lo que esta registrando la base de datos por el administrador
from django.contrib import admin
from .models import UserRegister

admin.site.register(UserRegister)
Ahora creamos la base de datos con el comando python manage.py syncdb, hasta ahora solo hemos creado una aplicación con el sistema de autenticación por defecto de Django con un campo adicional. Ahora a realizar el sistema de registro de usuarios.

3.- Registro de Usuarios:

Primero vamos a crear el formulario en forms.py dentro de la aplicación. En principio se importa la clase creada en models.py, y como vamos a usar captcha para validar que no es un robot quien esta tratando de registrarse, importamos también el tipo de campo para el mismo. Creamos la clase heredada de forms y creamos los campos donde el usuario va registrar su clave y el campo captcha.
# -*- coding: UTF-8 -*-
from django import forms
from .models import UserRegister
from captcha.fields import ReCaptchaField

class RegistrationForm(forms.ModelForm):
    #Información de la clave
    password = forms.CharField( label='Clave', widget=forms.PasswordInput()
    )
    password_check = forms.CharField(label='Ingrese su clave nuevamente',
        widget=forms.PasswordInput()
    )
    captcha = ReCaptchaField(attrs={'theme' : 'clean'})
Agregamos la clase Meta para indicarle a la clase RegistrationForm con que modelo va trabajar y que campos va mostrar:
class Meta:
        model = UserRegister
        fields = ["username", "first_name", "last_name", "email",]
Ahora creamos los métodos para la clase RegistrationForm que haran las validaciones respectivas, asegurándose que las claves coincidan, que el usuario no exista o agreguen caracteres inválidos y evitar correos ya registrados, así nos debe quedar forms.py completo:
# -*- coding: UTF-8 -*-
from django import forms
from .models import UserRegister

import re
from captcha.fields import ReCaptchaField

class RegistrationForm(forms.ModelForm):
    #Información de la clave
    password = forms.CharField(
        label='Clave',
        widget=forms.PasswordInput()
    )
    password_check = forms.CharField(
        label='Ingrese su clave nuevamente',
        widget=forms.PasswordInput()
    )
    captcha = ReCaptchaField(attrs={'theme' : 'clean'})
   
    class Meta:
        model = UserRegister
        fields = ["username", "first_name", "last_name", "email",]

    def clean_password_check(self):
        """
        Revisar que ambas claves dadas coincidan
        """
        if 'password' in self.cleaned_data:
                password = self.cleaned_data['password']
                password_check = self.cleaned_data['password_check']
                if password == password_check:
                        return password_check
                raise forms.ValidationError('Claves no coinciden.')

    def clean_username(self):
        """
        Chequear que el usuario no exista y validar los caracteres ingresados
        """
        username = self.cleaned_data['username']
        if not re.search(r'^\w+$', username):
                raise forms.ValidationError('Usuario solo puede contener '
                                            'caracteres alfanumericos y underscore o piso.')
        try:
                UserRegister.objects.get(username=username)
        except UserRegister.DoesNotExist:
                return username
        raise forms.ValidationError('Nombre de usuario ya existe')

    def clean_email(self):
        """
        Validar que la direccion de correos dada sea unica en el proyecto
        """
        if UserRegister.objects.filter(email__iexact=self.cleaned_data['email']).count():
            raise forms.ValidationError(u'Esta dirección de correos esta en uso, por favor utilice otra')
        return self.cleaned_data['email']
Ahora en views.py se crea la clase para el registro de usuario, donde utilizaremos las librerías de Python random y string para crear la clave de 20 dígitos y grabarla en el campo activation_key que agregamos en el modelo y preparar el correo electrónico con el enlace a ser enviado al nuevo usuario para activar su cuenta, ya que hasta este momento esta registrado pero inactivo. Para esto hay que configurar a Django para que envié correos electrónicos, solo agrega estas lineas en settings.py:
#Aqui va la configuracion del servidor de correo (en este caso GMAIL)
EMAIL_HOST = 'smtp.gmail.com'
EMAIL_PORT = 587
EMAIL_HOST_USER = 'usuario@gmail.com'
EMAIL_HOST_PASSWORD = 'suclave'
EMAIL_USE_TLS = True
Así queda views.py
# -*- coding: UTF-8 -*-
from django.views.generic import CreateView
from django.core.mail import EmailMultiAlternatives
from django.http import HttpResponseRedirect
import random, string
from .models import UserRegister
from .forms import RegistrationForm
class UserCreateView(CreateView):
    model = UserRegister
    form_class = RegistrationForm
    template_name = 'register/register.html'
   
    def form_valid(self, form):
        form.instance.is_active = False
        form.instance.activation_key = ''.join(random.choice(string.ascii_uppercase + string.digits)
                                               for n in range(20))
        usuario = form.cleaned_data.get('email')
        html_content = 'Por favor visite http://midominio.com/activar/%s/ para activar su cuenta' \
                       %(form.instance.activation_key)
        msg = EmailMultiAlternatives('Código de Activación',html_content,\
                                     'registration@midiminio.com',[usuario])
        msg.attach_alternative(html_content,'text/html') # Definimos el contenido como HTML
        msg.send() # Enviamos el correo
        return super(UserCreateView, self).form_valid(form)
Ahora crea urls.py, pero antes agrega la linea en urls.py del proyecto para incluir las urls de la aplicación:
#urls.py en el Proyecto
from django.conf.urls import patterns, include, url

from django.contrib import admin
admin.autodiscover()

urlpatterns = patterns('',
    url(r'^register/', include('register.urls')),  # Agrega esta linea

    url(r'^admin/', include(admin.site.urls)),
)
 Crea el archivo urls.py dentro de tu aplicación:
from django.conf.urls import patterns, include, url
from .views import *

urlpatterns = patterns('.views',
                       url(r'^$', UserCreateView.as_view(), name='register'),
)
Ahora configura los templates dentro de settings.py
TEMPLATE_DIRS = (
    os.path.join(BASE_DIR, "templates"),
)
Crea la carpeta templates donde esta manage.py (Esto por supuesto depende de la configuración). Este es un ejemplo como quedaría el árbol del proyecto:

Crea el template base y lo llamas base.html
{% load bootstrap3 %}
<!DOCTYPE html>

<html>
<head>
    {# Load CSS and JavaScript #}
    {% bootstrap_css %}
    {% bootstrap_javascript %}
    <title>{% block title %}Ejemplo{% endblock %}</title>
</head>

<body>

<div class="container">
    {% block body_block %}This is body_block's default content.{% endblock %}
</div>

</body>
</html>
Este template carga primeramente bootstrap3 gracias a la aplicación que cargamos al principio django-bootstrap3. Ahora crea el formulario, en este caso podemos crear una carpeta para ordenar los templeates de acuerdo a la aplicación que pertenecen:
{% extends 'base.html' %}
{% load bootstrap3 %}

{% block title %}Formulario de Registro{% endblock %}

{# Display django.contrib.messages as Bootstrap alerts #}
    {% bootstrap_messages %}

{# Display a form #}
{% block body_block %}
<form action="" method="post" class="form">
    {% csrf_token %}
    {% bootstrap_form form %}
    {% buttons %}
        <button type="submit" class="btn btn-primary">
            {% bootstrap_icon "star" %} Submit
        </button>
    {% endbuttons %}
</form>
{% endblock %}
Arrancamos el servidor y colocamos la dirección http://127.0.0.1:8000/register/ en el navegador.


Registramos el primer usuario él cual enviara el correo electrónico y al revisar por admin y vemos que el usuario existe, solo que esta inactivo. El cuerpo del correo sera:
Por favor visite http://midominio/activar/MNP54P4WB50W4N9NJIXG/ para activar su cuenta
Para activarlo, crea una clase en views.py que recibirá por la url el código de activación enviado al correo electrónico del usuario.
class ActivteUserView(View):
   
    def dispatch(self, *args, **kwargs):
        self.codigo = self.kwargs['codigo']
        return super(ActivteUserView, self).dispatch(*args, **kwargs)
       
    def get(self, request, *args, **kwargs):
        try:
            self.usuario = UserRegister.objects.get(activation_key=self.codigo)
            if self.usuario.is_active == False:
                self.usuario.is_active = True
                self.usuario.save()
                return HttpResponseRedirect("/register/activo_exito/")
            else:
                return HttpResponseRedirect("/register/activo/")
        except UserRegister.DoesNotExist:
            return HttpResponseRedirect('/register/error_activacion')
Como se ve en el codigo tenemos unas redirecciones en cada caso, si tuvo exito, si ya esta registrado o simplemente un codigo errado, para ellos creamos las vistas necesarias.
class ErrorActiveView(TemplateView):
    template_name = 'register/error_activacion.html'
   
class UserActiveErrorView(TemplateView):
    template_name = 'register/usuario_ya_activo.html'

class UserActiveView(TemplateView):
    template_name = 'register/usuario_activo.html'
Hay que importar las nuevas clases utilizadas: TemplateView y View
from django.views.generic import CreateView, TemplateView, View
Así queda views.py completo:
# -*- coding: UTF-8 -*-
from django.views.generic import CreateView, TemplateView, View
from django.core.mail import EmailMultiAlternatives
from django.http import HttpResponseRedirect
import random, string

from .models import UserRegister
from .forms import RegistrationForm

class ErrorActiveView(TemplateView):
    template_name = 'register/error_activacion.html'
   
class UserActiveErrorView(TemplateView):
    template_name = 'register/usuario_ya_activo.html'

class UserActiveView(TemplateView):
    template_name = 'register/usuario_activo.html'

class UserCreateView(CreateView):
    model = UserRegister
    form_class = RegistrationForm
    template_name = 'register/register.html'
   
    def form_valid(self, form):
        form.instance.is_active = False
        form.instance.activation_key = ''.join(random.choice(string.ascii_uppercase + string.digits)
                                               for n in range(20))
        usuario = form.cleaned_data.get('email')
        html_content = 'Por favor visite http://midominio.com/activar/%s/ para activar su cuenta' \
                       %(form.instance.activation_key)
        msg = EmailMultiAlternatives('Código de Activación',html_content,\
                                     'registration@
midominio.com',[usuario])
        msg.attach_alternative(html_content,'text/html') # Definimos el contenido como HTML
        msg.send() # Enviamos el correo
        return super(UserCreateView, self).form_valid(form)
   
class ActivteUserView(View):
   
    def dispatch(self, *args, **kwargs):
        self.codigo = self.kwargs['codigo']
        return super(ActivteUserView, self).dispatch(*args, **kwargs)
       
    def get(self, request, *args, **kwargs):
        try:
            self.usuario = UserRegister.objects.get(activation_key=self.codigo)
            if self.usuario.is_active == False:
                self.usuario.is_active = True
                self.usuario.save()
                return HttpResponseRedirect("/register/activo_exito/")
            else:
                return HttpResponseRedirect("/register/activo/")
        except UserRegister.DoesNotExist:
            return HttpResponseRedirect('/register/error_activacion')
Agregamos las urls que faltan en urls.py:
from django.conf.urls import patterns, include, url
from .views import *

urlpatterns = patterns('.views',
                       url(r'^$', UserCreateView.as_view(), name='register'),
                       url(r'^activar/(?P<codigo>.+)/$', ActivteUserView.as_view(), name='activar_user'),
                       url(r'^activo/$', UserActiveErrorView.as_view(), name='activo'),
                       url(r'^activo_exito/$', UserActiveView.as_view(), name='exito_activo'),
                       url(r'^error_activacion/$', ErrorActiveView.as_view(), name='error_activacion'),
)
Se realizan los templates html faltantes:
error_activacion.html:
{% extends 'base.html' %}
{% load bootstrap3 %}

{% block title %}Error de Activacion{% endblock %}

{# Display a form #}
{% block body_block %}
    <div class="container">
        <h1 class="text-muted">Error en Activacion</h1>
    </div>

{% endblock %}
usuario_activo.html
{% extends 'base.html' %}
{% load bootstrap3 %}

{% block title %}Usuario Activo{% endblock %}

{# Display a form #}
{% block body_block %}
    <div class="container">
        <h1 class="text-muted">Usuario Activo</h1>
    </div>

{% endblock %}
usuario_ya_activo.html:
{% extends 'base.html' %}
{% load bootstrap3 %}

{% block title %}Error de Activacion{% endblock %}

{# Display a form #}
{% block body_block %}
    <div class="container">
        <h1 class="text-muted">Error, Usuario ya activo</h1>
    </div>

{% endblock %}
Revisamos nuevamente por admin y veremos que el usuario aparece tildado activo y ya puedes controlar el sitio solo para usuarios registrados. Espero que sea de utilidad y no duden en dejar sus comentarios. Hasta la próxima.

miércoles, 9 de octubre de 2013

Django en Producción con Centos, PostgreSQL, Virtualenv, Gunicorn, Nginx y Supervisor

En este articulo vamos llevar a un entorno de Producción nuestra aplicación que creamos con Django, para ello vamos a utilizar varias herramientas:
Nos basaremos en el sistema operativo Centos 6.4 que es el clon libre del Red Hat Enterprise Server, un sistema operativo Linux hecho para servidores. en el caso de otras distribuciones de Linux, solo busca como instalar los paquetes y donde están ubicados sus archivos de configuración.

Puedes hacer esto en un servidor local, o puedes utilizar cualquiera de los proveedores que dan servicio de VPS.

Voy a asumir que usted conoce o sabe como configurar su servidor para apuntar un dominio a la dirección IP del servidor.

1.- Crear un usuario donde va estar nuestro proyecto y darle permisos de Administrador


como usuario root, ejecutamos:
[root@localhost ~]#  useradd django
luego editamos el archivo /etc/sudoers, con tu editor de preferencia
[root@localhost ~]# vim /etc/sudoers
allí agrega debajo de la linea donde esta root:
## Allow root to run any commands anywhere
root    ALL=(ALL)       ALL
django        ALL=(ALL)       ALL

2.- Instalar PostgreSQL


Yo particularmente recomiendo que cuando este en el proceso de instalación de Centos, escoge la opción de Servidor de Base de datos, para tener ya PostgreSQL instalado, en caso contrario, instalarlo con el siguiente comando:
[root@localhost ~]#  yum install postgresql postgresql-server postgresql-contrib
Ahora iniciamos el servidor PostgreSQL
 [root@localhost ~]# service postgresql initdb
Arrancamos el servicio:
 [root@localhost ~]# service postgresql start
Y lo configuramos para que arranque cada vez que iniciemos el servidor:
 [root@localhost ~]# chkconfig postgresql on
Luego configuramos los archivos pg_hba.conf y postgres.conf para poder conectarnos al PostgreSQL, por favor revise la documentación para ver las opciones de configuración para su servidor. Editamos postgres.conf
[root@localhost ~]# vi /var/lib/pgsql/data/postgresql.conf
Descomentar las siguientes lineas y agregamos * en la variable listen_addresses si queremos administrar nuestro PostgreSQL desde cualquier equipo:
listen_addresses = '*'
port = 5432
Ahora editamos pg_hba.conf:
[root@localhost ~]# vi /var/lib/pgsql/data/pg_hba.conf
Y cambiamos la siguiente linea por esto:
 # TYPE  DATABASE    USER        CIDR-ADDRESS          METHOD
# "local" is for Unix domain socket connections only
local   all         all                               trust
Ahora reiniciamos nuestro servicio:
[root@localhost ~]# service postgresql restart
Le asignamos una clave al usuario que viene por defecto llamado postgres en la Base de Datos
[root@localhost ~]# su postgres
bash-4.1$
bash-4.1$ psql
could not change directory to "/root"
psql (8.4.13)
Type "help" for help.
postgres=# ALTER ROLE postgres WITH PASSWORD 'abc123';
postgres=# \q
bash-4.1$
En este caso se le asigno la clave abc123, coloque la que mas le conviene.

Y esta nuestro servidor funcionando, ahora creamos nuestro usuario y base de datos para nuestra aplicación:
bash-4.1$ createuser django -P
could not change directory to "/root"
Enter password for new role:
Enter it again:
Shall the new role be a superuser? (y/n) n
Shall the new role be allowed to create databases? (y/n) n
Shall the new role be allowed to create more new roles? (y/n) n
bash-4.1$ 
Ya tenemos creado el usuario django en PostgreSQL, ese es el usuario que colocaremos en el archivo settings.py de Django, ahora creamos la base de datos de nuestra aplicación:
bash-4.1$ psql
could not change directory to "/root"
psql (8.4.13)
Type "help" for help.
postgres=# CREATE DATABASE mibasedatos OWNER django;
GRANT
postgres=# \q
bash-4.1$ exit

3.- Instalar el repositorio EPEL (Extra Packages for Enterprise Linux):

[root@localhost ~]# wget http://ftp.riken.jp/Linux/fedora/epel/RPM-GPG-KEY-EPEL-6
[root@localhost ~]# rpm --import RPM-GPG-KEY-EPEL-6
[root@localhost ~]# rm -f  RPM-GPG-KEY-EPEL-6
Instalamos en este caso para Centos de 64:
[root@localhost ~]# wget http://ftp.riken.jp/Linux/fedora/epel/6/x86_64/epel-release-6-8.noarch.rpm
[root@localhost ~]# rpm -ivh epel-release-6-8.noarch.rpm
[root@localhost ~]# yum update

4.- Instalamos Nginx

[root@localhost ~]# yum install nginx
Arrancamos el servicio y lo configuramos para que arranque cada vez que inicie la maquina:
[root@localhost ~]# service nginx start
[root@localhost ~]# chkconfig nginx on
Nota: debemos inhabilitar el firewall que viene por defecto o configurar para acepte peticiones, en nuestro caso lo vamos a inhabilitar:
[root@localhost ~]# service iptables stop
Probamos nuestro servidor Web en nuestro navegador: http://localhost

5.- Instalar Python y librerías necesarias


Instalamos Python y las librerías y componentes necesarios para que nuestra aplicación funcione correctamente con PostgreSQL
[root@localhost ~]# yum install python python-devel python-setuptools python-pip libxml2-devel
Ademas vamos a instalar gcc, el compilador de C y postgresql-devel. que nos lo exige el psycopg2 para conectarnos desde Django a PostgreSQL
[root@localhost ~]# yum install gcc postgresql-devel

6.- Instalación de Virtualenv 


Para instalar virtualenv, utilizamos pip, ya aquí podemos ingresar con nuestro usuario que creamos al principio:

[django@localhost ~]$ sudo pip install virtualenv
Al terminar de instalar, procedemos a crear nuestro ambiente para la aplicación que vamos colocar en producción:
[django@localhost ~]$ virtualenv ~/env
Para activar ejecutamos:
[django@localhost ~]$ source ~/env/bin/activate
Y miren como nos cambia el prompt
(env)[django@localhost ~]$ 
Todo lo que instalemos aquí vía pip, solo estará en este ambiente, esto es muy útil cuando vamos a tener varias aplicaciones con diferentes versiones de Django

7.- Instalamos Django, psycopg2 y nuestra aplicación


Dentro de nuestro ambiente virtual, este pendiente que tengamos en el prompt los paréntesis con nuestro ambiente "(env)[django@localhost ~]$", instalamos lo que requerimos para nuestra aplicación, primero por supuesto Django:
 (env)[django@localhost ~]$ pip install django
La librería para conectarnos a PostgreSQL:
(env)[django@localhost ~]$ pip install psycopg2
La aplicación la copiamos al directorio que queramos, puede ser en /opt/webapps, o donde ustedes lo consideren:
(env)[django@localhost ~]$ sudo mkdir -p /opt/webapps
[sudo] password for django:
Lo mas importante es que el directorio tenga permiso de lectura:
drwxr-xr-x. 4 root root 4096 oct  9 19:31 /opt
Cambiamos el usuario de la carpeta webapps:
(env)[django@localhost ~]$cd /opt
(env)[django@localhost opt]$ sudo chown django:nginx webapps
[sudo] password for django:
 Solo para probar creamos una aplicación en Django:
 (env)[django@localhost opt]$ cd webapps/
(env)[django@localhost webapps]$ django-admin.py startproject demo
(env)[django@localhost webapps]$ cd demo
(env)[django@localhost demo]$ python manage.py runserver
Validating models...
0 errors found
October 09, 2013 - 19:12:55
Django version 1.5.4, using settings 'demo.settings'
Development server is running at http://127.0.0.1:8000/
Quit the server with CONTROL-C.
Ya podemos ver que nuestro servidor de desarrollo funciona en nuestro navegador con http://127.0.0.1:8000

Nos queda configurar Django con la Base de datos y podemos empezar a crear las tablas de nuestra aplicación:
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql_psycopg2',
        'NAME': 'mibasedatos',                    
        'USER': 'django',
        'PASSWORD': 'abc123',
        'HOST': 'localhost',                
        'PORT': '',                
    }
}
Solo queda que montes tu aplicación y crear las tablas de tu base de datos en el servidor, ahora a configurar Gunicorn y Nginx:

8.- Instalando y configurando Gunicorn


Gunicorn es también conocido como Green Unicorn (Unicornio Verde), es un servidor WSGI HTTP para Python. Es un pre-fork del proyecto Unicorn de Ruby. Gunicorn es compatible con varios frameworks, soporta WSGI, Django y Paster de forma nativa; consume pocos recursos en ejecución y es bastante rápido. Aquí solo voy a tratar lo básico, cualquier configuración adicional, por favor busque la documentación. Para instalarlo:
(env)[django@localhost opt]$ pip install gunicorn
Probemos nuestra pequeña aplicación con Gunicorn:
(env)[django@localhost demo]$ gunicorn -w3 demo.wsgi:application --bind 127.0.0.1:8000
2013-10-09 20:14:49 [8571] [INFO] Starting gunicorn 18.0
2013-10-09 20:14:49 [8571] [INFO] Listening at: http://127.0.0.1:8000 (8571)
2013-10-09 20:14:49 [8571] [INFO] Using worker: sync
2013-10-09 20:14:49 [8576] [INFO] Booting worker with pid: 8576
2013-10-09 20:14:49 [8577] [INFO] Booting worker with pid: 8577
2013-10-09 20:14:49 [8578] [INFO] Booting worker with pid: 8578
Ahora podemos probar en nuestro navegador  http://127.0.0.1:8000 y allí tenemos nuestra aplicación corriendo en un servidor WSGI HTTP

El comando gunicorn ofrece una extensa lista de opciones para configurar su comportamiento, pero las que he utilizado en esta oportunidad son:
-w INT: número de procesos workers que se arrancarán para servir las peticiones.Este dependerá en medida de la carga de trabajo que tenga la aplicación, también depende del hardware con que se cuente, de acuerdo a la siguiente formula: 2*CPU +1, Para las maquinas que tienen un solo procesador escriba 3.
demo.wsgi:application: la ubicación del archivo wsgi.py y escribimos después de los dos puntos application
--bind ADDRESS: es posible especificar tanto HOST:PUERTO para decirle a gunicorn por donde va recibir peticiones

Bien, hagamos un script para que levante el entorno virtual y ejecute nuestra aplicación con Gunicorn. lo creamos en nuestro home
(env)[django@localhost opt]$ cd
(env)[django@localhost opt]$ vi gunicorn_start.sh
y escribimos en nuestro archivo:
#!/bin/sh
NAME="demo"
DJANGODIR="/opt/webapps/demo"
NUM_WORKERS=3
echo "Arrancando Demo"
cd $DJANGODIR
source ~/env/bin/activate
exec gunicorn -w $NUM_WORKERS $NAME.wsgi:application --bind 127.0.0.1:8000
Salimos del ambiente virtual y ejecutamos para probarlo:
(env)[django@localhost ~]$ deactivate
[django@localhost ~]$ chmod +x gunicorn_start.sh
[django@localhost ~]$ ./gunicorn_start.sh
Arrancando Demo
2013-10-09 20:41:26 [8686] [INFO] Starting gunicorn 18.0
2013-10-09 20:41:26 [8686] [INFO] Listening at: http://127.0.0.1:8000 (8686)
2013-10-09 20:41:26 [8686] [INFO] Using worker: sync
2013-10-09 20:41:26 [8695] [INFO] Booting worker with pid: 8695
2013-10-09 20:41:26 [8696] [INFO] Booting worker with pid: 8696
2013-10-09 20:41:26 [8697] [INFO] Booting worker with pid: 8697
Como podemos ver nos queda nuestro terminal con la aplicación y no nos deja hacer mas nada y si lo cerramos, se cae la aplicación, esto lo vamos a resolver con Supervisor

9.- Instalando y Configurando Supervisor


Supervisor es un sistema cliente servidor que permite a los usuarios monitorear y controlar una serie de procesos en los sistemas operativos tipo UNIX.
Comparte algunos de los mismos objetivos de los programas como launchd , daemontools y runit . A diferencia de algunos de estos programas, no está diseñada para ejecutarse como un sustituto de init. En cambio, está destinado a ser utilizado para el control de procesos relacionados con un proyecto o un cliente, y está destinado a iniciar como cualquier otro programa en el arranque.
le damos Ctrl-C, para salir de Gunicorn y liberar la terminal, instalamos ahora Supervisor con yum:
[django@localhost ~]$ sudo yum install supervisor
Una vez instalado configuramos supervisor para nuestra aplicación en /etc/supervisord.conf. Hay que hacerlo como root:
[django@localhost ~]$ su -
Contraseña:
[root@localhost ~]# vi /etc/supervisord.conf
Agregamos lo siguiente al final del archivo:
[program:demo]
command=/home/django/gunicorn_start.sh
user=django
autostart=true
stdout_logfile=/opt/webapps/demo/logs/gunicorn_supervisor.log
redirect_stderr=true
Creamos la carpeta y archivo para los logs:
[root@localhost ~]# exit
[django@localhost ~]$ mkdir -p /opt/webapps/demo/logs
[django@localhost ~]$ touch /opt/webapps/demo/logs/gunicorn_supervisor.log
Arrancamos Supervisor y lo configuramos para que arranque siempre
[django@localhost ~]$ sudo service supervisord start
[django@localhost ~]$ sudo chkconfig supervisord on
Reiniciamos el servicio propiamente de Supervisor:
[django@localhost ~]$sudo supervisorctl reload
Restarted supervisord
Y ahora veremos nuestra aplicación corriendo:
[django@localhost ~]$ sudo supervisorctl status demo
[sudo] password for django:
demo    RUNNING    pid 8883, uptime 0:11:29
Para detenerla:
[django@localhost ~]$ sudo supervisorctl stop demo
Para reiniciarla:
[django@localhost ~]$ sudo supervisorctl restart demo
Listo ya tenemos nuestra aplicación lista para que arranque al iniciar el servidor

10.- Configuración de Nginx


Buscamos el archivo de configuración de nginx en /etc/nginx/conf.d llamado default.conf y lo cambiamos totalmente por esto:
server {
    listen 80;
    server_name ejemplo.com;
    access_log  /var/log/nginx/server.log;
    root /opt/webapps/demo;
    location /static/ {
    autoindex on;
    alias  /opt/webapps/demo/static/;
    }
    location /media/ {
    autoindex on;
    alias  /opt/webapps/demo/media/;
    }
    location / {
        proxy_pass http://127.0.0.1:8000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
  }
Lo importante, tu carpeta static y media, es importante colocar la ruta exacta hacia esos archivos, de lo contrario, no te permitirá ver los estilos de tu aplicación. Otra cosa importante es la dirección por donde esta sirviendo tu aplicación el Gunicorn.

Reiniciamos nuestro servicio de Nginx y a probar nuestra aplicación
[django@localhost ~]$ sudo service nginx start
Listo, espero sus comentarios y sugerencias, hasta la próxima.



martes, 17 de septiembre de 2013

Chequear disponibilidad de Campo Clave en Django 1.5

Hoy vamos a hacer algo para validar un campo en un  formulario, cuando le quitamos el foco al campo, este revisara en la base de datos, si ya existe, y no al final al hacer el submit. Esto es útil, para verificar si esta tomado el nombre de usuario, en caso de registro de usuarios, así como saber si el numero de identificación o cédula ya existe, entre otros.

Empecemos:

primero creamos nuestra url en urls.py
url(regex=r'^check_cedula/(?P<cedula>\d+)/$',
view=CedulaCheck.as_view(),
name='check_cedula'
),
Ahora nos vamos a nuestra vista views.py:
class CedulaCheck(TemplateView): 
def dispatch(self, *args, **kwargs):
self.cedula = self.kwargs['cedula']
return super(CedulaCheck, self).dispatch(*args, **kwargs) 
def get(self, request, *args, **kwargs):
if Persona.objects.filter(cedula__iexact=self.cedula):
return HttpResponse(False)
else:
return HttpResponse(True)
ya con esto podemos probar nuestra url con un numero de cédula y nos devolverá si existe o no
http://localhost:8000/check_cedula/12345678/
Ahora nos vamos a poner en acción nuestra API  recién creada con un formulario, primero creamos nuestra clase en views.py:
class PersonaCreateView(CreateView):
model = Persona
template_name = 'home/add_persona.html'
En nuestro html, nos vamos al campo que vamos a validar, es de notar que hice mi formulario a mano, no usando la plantilla de Django para crear los campos:
<div class="control-group">
<label for="cedula" class="control-label">
Cedula:
</label>
<div class="controls">
<input name="cedula" type="text" value="" id="cedula">
<span class="help-inline" id="idval">  Escriba su Cedula de Identidad</span>
</div>
</div>
y le agregamos el siguiente código jquery
<script>
function CheckId() {
$.get('/check_cedula/'+escape($('#cedula').val())+'/',
function(data){
if(data == "True"){
$('#idval').html("<i class='icon-ok'></i> Cedula disponible");
} else {
$('#idval').html("<i class='icon-remove'></i> Cedula existe");
}
});
}
function onChange(){
$("#cedula").change( function() {CheckId()});
}
$(document).ready(onChange);
</script> 
 Y listo, cuando coloquemos una cédula que ya existe, al dejar el foco del campo, nos dará una advertencia que ya existe y así no tenemos que escribir todos los campos y darle submit para que nos de el error.

Hasta la proxima

domingo, 15 de septiembre de 2013

Fotos con webcam usando Django 1.5 y JpegCam

Hola nuevamente

Tenia un poco abandonado mi blog, debido a razones de trabajo, hoy vengo nuevamente a hablarles de Django, el framework de Python, esta vez, vamos a ver cosas interesantes como el tomar una instantánea o fotografía desde nuestra webcam utilizando una librería de Flash y Javascript.

Jpegcam es un interesante componente de Flash/JavaScript para capturar y guardar imágenes desde la webcam del usuario. Se puede utilizar por ejemplo para permitir a los usuarios hacer una imagen de sí mismos como avatares, o para completar su perfil.

Es un widget que a través de flash muestra una vista en vivo de la webcam y botones con funciones Javascript asociadas  que puede capturar y enviar una imagen a un servidor en modo POST.

¿Qué debemos hacer?
  1. Descargar la ultima versión de Jpegcam y agrégalo a tu carpeta de statics en tu proyecto Django, esta consta de archivos que son: shutter.mp3, webcam.js, webcam.swf
  2. Editamos el archivo webcam.js y buscamos para configurar los path de swf_url y shutter_url. En mi caso:
              swf_url: '/static/jpegcam/webcam.swf'
             shutter_url: '/static/jpegcam/shutter.mp3'
          Y mas abajo en el archivo, aproximadamente en la linea 166, agregar el path:
             this.shutter_url = url ? url : '/static/jpegcam/shutter.mp3';
Ahora nos vamos a Django, quiero manifestar que esta guía esta hecha para personas que han programado con Django y tienen conocimientos básicos del framework.

Primero creamos nuestro modelo de datos, donde vamos a almacenar los datos de la persona a registrar y su fotografía.
models.py
from django.db import models
import os
def get_image_name(instance, filename):
f, ext = os.path.splitext(filename)
archivo = '%s%s' % (instance.cedula, ext)
return os.path.join('webcamimages', archivo) 
class Persona(models.Model):
"""docstring for Personal"""
cedula = models.CharField(max_length=10)
nombres = models.CharField(max_length=60)
apellidos = models.CharField(max_length=60)
foto = models.ImageField(upload_to=get_image_name, blank=True, null=True) 
def __unicode__(self):
return self.cedula 
@models.permalink
def get_absolute_url(self):
return ('persona', [str(self.id)]) 
def _get_full_name(self):
"Retorna los nombres completos de Persona"
return '%s %s' % (self.nombres, self.apellidos) 
full_name = property(_get_full_name)
Les explico un poco el modelo, primero tenemos una función llamada get_image_name, esta función nos sirve para llamar los archivos que subamos por la opción file del formulario, siempre tendrán el nombre del campo cedula con su extensión, si mi cédula es 12345 y estoy cargando el archivo foto.jpg, esta función lo renombrada y lo guardara como 12345.jpg en la carpeta webcamimages dentro de media.
foto = models.ImageField(upload_to=get_image_name, blank=True, null=True) 
Ahora nos vamos a nuestro url.py, donde tenemos estas dos entradas:
url(regex=r'^persona/$',
     view= PersonaCreateView.as_view(),
         name='add_persona'
    ),
url(regex=r'^save_image/(?P<cedula>\d+)/$',
     view=SaveImage.as_view(),
      name='salvar_imagen'
),

La que nos interesa en este momento es la de save_image, ya que es la url que usaremos para tomar la fotografía, la otra es para que el formulario guarde la información dada.

Ahora crearemos nuestro views.py
from django.views.generic import TemplateView, CreateView, DetailView, ListView
from django.views.decorators.csrf import csrf_exempt
from django.http import HttpResponse
from django.conf import settings
from .models import Persona

class SaveImage(TemplateView): 
@csrf_exempt
def dispatch(self, *args, **kwargs):
self.filename = self.kwargs['cedula']+'.jpg'
return super(SaveImage, self).dispatch(*args, **kwargs) 
def post(self, request, *args, **kwargs): # save it somewhere
f = open(settings.MEDIA_ROOT + '/webcamimages/'+ self.filename, 'wb')
f.write(request.body)
f.close()
# return the URL
return HttpResponse("/media/webcamimages/" + self.filename) 
def get(self, request, *args, **kwargs):
return HttpResponse('No esta pasando el POST')

class PersonaCreateView(CreateView):
model = Persona
template_name = 'home/add_persona.html' 
def form_valid(self, form):
form.instance.foto = 'webcamimages/'+ form.instance.cedula + ".jpg"
return super(PersonaCreateView, self).form_valid(form)

Como ven, tenemos dos clases, la primera SaveImage, que es la que nos toma la instantánea y la guarda en la carpeta webcamimages con la cédula de la persona, la otra es la que guarda en base de datos y toma la dirección donde esta guardada la imagen y la agrega en el campo foto.

Ahora hacemos el html, llamado en nuestro caso add_persona.html
{% extends "base.html" %}
{% block extra_css %}
<!-- Primero, incluir la libreria de JpegCam -->
<script type="text/javascript" src="{{ STATIC_URL }}jpegcam/webcam.js"></script>
{% endblock extra_css %}
{% block contenido %}
<h1>Registrar Persona</h1>
<form class="span10" action="" method="POST" enctype="multipart/form-data">
{% csrf_token %}
<div class="row well">
<div class="span6">
<div class="control-group">
<label for="cedula" class="control-label">
Cedula:
</label>
<div class="controls">
<input name="cedula" type="text" value="" id="cedula">
<span class="help-inline">  Escriba su Cedula de Identidad</span>
</div>
</div>
<div class="control-group">
<label for="nombres" class="control-label">
Nombres:
</label>
<div class="controls">
<input name="nombres" type="text" value="" id="nombres">
</div>
</div>
<div class="control-group">
<label for="apellidos" class="control-label">
Apellidos:
</label>
<div class="controls">
<input name="apellidos" type="text" value="" id="apellidos">
</div>
</div>
<div class="control-group">
<label for="foto" class="control-label">
Foto:
</label>
<div class="controls">
<input name="foto" type="file" value="" id="foto">
<a href="#takephoto" role="button" data-toggle="modal" class="btn btn-warning">Tomar Foto</a>
</div>
</div>
</div>
<div class="span3" id="fotoview">
</div>
</div>
<button type="submit" class="btn btn-primary pull-right">Guardar</button>
</form>
<!-- Advanced Modal -->
<div id="takephoto" class="modal hide fade" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
   <h3 id="myModalLabel">Camara</h3>
</div>
<div class="modal-body">
<!-- Configure a few settings -->
<script language="JavaScript">
document.write( webcam.get_html(320, 240) );
</script>
</div>
<div class="modal-footer">
<button class="btn" data-dismiss="modal" aria-hidden="true">Cerrar</button>
<button class="btn btn-primary" onClick="take_snapshot()" >Fotografíar</button>
</div>
</div>
{% endblock contenido %}

Lo primero es cargar la librería jpegcam.js, luego creamos nuestro formulario, aquí estoy usando bootstrap para ayudarme con los estilos, utilizo una ventana modal para activar la cámara y tomar la fotografía. Aquí algunos captura de pantalla de la aplicación final:



Y listo, quiero manifestar que hay formas de utilizar la cámara sin usar flash, el cual esta muy cuestionado por el tema de seguridad, mas esto les puede servir en un entorno empresarial, esta aplicación la pueden descargar desde github es este enlace, Espero sus recomendaciones y mejoras.

Saludos



miércoles, 10 de octubre de 2012

Creando Aplicaciones Web con Django 1.4 (2da Parte)

En el articulo anterior hablamos de como arrancar un proyecto en Django, en esta oportunidad aprenderemos un tema importante como es la configuración del proyecto. podemos decir primeramente que no hay una manera definitiva de hacerla, ya que la flexibilidad de Django nos permite que cada quien la realice a sus gusto.

Django por ser un framework de Python, utiliza este lenguaje para guardar sus configuraciones y aprovecha la manera de trabajar del lenguaje para hacer archivos de configuración fáciles de leer, extender y utilizar dentro de nuestros proyectos. Por eso es que quizás veremos en algunos proyectos que la configuración esta en varios archivos Python. En nuestro caso solo hablaremos y trabajaremos con el archivo settings.py.

Empecemos:

Editamos nuestro archivo settings.py con nuestro editor preferido, en mi caso yo uso vim, pero también lo puedes hacerlo con gedit, geany o nano (que es un clon del antiguo Wordstar, para algunos nostálgicos).

Primeramente importamos os, este módulo provee docenas de funciones para interactuar con el sistema operativo, en nuestro caso lo usaremos para conocer la ruta de nuestro proyecto.

# -*- coding: UTF-8 -*-
# Django settings for recetas project.

import os

#Definimos la ruta del proyecto
RUTA_PROYECTO = os.path.dirname(os.path.realpath(__file__))

También le damos la codificación UTF-8 a nuestro archivo de configuración para evitar los errores de caracteres en nuestro idioma.

Django por defecto trae la opción DEBUG=True, para que mientras estemos en desarrollo, podamos ver en detalle los errores de la aplicación, en le caso que tengamos la opción de DEBUG=False, normalmente en producción, las notificaciones de error de código son enviadas vía correo electrónico a los administradores, junto con los detalles completos del error. Para poner los datos de los administradores, debemos agregar en forma de tupla, en mi caso lo dejaré así:

 ADMINS = (
     ('Francisco Quivera', 'fquivera@gmail.com'),
)

Una vez hecho esto vamos a definir con que manejador de base de datos trabajara nuestro proyecto. Quiero aclarar que aunque es posible usar Django sin una base de datos, Django incluye un mapeador objeto-relacional (ORM), en el que es posible describir la estructura de la base de datos usando Python. Esto lo veremos en mas detalle cuando veamos los modelos, aquí solo le diremos a Django con que manejador de base de datos vamos a trabajar. Django soporta de manera predeterminada la conexión con Postgresql, MySql, Sqlite3 y Oracle. En nuestro proyecto usaremos Sqlite3, por su facilidad de uso, ya que viene con Python desde la versión 2.5.

Busquemos la siguiente sección del archivo y modificamos:

DATABASES = {
    'default': {
      'ENGINE': 'django.db.backends.sqlite3', #Add 'postgresql_psycopg2', 'mysql', 'sqlite3' or 'oracle'.
        'NAME': os.path.join(RUTA_PROYECTO,'db/recetas.db'), # Or path to database file if using sqlite3.
        'USER': '',                      # Not used with sqlite3.
        'PASSWORD': '',              # Not used with sqlite3.
        'HOST': '',                      # Set to empty string for localhost. Not used with sqlite3.
        'PORT': '',                      # Set to empty string for default. Not used with sqlite3.
    }
}

Estoy resaltando lo que vamos a agregar, en el caso de utilizar MySql o Postgres, deben instalar previamente los módulos Python para la conexión con estas bases de datos, en Ubuntu se hace con:

MySql:
 
sudo install python-mysqldb

Postgres:

sudo apt-get install python-psycopg2

Configurar la zona horaria, Django permite configurar la zona horaria del proyecto, esto lo hacemos en la siguiente sección, en mi caso agregue la que me corresponde, pueden buscar en la red cual es la que aplica para su caso:

TIME_ZONE = 'America/Caracas'

Django también permite configurar el idioma que usará de manera predeterminada para su funcionamiento, esto es muy útil ya que el administrador de Django, utilizara el idioma definido aquí, para configurar esto debemos cambiar lo siguiente:

LANGUAGE_CODE = 'es-VE'

Django requiere rutas de archivos para cargar archivos estáticos y definir donde estarán nuestras Plantillas o Templates, para hacer esto de manera dinámica, usamos las bondades que nos ofrece Python. Como ya definimos la variable RUTA_PROYECTO, que no es mas que la ruta del directorio donde se encuentra dicho archivo, a partir de éste armaremos la ruta de los archivos estáticos.

Para esto primero debemos crear las carpetas donde vamos a tener dichos archivos, como ya estamos ubicados en home/fquivera/recetas/recetas, hacemos lo siguiente:

mkdir static media plantillas db

luego nos cambiamos a static para crear otras carpetas

cd static
mkdir js img css fonts

Nos deba quedar nuestro árbol de directorio de la siguiente manera:

└── recetas
    ├── manage.py
    └── recetas
        ├── __init__.py
        ├── db
        ├── media       
        ├── plantillas
        ├── settings.py
        ├── static
        │   ├── css
        │   ├── fonts
        │   ├── img
        │   └── js
        ├── urls.py
        └── wsgi.py

¿Para que son esas carpetas que acabamos de crear?

Bien, la carpeta static la utilizamos para ubicar los archivos de estilos css, dentro de la carpeta css, los javascript que podamos utilizar dentro de la carpeta js, las imágenes de nuestro proyecto, como logos, backgrounds, entre otros en la carpeta img y por ultimo si requerimos alguna fuente de letra, la ubicamos en la carpeta fonts
Por otro lado esta la carpeta media, esta carpeta la usamos para almacenar las imágenes, videos, sonidos que utilizamos en nuestros datos, osea, multimedia asociada en nuestra base de datos.
Y por ultimo la carpeta plantillas que allí estarán nuestras plantillas html de nuestro proyecto. La carpeta db es para el archivo de base de datos Sqlite3.

Ahora nos toca decirle a Django a través del archivo settings.py donde están ubicados esos archivos, para ello volvemos a editarlo, buscamos y cambiamos lo siguiente:

Esta variable le dirá a Django donde esta ubicada la carpeta media

MEDIA_ROOT = os.path.join(RUTA_PROYECTO,'media')

La siguiente es la ubicación vía URL, nos permitirá ubicarla mediante http://miproyecto/media

MEDIA_URL = '/media/'

Igualmente la URL para los archivos estáticos

STATIC_URL = '/static/'

La ubicación de los archivos estáticos:

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

Por ultimo, la ubicación de mis plantillas

TEMPLATE_DIRS = (
    os.path.join(RUTA_PROYECTO,'plantillas'),
)

Los proyectos en Django trabajan con aplicaciones, algunas ya vienen configuradas de manera predeterminada. Primeramente vamos a utilizar la aplicación de administración y su documentación, estas ya vienen construidas. Para habilitar estas aplicaciones debemos buscar la sección de INSTALLED_APPS que se encuentra casi al final del archivo settings.py y quitarle la marca de comentarios a 'django.contrib.admin' y 'django.contrib.admindocs'. Nos debe quedar de la siguiente manera:

INSTALLED_APPS = (
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.sites',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'django.contrib.flatpages',
    'django.contrib.admin',
    'django.contrib.admindocs',
)

Ahora salvamos nuestro archivo settings.py, regresamos a la carpeta principal y ejecutamos el siguiente comando:

python manage.py syncdb

Este comando nos crea la base de datos del proyecto, hasta ahora solo va generar las tablas necesarias por el administrador de Django.

Creating tables ...
Creating table auth_permission
Creating table auth_group_permissions
Creating table auth_group
Creating table auth_user_user_permissions
Creating table auth_user_groups
Creating table auth_user
Creating table django_content_type
Creating table django_session
Creating table django_site
Creating table django_admin_log

You just installed Django's auth system, which means you don't have any superusers defined.
Would you like to create one now? (yes/no):
 
Aquí nos pide si queremos crear el superusuario para el administrador, le decimos que si, y nos pide los datos del usuario que sera el administrador

Would you like to create one now? (yes/no): yes
Username (leave blank to use 'fquivera'):
E-mail address: fquivera@gmail.com
Password:
Password (again):
Superuser created successfully.
Installing custom SQL ...
Installing indexes ...
Installed 0 object(s) from 0 fixture(s)

Ahora para poder ver los cambios que hicimos y navegar por la interfaz administrativa de Django, aún falta modificar un archivo llamado urls.py. Este archivo esta en la misma carpeta donde esta el archivo settings.py. Modifiquemos este archivo:

vim urls.py 

from django.conf.urls import patterns, include, url

# Uncomment the next two lines to enable the admin:
# from django.contrib import admin
# admin.autodiscover()

urlpatterns = patterns('',
    # Examples:
    # url(r'^$', 'recetas.views.home', name='home'),
    # url(r'^recetas/', include('recetas.foo.urls')),

  #Uncomment the admin/doc line below to enable admin documentation:
    # url(r'^admin/doc/', include('django.contrib.admindocs.urls')),

    # Uncomment the next line to enable the admin:
    # url(r'^admin/', include(admin.site.urls)),
)

Quitemos el comentario a algunas cosas y nos queda el archivo de la siguiente manera:

from django.conf.urls import patterns, include, url
from django.contrib import admin

admin.autodiscover()

urlpatterns = patterns('',
    # Examples:
    # url(r'^$', 'recetas.views.home', name='home'),
    # url(r'^recetas/', include('recetas.foo.urls')),


    url(r'^admin/doc/', include('django.contrib.admindocs.urls')),

    url(r'^admin/', include(admin.site.urls)),
)

he resaltado lo que he cambiado, además se han borrado las lineas de comentario, bien ahora si probamos lo que hemos hecho hasta ahora

$ python manage.py runserver
Validating models...

0 errors found
Django version 1.4.1, using settings 'recetas.settings'
Development server is running at http://127.0.0.1:8000/
Quit the server with CONTROL-C.

Y probamos en nuestro navegador http://127.0.0.1:8000

veremos lo siguiente:


Upssss, que paso aquí, como ya modificamos el archivo urls.py, Django, ve cuales son las URLs validas para el proyecto y estas son /admin y /admin/doc, ya que no hemos colocado la url raíz. corregimos la url en nuestro navegador de la siguiente manera:

http://127.0.0.1:8000/admin


Ahora Django nos pide el usuario y contraseña, para ingresar al administrador, lo hacemos y tenemos la siguiente pantalla:


Hasta aquí esta segunda parte, cualquier duda, escriba en los comentarios y así lo compartimos con todos. Hasta la próxima