Ya está disponibles las diapositivas y el vídeo del taller de Introducción a Django que realizamos Antonio Melé (@zenxone) y Miguel Araujo (@maraujop) en el Betabeers de Octubre.
Aquí tenéis las diapositivas: Introducción a Django y Ecosistema de aplicaciones Django y apps pluggables.
Y aquí tenéis el vídeo:
Publicado por Antonio Melé el Jueves 20 d Octubre d 2011 | 16 comentarios | Categorías: comunidad, cursos, pluggables, tutorial
Mitch Fournier explica en su blog cómo importar datos en formato CSV a un modelo de Django, tal cómo lo ha utilizado en su proyecto Wantbox.com.
Primero creamos un modelo que contenga los mismos campos que el archivo CSV que queramos importar, utilizando el tipo de campo más adecuado para cada uno de ellos dependiendo de si sus valores van a ser cadenas de texto, números, fechas... Aquí tenemos un ejemplo de archivo CSV:
ZIPCODE, CITY, STATECODE, STATENAME
02111, BOSTON, MA, MASSACHUSETTS
02481, WELLESLEY HILLS, MA, MASSACHUSETTS
05819, ST. JOHNSBURY, VT, VERMONT
...
Creamos el modelo que nos sirva para almacenar los datos:
import datetime
class ZipCode(models.Model):
zipcode = models.CharField(max_length=5)
city = models.CharField(max_length=64)
statecode = models.CharField(max_length=2)
statename = models.CharField(max_length=32)
create_date = models.DateTimeField(default=datetime.datetime.now)
def __unicode__(self):
return "%s, %s (%s)" % (self.city, self.statecode, self.zipcode)
class Meta:
ordering = ['zipcode']
Después creamos un script que utilizaremos para importar los datos, podemos llamarlo load_data.py. El script incluirá la ruta de nuestro archivo CSV y de nuestro proyecto para utilizar sus settings. En el script leeremos las líneas del archivo CSV y crearemos una instancia de nuestro modelo por cada línea para después guardarla en la base de datos.
# ruta a nuestro archivo CSV
csv_filepathname="/home/usuario/zipcodes.csv"
# ruta a nuestro proyecto de django
your_djangoproject_home="/home/usuario/projects/mi_proyecto/"
import sys,os
sys.path.append(your_djangoproject_home)
os.environ['DJANGO_SETTINGS_MODULE'] = 'settings'
# importamos nuestro modelo
from zips.models import ZipCode
import csv
dataReader = csv.reader(open(csv_filepathname), delimiter=',', quotechar='"')
for row in dataReader:
if row[0] != 'ZIPCODE': # ignoramos la primera línea del archivo CSV
zipcode = ZipCode()
zipcode.zipcode = row[0]
zipcode.city = row[1]
zipcode.statecode = row[2]
zipcode.statename = row[3]
zipcode.save()
Este script también nos sirve para importar datos de archivos TSV de Excel cambiando la línea de dataReader por:
dataReader = csv.reader(open(csv_filepathname), dialect='excel-tab')
De esta forma podemos importar nuestros datos en formato CSV o TSV a nuestros proyecto django. También podemos crear un management command específico para ello en lugar utilizar un script independiente.
Publicado por Antonio Melé el Miércoles 12 d Octubre d 2011 | 2 comentarios | Categorías: modelos, trucos, tutorial
Vamos a ver cómo combinar django-qsstats para generar estadísticas y Google Visualization API para representarlas gráficamente.
django-qsstats permite obtener estadísticas agregadas sobre querysets de forma sencilla. Vamos a crear una vista que nos dé el número de usuarios registrados cada día para los últimos 14 días. Para ello crearemos una QuerySetStats a partir del campo date_joined del modelo User de django.contrib.auth. Usaremos time_series pasándole la fecha inicial y final, para obtener un listado de tuplas tipo (fecha, valor) diario con la fecha y el número de usuarios registrados cada día. Necesitaremos pasar a nuestra plantilla nuestra clave de la API de javascript de Google. Si no tienes una clave puedes conseguirla aquí.
Crearemos la siguiente vista en views.py:
from django.template import RequestContext
from django.shortcuts import render_to_response
from django.contrib.auth import User
import datetime
import qsstats
def estadisticas(request):
GOOGLE_API_KEY = 'clave'
qs = User.objects.all()
qss = qsstats.QuerySetStats(qs, 'date_joined')
hoy = datetime.date.today()
hace_2_semanas = hoy - datetime.timedelta(weeks=2)
users_stats = qss.time_series(hace_2_semanas, hoy)
return render_to_response('estadisticas.html', locals(), context_instance=RequestContext(request))
En user_stats tendremos una lista de tuplas con un elemento por cada día de las dos semanas.
En nuestra plantilla estadisticas.html cargaremos la API de javascript de Google. Crearemos una tabla de datos con DataTable y utilizaremos un gráfico tipo LineChart para su representación. La plantilla quedará de la siguiente manera:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8" />
</head>
<body>
<h1>Nuevos usuarios en las últimos 2 semanas</h1>
<div id="usuarios_14_dias"></div>
</body>
</html>
<script type="text/javascript" src="http://www.google.com/jsapi?key={{ GOOGLE_API_KEY }}"></script>
<script type="text/javascript"><!--
google.load("visualization", "1", {packages:["corechart"]});
google.setOnLoadCallback(function() {
var data = new google.visualization.DataTable();
data.addColumn('string', 'Día');
data.addColumn('number', 'Usuarios nuevos');
data.addRows({{ users_stats|length }});
{% for s in users_stats %}
data.setValue({{ forloop.counter0 }}, 0, '{{ s.0|date:"d M" }}');
data.setValue({{ forloop.counter0 }}, 1, {{ s.1 }});
{% endfor %}
var chart = new google.visualization.LineChart(document.getElementById('usuarios_14_dias'));
chart.draw(data, {width: 620, height: 200, legend:'none'});
});
//--></script>
Obtendremos un gráfico como el siguiente:
Publicado por Antonio Melé el Domingo 15 d Agosto d 2010 | 3 comentarios | Categorías: plantillas, tutorial
A veces queremos utilizar la función de aggregación annotate() y aplicar filtros al modelo que se encuentra dentro de la misma, pero no es posible hacerlo con el ORM de Django actualmente. En este caso la solución pasa por usar la función extra() del ORM de Django para incluir SQL propio.
Vamos a ver un ejemplo práctico. Supongamos una aplicación llamada ocio y el siguiente models.py con hobbies y personas que los practican:
from django.db import models
class Hobby(models.Model):
nombre = models.CharField(max_length=250)
SEXO_CHOICES = (
('m','Masculino'),
('f','Femenino'),
)
class Persona(models.Model):
nombre = models.CharField(max_length=250)
sexo = models.CharField(max_length=1, choices=SEXO_CHOICES)
hobbies = models.ManyToManyField(Hobby, related_name='personas')
Gracias a las funciones de agregación de Django podemos obtener fácilmente todos los hobbies y el número de personas que lo practican utilizando annotate(). En el siguiente ejemplo vemos que para cada hobby se contará el número de personas relacionadas y será accesible mediante el atributo personas_count:
from django.db.models import Count
hobbies = Hobby.objects.annotate(personas_count=Count('personas_count'))
for hobby in hobbies:
print '%s personas practican %s' % (hobby.personas_count, hobby.nombre)
Con esto contamos todas las personas relacionadas con cada hobby, pero a veces nos interesa filtrar las personas que se contabilizan. ¿Y si sólo quisiéramos obtener el número de mujeres que practican cada hobby? En este caso queremos filtrar por un atributo del modelo que se está utilizando en annotate() y de momento no se puede hacer con el ORM de Django.
Para obtener el número de mujeres que practican cada hobby lo primero que haremos será obtener mediante values_list() un listado de los id de las personas que cumplan la condición sexo='f':
# obtenemos lista en python, p. ej: [13, 21, 60]
mujeres_ids = Persona.objects.filter(sexo='f').values_list('id', flat=True)
A continuación convertiremos la lista a un string con id's separados por comas para poder utilizarlos en nuestra sentencia SQL:
# id's separados por comas en string, p. ej: "13,21,60"
lista_ids = ','.join(str(id) for id in mujeres_ids)
Después prepararemos la sentencia SQL que utilizaremos en nuestro queryset(). Recordemos que por defecto Django crea las tablas de la base de datos con la nomenclatura aplicacion_modelo. Por lo que si nuestra aplicación se llama ocio, la tabla para el modelo Persona será ocio_persona y para el modelo Hobby será ocio_hobby. Para la relación M2M Django genera una tabla intermedia que relaciona los id's de personas con los id's de hobbies. Esta tabla en nuestro caso será ocio_persona_hobbies ya que el campo de la relación ManyToMany se llama hobbies y se encuentra en el modelo Persona.
Teniendo en cuenta que la query va a hacerse sobre el modelo Hobby utilizaremos una consulta SELECT que realice un COUNT sobre la tabla que relaciona personas con hobbies de tal forma que por cada hobby (ocio_hobby.id) contemos el número de filas en los que el id de la persona relacionada se encuentre en la lista de id's de mujeres.
'SELECT COUNT(*) FROM ocio_persona_hobbies WHERE ocio_persona_hobbies.hobby_id = ocio_hobby.id AND ocio_persona_hobbies.persona_id IN (%s)' % lista_ids
Por último prepararemos nuestra queryset() utilizando extra() para incluir nuestro código SQL. Así quedará el código completo:
mujeres_ids = Persona.objects.filter(sexo='f').values_list('id', flat=True)
lista_ids = ','.join(str(id) for id in mujeres_ids)
hobbies = Hobby.objects.extra(
select = {
'personas_count': 'SELECT COUNT(*) FROM ocio_persona_hobbies WHERE ocio_persona_hobbies.hobby_id = ocio_hobby.id AND ocio_persona_hobbies.persona_id IN (%s)' % lista_ids
},
)
Si queremos hacer nuestro código independiente de los nombres de las tablas de la base de datos podemos usar Persona._meta.db_table para obtener el nombre de la tabla usada para el modelo Persona y del mismo modo para el modelo Hobby. Para obtener el nombre de la tabla que relaciona personas y hobbies usaremos Persona._meta.get_field('hobbies').m2m_db_table().
El código independiente de las tablas quedaría de la siguiente manera:
mujeres_ids = Persona.objects.filter(sexo='f').values_list('id', flat=True)
lista_ids = ','.join(str(id) for id in mujeres_ids)
personas_hobbies = Persona._meta.get_field('hobbies').m2m_db_table()
hobbies = Hobby.objects.extra(
select = {
'personas_count': 'SELECT COUNT(*) FROM %s WHERE %s.hobby_id = %s.id AND %s.persona_id IN (%s)' % (personas_hobbies, personas_hobbies, Hobby._meta.db_table, personas_hobbies, lista_ids)
},
)
Publicado por Antonio Melé el Viernes 13 d Agosto d 2010 | 4 comentarios | Categorías: modelos, querysets, trucos, tutorial
Suscríbete a nuestro feed RSS y al feed de la comunidad para estar al tanto de todo lo que ocurre entorno a Django.
Tú también puedes escribir en éste blog. Para hacerlo basta con que nos digas sobre qué quieres escribir un artículo relacionado con Django.
Utilizar un formulario para modificar 2 modelos
Descubriendo objetos similares por sus etiquetas