A veces tenemos que hacer queries un poco especiales y necesitamos ayuda de SQL cuando el ORM de Django se nos queda pequeño. Aquí tenemos un ejemplo de cómo ordenar una query a la base de datos por la longitud de un campo:
Modelo.objects.all().extra(select={'length':'Length(campo)'}).order_by('length')
Aprovechando la función extra del ORM de Django que nos permite añadir SQL a nuestras queries podemos calcular la longitud del campo con la función Length() de SQL y guardarla en un argumento length que luego utilizamos en el order_by.
Publicado por Antonio Melé el Jueves 13 d Octubre d 2011 | 1 comentario | Categorías: querysets, trucos
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
Los archivos que suben los usuarios a veces tienen nombres con caracteres no ASCII. Hoy en día casí todos los sistemas de archivos permiten encoding UTF-8, pero a veces nos podemos encontrar problemas en sistemas que no tienen UTF-8 activado o al ejecutar scripts sobre los ficheros que esperen un nombre de archivo en ASCII.
Bojan Mihelac ha publicado en su blog una clase de almacenamiento que se basa en el FileSystemStorage original añadiéndole la normalización de nombres de archivo a ASCII antes de ser almacenados.
A continuación tenéis el código de ASCIIFileSystemStorage. Para convertir a ASCII los nombres de los archivos que se suban bastará con guardar el código e incluir la clase en el setting DEFAULT_FILE_STORAGE:
import unicodedata
from django.core.files.storage import FileSystemStorage
class ASCIIFileSystemStorage(FileSystemStorage):
"""
Convert unicode characters in name to ASCII characters.
"""
def get_valid_name(self, name):
name = unicodedata.normalize('NFKD', name).encode('ascii', 'ignore')
return super(ASCIIFileSystemStorage, self).get_valid_name(name)
Publicado por Antonio Melé el Miércoles 16 d Febrero d 2011 | 2 comentarios | Categorías: trucos
Utilizar rutas relativas en nuestro settings.py en lugar de rutas absolutas permite que el proyecto no dependa del lugar en el que se encuentra en el sistema de archivos. Esto es ideal cuando utilizamos el proyecto en distintos entornos y las rutas absolutas del proyecto son distintas en cada uno de ellos, o si la ruta del proyecto puede variar en algún momento.
Hay dos settings que dependen de rutas del sistema: MEDIA_ROOT y TEMPLATE_DIRS. Para ellos podemos utilizar la propia ruta del proyecto de la siguiente manera con el fin de que las rutas sean relativas. El siguiente ejemplo asume que templates y media se encuentran dentro de la ruta del proyecto:
# settings.py
import os
# ruta del proyecto
PROJECT_PATH = os.path.realpath(os.path.dirname(__file__))
TEMPLATE_DIRS = (
os.path.join(PROJECT_PATH, 'templates'),
)
MEDIA_ROOT = os.path.join(PROJECT_PATH, 'media')
Publicado por Antonio Melé el Martes 15 d Febrero d 2011 | 3 comentarios | Categorías: settings, trucos
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