martes, septiembre 22, 2009

Fotos de Soho v0.2

Después de un tiempo, he realizado la versión 0.2 de un script para descargar las imagenes de soho que busca ser multiplataforma, hecho en python, depende de la libreria PIL.
Para usarlo hay que crear una carpeta y alli poner el script, luego ejecutarlo como:


python2.5 soho.py


o


chmod a+x soho.py
./soho.py


Este es el código:


#! /usr/bin/env python2.5
import os, sys
from urllib2 import Request, urlopen, URLError
from PIL import ImageFile
URL = 'http://www.soho.com.co/galerias_new/mod_'
MODELO_INICIO = 205
MODELO_FINAL = 577
flag_descargar = True




def make_request(full_url):
    print 'Obteniendo imagen de %s ' % full_url 
    req = Request(full_url)
    try:
        response = urlopen(req)
    except URLError, e:
        if hasattr(e, 'reason'):
            print 'We failed to reach a server.'
            print 'Reason: ', e.reason
        elif hasattr(e, 'code'):
            print 'The server couldn\'t fulfill the request.'
            print 'Error code: ', e.code
    else:
        return response


def save_image(response, name):
    "La imagen"
    parser = ImageFile.Parser()
    parser.feed(response.read())
    image = parser.close()
    image.save(name)


while flag_descargar:
    """
    TODO: mejorar los nombres de las carpetas y de los archivos
    """
    NOMBRE_CARPETA = 'soho'
    if 1 <= MODELO_INICIO < 10:
        NOMBRE_CARPETA+='000'
    elif 10 <= MODELO_INICIO < 100:
        NOMBRE_CARPETA+='00'
    elif 100 <= MODELO_INICIO < 1000:
        NOMBRE_CARPETA+='0'
    NOMBRE_CARPETA+=str(MODELO_INICIO)
    if not os.path.exists(NOMBRE_CARPETA):
        full_url = URL+str(MODELO_INICIO)+'/f1.jpg'
        response = make_request(full_url)
        if response:
            "Esto se ejecuta si encuentra la primera foto"
            "Crea la carpeta"
            os.mkdir(NOMBRE_CARPETA)
            save_image(response, NOMBRE_CARPETA+'/f1.jpg')
            "Guarda el resto de imagenes"
            contador = 2
            while True:
                full_url = "%s%s/f%s.jpg" % (URL,str(MODELO_INICIO),str(contador))
                response = make_request(full_url)
                if response:
                    nombre_foto = '%s/f%s.jpg' % (NOMBRE_CARPETA, contador)
                    save_image(response, nombre_foto)
                    contador += 1
                else:
                    break
        else:
            MODELO_INICIO += 1
    else:
        print "YA EXISTE LA CARPETA %s" % NOMBRE_CARPETA
        if MODELO_INICIO <= MODELO_FINAL:
            MODELO_INICIO += 1
        else:
            flag_descargar = False


domingo, agosto 30, 2009

Primeros pasos con geodjango

Este es un minitutorial "expreso" para probar geodjango en debian testing con postgres 8.3, postgis y django 1.1

Pues lo primero es instalar los "juguetes":

$ apt-get install postgis postgresql-8.3 postgresql-plpython-8.3 
$ apt-get install python2.5 python-psycopg2 python-django ipython 
$ apt-get install gdal-bin python-gdal  
Ahora debemos configurar un poco postgres asi:
Debemos volvernos root y luego el usuario postgres

$ su 
$ su postrgres
$ psql template1

Este úlrimo comando nos conecta a postgres como el usuario postgres (el root del servidor de bases de datos), luego configuramos una plantilla para postigs (esto lo hacemos una sola vez)

template1=# ALTER USER postgres WITH PASSWORD 'postgres';
ALTER ROLE
Template1=#  \q

Luego:

$ cd /tmp
$ wget http://geodjango.org/docs/create_template_postgis-debian.sh
$ bash create_template_postgis-debian.sh
Esto nos crea la plantilla template_postgis, ahora volvemos a postgres:

$ createdb -T template_postgis geodjango

Salimos de postgres y del usuario root.
Ahora creamos un projecto y la app:
$ djano-admin startproject geodjango
$ cd geodjango
$ python manage.py startapp world

Luego editamos el settings de nuestro proyecto con el editor de nuestra preferencia (sugerencia rapida gedit)

$ gedit settings.py &
Dejamos las siguientes variables así

DATABASE_ENGINE = 'postgresql_psycopg2' 
DATABASE_NAME = 'geodjango'             # Or path to database file if using sqlite3.
DATABASE_USER = 'postgres'             # Not used with sqlite3.
DATABASE_PASSWORD = 'postgres'         # Not used with sqlite3.
DATABASE_HOST = 'localhost'
LANGUAGE_CODE = 'es'
INSTALLED_APPS = (
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.sites',
    'django.contrib.admin',
    'django.contrib.gis',
    'geodjango.world',
)

luego de guardar estos cambios:
$ mkdir world/data
$ cd world/data
$ wget http://thematicmapping.org/downloads/TM_WORLD_BORDERS-0.3.zip
$ unzip TM_WORLD_BORDERS-0.3.zip
$ cd ../..
 
Luego editamos otro archivo:
 
$ gedit world/models.py & 
 
from django.contrib.gis.db import models

class WorldBorders(models.Model):
    # Regular Django fields corresponding to the attributes in the
    # world borders shapefile.
    name = models.CharField(max_length=50)
    area = models.IntegerField()
    pop2005 = models.IntegerField('Population 2005')
    fips = models.CharField('FIPS Code', max_length=2)
    iso2 = models.CharField('2 Digit ISO', max_length=2)
    iso3 = models.CharField('3 Digit ISO', max_length=3)
    un = models.IntegerField('United Nations Code')
    region = models.IntegerField('Region Code')
    subregion = models.IntegerField('Sub-Region Code')
    lon = models.FloatField()
    lat = models.FloatField()

    # GeoDjango-specific: a geometry field (MultiPolygonField), and
    # overriding the default manager with a GeoManager instance.
    mpoly = models.MultiPolygonField()
    objects = models.GeoManager()

    # So the model is pluralized correctly in the admin.
    class Meta:
        verbose_name_plural = "World Borders"

    # Returns the string representation of the model.
    def __unicode__(self):
        return self.name
 
Luego vemos que todo vaya bien:
 
$ ./manage.py sqlall world 

Esto nos mostrara el sql de postgres para crear nuestro modelo:
 
BEGIN;
CREATE TABLE "world_worldborders" (
    "id" serial NOT NULL PRIMARY KEY,
    "name" varchar(50) NOT NULL,
    "area" integer NOT NULL,
    "pop2005" integer NOT NULL,
    "fips" varchar(2) NOT NULL,
    "iso2" varchar(2) NOT NULL,
    "iso3" varchar(3) NOT NULL,
    "un" integer NOT NULL,
    "region" integer NOT NULL,
    "subregion" integer NOT NULL,
    "lon" double precision NOT NULL,
    "lat" double precision NOT NULL
)
;
SELECT AddGeometryColumn('world_worldborders', 'mpoly', 4326, 'MULTIPOLYGON', 2);
ALTER TABLE "world_worldborders" ALTER "mpoly" SET NOT NULL;
CREATE INDEX "world_worldborders_mpoly_id" ON "world_worldborders" USING GIST ( "mpoly" GIST_GEOMETRY_OPS );
COMMIT;
 
 
Luego ejecutamos este sql:
$ ./manage.py syncdb
 
Lo que nos preguntara el usuario admin, su correo y la clave de acceso:
Creating table auth_permission
Creating table auth_group
Creating table auth_user
Creating table auth_message
Creating table django_content_type
Creating table django_session
Creating table django_site
Creating table django_admin_log
Creating table world_worldborders

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): yes
Username (Leave blank to use 'diegueus9'): <- Toma el usuario con el que estes haciendo esto
E-mail address:  <- Escribe tu correo
Password:
Password (again):
Superuser created successfully.
Installing custom SQL for world.WorldBorders model
Installing index for auth.Permission model
Installing index for auth.Message model
Installing index for admin.LogEntry model 

Luego creamos un scrip que cargará los datos de los archivos que descargamos:
$ gedit world/load.py
import os
from django.contrib.gis.utils import LayerMapping
from models import WorldBorders

world_mapping = {
    'fips' : 'FIPS',
    'iso2' : 'ISO2',
    'iso3' : 'ISO3',
    'un' : 'UN',
    'name' : 'NAME',
    'area' : 'AREA',
    'pop2005' : 'POP2005',
    'region' : 'REGION',
    'subregion' : 'SUBREGION',
    'lon' : 'LON',
    'lat' : 'LAT',
    'mpoly' : 'MULTIPOLYGON',
}

world_shp = os.path.abspath(os.path.join(os.path.dirname(__file__), 'data/TM_WORLD_BORDERS-0.3.shp'))

def run(verbose=True):
    lm = LayerMapping(WorldBorders, world_shp, world_mapping,
                      transform=False, encoding='iso-8859-1')

    lm.save(strict=True, verbose=verbose)
 
Ahora lo que vamos a hacer es subir la info de las fronteras de los paises del mundo a nuestro modelo:
 
$ ./manage shell 
Python 2.5.4 (r254:67916, Feb 18 2009, 03:00:47)
Type "copyright", "credits" or "license" for more information.

IPython 0.9.1 -- An enhanced Interactive Python.
?         -> Introduction and overview of IPython's features.
%quickref -> Quick reference.
help      -> Python's own help system.
object?   -> Details about 'object'. ?object also works, ?? prints more.

In [1]: from world import load

In [2]: load.run()
...
...
...
Saved: Jersey
Saved: South Georgia South Sandwich Islands
Saved: Taiwan

In [3]: exit()
Do you really want to exit ([y]/n)? y
Ahora vamos a activar y usar nuestra interfaz automagica administrativa que nos da django:
$ gedit world/admin.py &
from django.contrib.gis import admin
from models import WorldBorders

class WorldBordersAdmin(admin.GeoModelAdmin):
    list_display = ['name', 'area', 'pop2005', 'lon', 'lat']
    search_fields = ['name']

admin.site.register(WorldBorders, WorldBordersAdmin)
 
Y luego editamos las urls:
$ gedit urls.py &
from django.conf.urls.defaults import *
from django.contrib import admin
admin.autodiscover()

urlpatterns = patterns('',
    (r'^admin/', include(admin.site.urls)),
)

Ahora ponemos a correr nuestro servidor de desarrollo:
$ ./manage runserver 9090
Validating models...
0 errors found

Django version 1.1, using settings 'geodjango.settings'
Development server is running at http://127.0.0.1:9090/
Quit the server with CONTROL-C.
Y en el navegador vamos a  http://127.0.0.1:9090/ veremos un error 404 como este:

Luego vamos a http://127.0.0.1:9090/admin y veremos esta interfaz:
alli ingresamos el usuario y la clave que configuramos cuando corrimos el comando syncdb y veremos esto:

Luego hacemos clic en World Borders y veremos algo así:

Allí podemos ordenar la lista por nombre  del pais (name), area (area), poblacion del 2005 (population 2005) o longitud y latitud del mismo. Ahora cerca al boton buscar ingresamos colombia y le damos buscar luego clic en colombia y veremos info y este mapa:

Y eso es todo, así tendremos nuestro "Hola mundo" con geodjango, django, postgres, postgis, etc...

Hola Mundo con Mapserver

Este es un post con el "hola mundo" del mapserver, basado en la información del post http://blueswinter.blogspot.com/2009/05/mapserver-ii-mi-primer-experiencia.html y para debian testing.
Primero debemos instalar apache y mapserver así:
$ apt-get install cgi-mapserver mapserver-bin mapserver-doc apache2

Luego creamos una carpeta para poner los datos del primer mapa (como root):
$ mkdir /home/mapdata/
$ chmod 777 /home/mapdata/

Luego dentro del directorio (cd /home/mapdata) hacemos un archivo

$ nano hola.map

y le ponemos el siguiente contenido:

MAP                                                        
# Este es nuestro 'hola mundo' mapfile                     
NAME "Hello_Word"                                          
SIZE 400 300                                               
IMAGECOLOR 249 245 186                                     
IMAGETYPE png
EXTENT -1.00 -1.00 1.00 1.00
WEB
TEMPLATE "/var/www/map/hola.html"
IMAGEPATH "/var/www/map/tmp/"
IMAGEURL "/map/tmp/"
END
LAYER
STATUS default
TYPE point
FEATURE
POINTS 0.0 0.0 END
TEXT "HOLA MUNDO"# USA 2 ESPACIOS!
END # end FEATURE
CLASS
STYLE
COLOR 255 0 0
END
LABEL
TYPE bitmap
END
END # end CLASS
END # end LAYER
END # end MAPFILE
END

Guardamos con ctrl+s

luego vamos al directorio de apache (en debian es /var/www/) y creamos una carpeta para la prueba (como root ):
$ mkdir map
$ mkdir map/tmp

y dentro de map hacemos un html:

$ nano hola.html



< html >
< head >< title >MapServer Hola Mundo< /head >
< body >
< form method=POST action="/cgi-bin/mapserver">
< input type="submit" value="cliqueame" >
< input type="hidden" name="map" value="/home/mapdata/hola.map" >
< input type="hidden" name="map_web" value="imagepath /var/www/map/tmp/ imageurl /map/tmp/" >

< img src="[img]" with=400 heigth=300 border=0 >




guardamos y en el navegador vamos a http://localhost/map/hola.html hacemos clic en el boton y listo!, vemos algo como esto:

viernes, marzo 20, 2009

Snippet de vista para i18n

Una de las cosas que nos ofrece django es vistas genéricas y soporte para localización (aka i10n) e internacionalización (aka i18n). Entonces una vez tenemos nuestro sitio con i18n o i10n pues lo que sigue es que le demos a nuestros usuarios la manera de escoger su idioma, django tiene un algoritmo par esto, sin embargo en algún punto nuestros usuarios querrán poder escoger su idioma preferido, para esto este framework nos da la opcion de una vista generica, sobre la cual encontrarán información en http://docs.djangoproject.com/en/dev/topics/i18n/#the-set-language-redirect-view.

Lo único es que esta vista espera que halla un formulario para que el usuario escoja su idioma y además que tengamos predefinida una página a la cual el usuario será redirigido después de seleccionar el idioma a lo cual le veo particularmente un inconveniente pues si el usuario ha llegado a un punto importante para él y es llevado a la página inicial pues no le agradará (en mi caso me molestaría), además si queremos tener la posibilidad de hacerlo desde una url y no una variable por post?

Para resolver este conflicto se modifica un poco la vista que nos trae django y la dejamos así:


def set_lang(request,lang):
    response = HttpResponseRedirect(request.META['HTTP_REFERER'])
    lang_code = u'%s' % lang
    if lang_code and check_for_language(lang_code):
        if hasattr(request, 'session'):
            request.session['django_language'] = lang_code
        else:
            response.set_cookie(settings.LANGUAGE_COOKIE_NAME, lang_code)
    return response

Esta vista espera que se escoja el idioma por una url y además redireccionará al usuario a la página en la que se encontraba, podemos hacerlo incluso en el urls.py y finalmente escogemos la url:

urlpatterns = patterns('',
    ... 
    (r'^set_lang/(?P\w{2})/$',set_lang),
    ...
)


de esta manera si se va a /set_lang/es/, django cargará todo nuestro sitio en español y volvera a la vista en la que lo hallamos hecho.

lunes, marzo 09, 2009

Plugins de firefox para desarrollo web

Este es el listado de los plugins para desarrollo web creo fundamentales:

Otros que ayudan:

lunes, febrero 16, 2009

Probando otro servicio de identica/twitter

http://twitterfeed.com es un sitio que permite twittear/identiquear un post de un blog, y esta es una prueba

martes, enero 27, 2009

16pf


Cattell's 16 Factor
Test Results










Warmth |||||||||||| 38%
Intellect ||||||||||||||||||||| 70%
Emotional Stability ||||||||| 22%
Aggressiveness ||||||||||||||||||||| 62%
Liveliness ||||||||||||||||||||| 62%
Dutifulness ||||||||||||||| 46%
Social Assertiveness ||||||||||||||| 42%
Sensitivity |||||||||||||||||||||||||||| 82%
Paranoia |||||||||||||||||||||66%
Abstractness ||||||||||||||||||||| 70%
Introversion |||||||||||||||||| 54%
Anxiety |||||||||||||||||| 58%
Openmindedness ||||||||||||||||||||| 70%
Independence ||||||||||||||||||||| 70%
Perfectionism |||||||||||||||||| 58%
Tension ||||||||||||||| 46%

Take Cattell 16
Factor Test (similar to 16pf)

personality tests by
similarminds.com


Lo pongo solo porque me rechazarón (una psicologa claro).

jueves, enero 22, 2009

Como usar el poderoso ORM de django en una aplicación de Escritorio

Alguna vez alguien me preguntaba que tan complejo seria usar el poderoso ORM de django en una aplicación de escritorio, lo cual me pareció una cuestión interesante pero debido al trabajo y la procrastinación™ lo dejé a algún lado, en estos días como ando melómano he estado dedicándole mucho tiempo a la musica, por cierto el reproductor que yo uso es Amarok, aunque también decidí probar el mpd, en fin cada cual tiene lo suyo y amarok me parece muy poderoso, probé otros mas como exaile, que intenta ser como amarok pero esta escrito en python con librerías gtk y este muy biche, entonces curioseando y por algunos errores de comportamiento en el amarok, me dio por revisar la estructura de la base de datos, y sinceramente no es lo mejor en modelos E-R, entonces quería ver que tan complejo sería hacer un nuevo reproductor de musica, principalmente que sea un frontend a los más comunes, amarok, banshee, mpd, y demás, incluso con una interfaz web al estilo ampache, pero pues obviamente en python y usando django, entonces empecé a realizar el esquema y de repente se me ocurrio la idea de tambien hacer un cliente de escritorio y volvio esta cuestión a mi.
Lo curioso del asunto es que es mucho más sencillo de lo que creia solo hay que poner tres lineas de código al inicio de nuestra aplicación:
Nota: es importante que crees el proyecto con el django-admin

import os, sys
os.environ['DJANGO_SETTINGS_MODULE']='proyecto.settings'
sys.path+=[os.path.split(os.path.split(os.path.abspath(__file__))[0])[0]]

La primera linea importa los modulos os y sys.
La seguna pone la variable de entorno DJANGO_SETTINGS_MODULE que django buscará para saber las configuraciones del archivo settings.py y la ultima agrega al path de python el path de donde se encuentra la carpeta del projecto.

Y de esta manera ya podemos usar todo lo que nos ofrece django en una aplicación de escritorio, el ORM, los validadores, incluso los forms.