node -v
# Tienes dos opciones para instalar NVM
curl https://raw.githubusercontent.com/creationix/nvm/v0.12.1/install.sh | bash
# wget -qO- https://raw.githubusercontent.com/creationix/nvm/v0.12.1/install.sh | bash
source ~/.profile
# Si no te funcionan los siguientes comandos, abre un terminal nuevo
nvm ls-remote # lista de versiones
nvm install v4.4.4 # intalacion
nvm current # version Node NVM activado
node -v # version Node que esta siendo usada
npm -v # version NPM que esta siendo usada
which node # donde esta instalado Node
# Ya podemos instalar los paquetes
npm -g install ember-cli # Install Ember-cli
npm -g install bower # Install bower package manager
npm -g install phantomjs # Install phantomJS (integration testing)
ember new proyecto # Creamos un nevo proyecto ember
cd proyecto
ember server # arrancamos el servidor
# Si clonaramos un proyecto de git
git clone git@github.com:...
cd proyecto
npm install # instalamos dependencias
bower install
ember server
# para usar una version concreta de Node
nvm use v4.4.4
en la mina
viernes, 20 de mayo de 2016
Ember: Instalar Node.js/NPM sin Sudo
lunes, 10 de agosto de 2015
Iframe
# config/application.rb
# Enable IFrame
config.action_dispatch.default_headers = { 'X-Frame-Options' => 'ALLOWALL' }
Este es el codigo html del iframe
<iframe width="100%" frameborder="0" src="http://nuestra.apprails/" height="400"></iframe>
domingo, 2 de agosto de 2015
Instalar rbenv, ruby-build y bundler en Ubuntu
sudo apt-get update
sudo apt-get install git-core curl zlib1g-dev build-essential libssl-dev libreadline-dev libyaml-dev libsqlite3-dev sqlite3 libxml2-dev libxslt1-dev libcurl4-openssl-dev python-software-properties libffi-dev
# inatalamos rbenvgit clone https://github.com/sstephenson/rbenv.git ~/.rbenv
echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bashrc
echo 'eval "$(rbenv init -)"' >> ~/.bashrc
exec $SHELL
type rbenv #=> "rbenv is a function"
# instalamos ruby-buildgit clone https://github.com/sstephenson/ruby-build.git ~/.rbenv/plugins/ruby-build
# Listado de las versiones de ruby$ rbenv install -l
# Instalamos ruby 2.2.2, lo designamos por defecto y lo comprobamosrbenv install 2.2.2
rbenv global 2.2.2
ruby -v
# para evitar intalar la documentecion de la gemasecho "gem: --no-ri --no-rdoc" > ~/.gemrc
# instalamos bundlergem install bundler
# Repo rbenv https://github.com/sstephenson/rbenv# Repo ruby-build https://github.com/sstephenson/ruby-build
# web bundler http://bundler.io/
# Recordatorio RVM, instalación y uso http://en-la-mina.blogspot.com/2012/01/recordatorio-rvm-instalacion-y-uso.html
martes, 13 de mayo de 2014
Aplicación de Datos: Python, Flask, pip y virtualenvs
- Fuente "Aplicación de Datos"
- Necesario instalación de entrada anterior "Python, Django, pip y virtualenvs en Ubuntu"
- Codigo fuente en github
Flask un micro framework para crear aplicaciones web en python. Usar pip para instalar Flask
$ pip install Flask
Crear directorio en donde pondremos archivos con código de la aplicación
$ mkdir mi-app
Adentro crear archivo llamado app.py, donde configuremos Flask y servira como backend de nuestro proyecto. Abrir app.py en un editor
from flask import Flask
app = Flask(__name__)
Configurar para hacer la raíz de tu sitio. Usaremos un archivo llamado 'index.html' para colocar la información. Tenemos que especificarlo en app.py
from flask import Flask
from flask import render_template
app = Flask(__name__)
@app.route("/")
def index():
return render_template('index.html')
Crear directorio "templates" dentro del directorio de nuestro proyecto.
$ mkdir templates
Crear "index.html" dentro del directorio "templates" y colocarle cualquier texto.
¡Hola Mundo!
Volver a editar app.py y agregarle lo siguiente para poder levantar el servidor local de Flask
from flask import Flask
from flask import render_template
app = Flask(__name__)
@app.route("/")
def index():
return render_template('index.html')
if __name__ == '__main__':
app.run(
host="0.0.0.0",
port=8000,
use_reloader=True,
debug=True,
)
Correr app.py en la linea de comandos. Mirar el resultado en un navegador en http://localhost:8000
$ python app.py
Comenzar nuevamente editando "index.html". Reemplazar el contenido por el esqueleto de un archivo HTML
Incendios en España entre 2004 y 2014
Crear directorio para guardar archivos estáticos. Aqui guardaremos el CSV con nuestros datos. Descargalo
$ mkdir static
Abrir app.py en editor de texto. Usaremos libreria csv para acceder a nuestros datos y pasarle la lista de datos del csv a index.html
from flask import Flask
from flask import render_template
app = Flask(__name__)
csv_path = './static/incendios.csv'
csv_obj = csv.DictReader(open(csv_path, 'r'))
csv_list = list(csv_obj)
@app.route("/")
def index():
return render_template('index.html',
object_list=csv_list,
)
if __name__ == '__main__':
app.run(
host="0.0.0.0",
port=8000,
use_reloader=True,
debug=True,
)
Guardar app.py y editar index.html. Colocar la lista del csv en el index.html. En linea de comandos correr app.py y visitar http://localhost:8000 nuevamente
Incendios en España entre 2004 y 2014
{{ object_list }}
Vamos a darle formato a los datos en index.html. Estamos usando el lenguaje de templating jinja de Flask
Incendios en España entre 2004 y 2014
IDPIF
Superficie Forestal Quemada
Fecha
Muertos
Heridos
Comunidad
Provincia
Comarca
Causa
Perdidas
{% for obj in object_list %}
{{ obj['IDPIF'] }}
{{ obj['SUPQUEMADA'] }}
{{ obj['FECHA'] }}
{{ obj['MUERTOS'] }}
{{ obj['HERIDOS'] }}
{{ obj['COMUNIDAD'].decode('UTF-8') }}
{{ obj['PROVINCIA'].decode('UTF-8') }}
{{ obj['COMARCA'].decode('UTF-8') }}
{{ obj['CAUSA'].decode('UTF-8') }}
{{ obj['PERDIDAS'] }}
{% endfor %}
Ahora página de detalles por incendio. Agregamos una nueva ruta en archivo "app.py"
@app.route('//')
def detail(number):
return render_template('detail.html')
Agreguemos el template "detail.html". Editamos el archivo detail.html. Agregar algo simple. Y levantamos la página en el navegador con cualquier número. http://localhost:8000/2004210126/
¡Hola Detalle!
Buscamos el incendio. Conectamos el número en la URL con el número identificador real del incendio en el CSV. Editamos app.py y convertimos la lista que tenemos en algo donde el incendio sea fácilmente buscable por identificador.
Editamos la función detail en app.py para que conecte el número en la URL con el registro correspondiente. Quedaría:
import csv
from flask import Flask
from flask import render_template
app = Flask(__name__)
csv_path = './static/incendios.csv'
csv_obj = csv.DictReader(open(csv_path, 'r'))
csv_list = list(csv_obj)
csv_dict = dict([[o['IDPIF'], o] for o in csv_list])
@app.route("/")
def index():
return render_template('index.html',
object_list=csv_list,
)
@app.route('//')
def detail(number):
return render_template('detail.html',
object=csv_dict[number],
)
if __name__ == '__main__':
app.run(
host="0.0.0.0",
port=8000,
use_reloader=True,
debug=True,
)
Volver a editar detail.html para agregarle datos desde nuestro CSV
{{ object['COMUNIDAD'].decode('UTF-8') }}
Editar "index.html" para enlazar la página del incendio. En la tag table reemplazar la fila de
{{ obj['IDPIF'] }}
Agregar el resto de los campos del incendio en detail.html
Incendio de {{ object['COMUNIDAD'].decode('UTF-8') }}
En la comunidad {{ object['COMUNIDAD'].decode('UTF-8') }}, provincia {{ object['PROVINCIA'].decode('UTF-8') }}, comarca {{ object['COMARCA'].decode('UTF-8') }}, municipio {{ object['MUNICIPIO'].decode('UTF-8') }} se quemó una superficie forestal de {{ object['SUPQUEMADA'] }}. Hubieron {{ object['MUERTOS'] }} muertos y {{ object['HERIDOS'] }} heridos. Se detectó en la fecha {{ object['FECHA'] }}. Se pudo controlar en {{ object['TIME_CTRL'] }} minutos y extinguir en {{ object['TIME_EXT'] }} minutos. La causa del incendio fue {{ object['CAUSA'].decode('UTF-8') }}. En la extinción del incendio participaron {{ object['PERSONAL'] }} personas, {{ object['PESADOS'] }} vehiculos pesados y {{ object['AEREOS'] }} medios aereos.
Javascript. Ahora vamos a colocar un mapa con los incendios usando una libreria de Javascript llamada Leaflet. Primero hay que importarla en el archivo "index.html"
...
Crear un elemento HTML para el mapa
...
Incendios en España entre 2004 y 2014
...
Y usar Leaflet para centrarlo en España. Inicializamos el mapa con las coordenadas de España y nivel de zoom
Agregamos la capa de tiles desde mapquest, que utiliza open street map. Se le pasa la URL para las imagenes de tiles, el nivel máximo de zoom (18) y el texto sobre de donde vienen los mapas.
Le agregamos el layer al elemento del mapa
Transformar los datos del CSV que tenemos a GeoJSON. GeoJSON es un formato para guardar estructuras de datos geograficos junto a información no geografica
Agregar una ventanita popup que muestre información sobre el incendio. Sustituir var dataLayer
Hacemos lo mismo en "detail.html" agregamos un mapa del incendio. Quedaria:
Incendio de {{ object['COMUNIDAD'].decode('UTF-8') }}
En la comunidad {{ object['COMUNIDAD'].decode('UTF-8') }}, provincia {{ object['PROVINCIA'].decode('UTF-8') }}, comarca {{ object['COMARCA'].decode('UTF-8') }}, municipio {{ object['MUNICIPIO'].decode('UTF-8') }} se quemó una superficie forestal de {{ object['SUPQUEMADA'] }}. Hubieron {{ object['MUERTOS'] }} muertos y {{ object['HERIDOS'] }} heridos. Se detectó en la fecha {{ object['FECHA'] }}. Se pudo controlar en {{ object['TIME_CTRL'] }} minutos y extinguir en {{ object['TIME_EXT'] }} minutos. La causa del incendio fue {{ object['CAUSA'].decode('UTF-8') }}. En la extinción del incendio participaron {{ object['PERSONAL'] }} personas, {{ object['PESADOS'] }} vehiculos pesados y {{ object['AEREOS'] }} medios aereos.
domingo, 20 de abril de 2014
Python, Django, pip y virtualenvs en Ubuntu
Instalamos entorno Python/Django [gdggranada.com]:
Ubuntu (12.04) ya trae Python (2.7), aun así comprobamos que está todo:
verdor@enlamina ~$ sudo apt-get install python-virtualenv python-pip python-dev sqlite3 python-sqlite build-essential
verdor@enlamina ~$ #sudo apt-get install python-imaging python-pythonmagick python-markdown python-textile python-docutils #parece que esto es opcional
- pip es una herramienta para instalar y administrar Paquetes Python (¿RubyGem?)
- virtualenvs o entornos virtuales (de Python) es un espacio completamente independiente de otros entornos virtuales y de los paquetes instalados globalmente en el sistema (¿RVM?) [Tutorial de Python virtualenv]
Podemos instalar Django con apt-get de sistema...
verdor@enlamina ~$ sudo apt-get install python-django
...o bajar los repos...
verdor@enlamina ~$ git clone https://github.com/django/django.git
... o usar pip...
verdor@enlamina ~$ pip install Django==1.6.2 # Estable
verdor@enlamina ~$ # pip install https://www.djangoproject.com/download/1.7b1/tarball/ # version beta 1.7
Continuamos...
Preparamos el Entorno:
Actualizamos pip e instalamos virtualenv (se puede hace con sudo)
verdor@enlamina ~$ pip install --upgrade pip
verdor@enlamina ~$ pip install --upgrade virtualenv # --upgrade es opcional
Preparamos el entorno:
verdor@enlamina ~$ cd src
verdor@enlamina ~/src$ mkdir entorno
verdor@enlamina ~/src$ cd entorno
verdor@enlamina ~/src/entorno$ virtualenv env
New python executable in env/bin/python
Installing setuptools, pip...done.
Activamos el entorno:
verdor@enlamina ~/src/entorno$ source env/bin/activate
(env)verdor@enlamina ~/src/entorno$ # ojo con el prompt
Instalamos django 1.5:
(env)verdor@enlamina ~/src/entorno$ pip install django==1.5
Downloading/unpacking django==1.5
Downloading Django-1.5.tar.gz (8.0MB): 8.0MB downloaded
...
Successfully installed django
Cleaning up...
Creamos un proyecto (luego distinguiremos entre proyecto y aplicación):
verdor@enlamina ~$ django-admin.py startproject mysite
verdor@enlamina ~$ cd mysite
verdor@enlamina/mysite ~$ python manage.py runserver
Validating models...
0 errors found
April 20, 2014 - 06:51:31
Django version 1.5, using settings 'mysite.settings'
Development server is running at http://127.0.0.1:8000/
Quit the server with CONTROL-C.
Vamos a comprobar que arranca la aplicación en el navegador http://127.0.0.1:8000/, y esto es lo que vemos:
It worked!
Congratulations on your first Django-powered page.
- If you plan to use a database, edit the
DATABASES
setting inmysite/settings.py
. - Start your first app by running
python manage.py startapp [appname]
.
DEBUG = True
in your
Django settings file and you haven't configured any URLs. Get to work!
¿Y donde esta el código generado de mi proyecto?
mysite/
manage.py
mysite/
__init__.py
settings.py
urls.py
wsgi.py
- miblog/: El Directorio externo que contiene nuestro projecto.
- miblog/miblog: El directorio interno que sera el nombre que usaremos para importar el paquete.
- manage.py: Una utilidad de línea de comandos para interactuar con nuestro proyecto(crear las tablas, iniciar el servidor...).
- miblog/__init__.py: Un archivo vació requerido para que Python trate a este directorio como un paquete.
- miblog/settings.py: Configuraciones para este proyecto de Django.
- miblog/urls.py: La “tabla de contenidos” de nuestro proyecto.
- miblog/wsgi.py: El archivo encargado de ser compatible con el servidor web.
Editamos settings.py. Guias: maestrosdelweb.com django-en-cero-coma-i 1ªDjangoApp
Codificacion de caracteres:
#encoding:utf-8
Ruta del proyecto. Con ello creamos una nueva variable de configuración que guarda la ruta del proyecto, de manera que ahora podemos indicar el resto de rutas de forma relativa a la nueva variable. Además añadimos esta ruta al path de python lo que repercutirá en ventajas futuras.
# Identificando la ruta del proyecto
import os
PROJECT_PATH = os.path.dirname(os.path.realpath(__file__))
Configuramos la base de datos. Usamos sqlite3. También podríamos usar por fácilmente postgresql, mysql y oracle
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3', # Add 'postgresql_psycopg2', 'mysql', 'sqlite3' or 'oracle'.
'NAME': 'mysite.db', # Or path to database file if using sqlite3.
# The following settings are not used with sqlite3:
'USER': '',
'PASSWORD': '',
'HOST': '', # Empty for localhost through domain sockets or '127.0.0.1' for localhost through TCP.
'PORT': '', # Set to empty string for default.
}
}
Otras variables:
TIME_ZONE = 'Europe/Madrid'
LANGUAGE_CODE = 'es-es'
INSTALLED_APPS = (
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.sites',
'django.contrib.messages',
'django.contrib.staticfiles',
# Uncomment the next line to enable the admin:
'django.contrib.admin',
# Uncomment the next line to enable admin documentation:
'django.contrib.admindocs',
# Esta es la aplicación que estamos haciendo
'mysite',
)
Aplicaciones instaladas INSTALLED_APPS: Un proyecto en Django necesita de aplicaciones, algunas ya vienen configuradas de manera predeterminada. En nuestro proyecto usaremos la aplicación de administración y su documentación, estas ya vienen construidas, y también nuestra primera aplicación creada líneas arriba, llamada principal. Para habilitar estas aplicaciones debemos buscar la siguiente sección que se encuentra casi al final del archivo settings.py. Django tendra que crear las tablas de estas aplicaciones adames de las que necesite nuestra propia aplicación mysite.
El resto de configuraciones se iran modificando a medida que lo necesitemos.
Creación de la base de datos. (Ojo, si no esta cargado el envairoment no funcionara):
(env)verdor@enlamina ~/src/entorno/mysite$ python -c "import django; print(django.get_version())" # Prueba
1.5
verdor@enlamina ~/src/entorno/mysite$ source ../env/bin/activate # Si falla lo cargamos así
(env)verdor@enlamina ~/src/entorno/mysite$ python manage.py sync #Creación BD
Creating tables ...
Creating table auth_permission
Creating table auth_group_permissions
Creating table auth_group
Creating table auth_user_groups
Creating table auth_user_user_permissions
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): yes
Username (leave blank to use 'verdor'):
Email address:
Password:
Password (again):
Superuser created successfully.
Installing custom SQL ...
Installing indexes ...
Installed 0 object(s) from 0 fixture(s)
Configuramos las direcciones/rutas del proyecto. Fichero urls.py. Es solo descomentar algunas lineas:
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'^$', 'mysite.views.home', name='home'),
#url(r'^mysite/', include('mysite.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)),
)
Arrancamos el servidor y ya podemos ir a la zona de administración http://127.0.0.1:8000/admin
(env)verdor@enlamina ~/src/entorno/mysite$ python manage.py runserver
Este es un buen momento usar git y hacer un comit inicial y montar un repositorio en github
? Antes de seguir. Lo que hemos hecho es crear un proyeco. Un proyecto puede estar compuesto de múltiples aplicaciones (ejemplo las que vienen por defecto en INSTALLED_APPS), y una aplicación se puede integrar en múltiples proyectos.
Creamos una aplicación:
Vamos a realizar un blog
verdor@enlamina ~$ ~/src/entorno/mysite$ source ../env/bin/activate #Cargamos el entorno
(env)samu@sub ~/src/entorno/mysite$ python manage.py startapp blog #Creamos al aplicacion
Ahora tenemos los siguientes ficheros:
mysite/
manage.py
blog/
__init__.py
models.py
tests.py
views.py
mysite/
__init__.py
settings.py
urls.py
wsgi.py
Comenzamos con el modelo (ejemplo 1, ejemplo 2) (ORM). Editamos models.py:
from django.db import models
# Create your models here.
class Category(models.Model):
name = models.CharField(max_length=200)
class Post(models.Model):
title = models.CharField(max_length=200)
content = models.TextField()
category = models.ForeignKey(Category)
creation_date = models.DateTimeField(auto_now_add=True)
Antes de probar el modelo, hay que incluir la aplicación blog en el proyecto editando mysite/setting.py
INSTALLED_APPS = (
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.sites',
'django.contrib.messages',
'django.contrib.staticfiles',
# Uncomment the next line to enable the admin:
'django.contrib.admin',
# Uncomment the next line to enable admin documentation:
'django.contrib.admindocs',
# Esta es el proyecto
'mysite',
# Esta es aplicación
'blog',
)
Una vez hecho esto ejecutamos el siguiente comando y comprobamos que se generan las consultas esperadas:
(env)verdor@enlamina ~/src/entorno/mysite$ python manage.py sqlall blog
BEGIN;
CREATE TABLE "blog_category" (
"id" integer NOT NULL PRIMARY KEY,
"name" varchar(200) NOT NULL
)
;
CREATE TABLE "blog_post" (
"id" integer NOT NULL PRIMARY KEY,
"title" varchar(200) NOT NULL,
"content" text NOT NULL,
"category_id" integer NOT NULL REFERENCES "blog_category" ("id"),
"creation_date" datetime NOT NULL
)
;
CREATE INDEX "blog_post_6f33f001" ON "blog_post" ("category_id");
COMMIT;
Ahora creamos las tablar realmente:
(env)verdor@enlamina ~/src/entorno/mysite$ python manage.py syncdb
Creating tables ...
Creating table blog_category
Creating table blog_post
Installing custom SQL ...
Installing indexes ...
Installed 0 object(s) from 0 fixture(s)
Toca el momento de crear las vistas. Editamos blog/views.py e importamos los modelos que vayamos a utilizar:
# Create your views here.
from django.shortcuts import render_to_response
from blog.models import Category
from blog.models import Post
Tambien en blog/views.py añadiremos las funciones que gestionan las peticiones que se hagan al servidor. Algo así como los controladores de RoR.
# Create your views here.
from django.shortcuts import render_to_response
from blog.models import Category
from blog.models import Post
# Vista para un post
# Show
# template/post.html
def one_post(request, idpost):
post = Post.objects.get(id=idpost)
return render_to_response(
"post.html",
{
"post":post,
},
)
# Vista de un listado de posts
# Index
#template/home.html
def home(request):
posts = Post.objects.order_by("-creation_date")
return render_to_response(
"home.html",
{
"posts":posts,
},
)
# Vista de un listado de posts filtrado por category
#template/home.html
def posts_by_category(request, idcategory):
category = Category.objects.get(id=idcategory)
posts = category.post_set.order_by("-creation_date")
return render_to_response(
"home.html",
{
"posts":posts,
},
)
Ahora creamos las plantillas. Lo que en RoR serian las vistas. Se estarán en la carpeta blog/templates/
Creamos blog/templates/base.html. Se usará de base para generar el resto de las plantillas. Las plantillas heredarán de base.html, y a través de etiqueta block base.html mostrara el código de las plantillas que hereden de esta:
#blog/templates/base.html
<!DOCTYPE html>
<html>
<head>
<title>{% block title %}{% endblock %}</title>
</head>
<body>
{% block content %}{% endblock %}
</body>
</html>
Creamos post.html
{% extends "base.html" %}
{% block title %}
{{ post.title }}
{% endblock %}
{% block content %}
<h1>{{ post.title }}</h1>
<p>{{ post.content }}</p>
{% endblock %}
home.html
{% extends "base.html" %}
{% block title %}Mi blog{% endblock %}
{% block content %}
{% for post in posts %}
<h1>{{ post.title }}</h1>
<p>{{ post.content }}</p>
<hr>
{% endfor %}
{% endblock %}
Tenemos que indicar en al proyecto donde estan las plantillas, editamos TEMPLATE_DIRS de mysite/settinds.py :
TEMPLATE_DIRS = (
# Put strings here, like "/home/html/django_templates" or "C:/www/django/templates".
# Always use forward slashes, even on Windows.
# Don't forget to use absolute paths, not relative paths.
"../blog/templates",
)
Nos quedan crear las URLs de la aplicacion (las rutas). Lo primero indicar al proyecto que busque las URLs de la aplicacion blog. Editamos mysite/urls.py e indicamos que incluya las rutas de blog. Quedaria asi:
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'^$', 'mysite.views.home', name='home'),
#url(r'^mysite/', include('mysite.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)),
# Rutas de la aplicacion blog
url(r'^', include('blog.urls')),
)
Ahora crearemos un fichero blog/urls.py de la aplicación. Debe quedar así:
from django.conf.urls import patterns, include, url
urlpatterns = patterns('',
url(
r'^post/(?P[0-9]+)/$',
'blog.views.one_post',
name="one_post"),
url(
r'^category/(?P[0-9]+)/$',
'blog.views.posts_by_category',
name="posts_by_category"),
url(
r'^$',
'blog.views.home',
name='home'),
)
Por último vamos hacer accesibles nuestro modelos den blog desde el panel de adminición. Para ello vamos a añadir un fichero admin.py en el directorio blog indicándoselo. Debería quedar así:
from django.contrib import admin
from blog.models import Category
from blog.models import Post
admin.site.register(Post)
admin.site.register(Category)
Símplemente registramos los modelos en el panel de administración. Por último, vamos a ejecutar de nuevo el comando para sincronizar la base de datos, ya que Django Admin añadirá alguna tabla más:
(env)verdor@enlamina ~/src/entorno/mysite$ python manage.py syncdb
Creating tables ...
Installing custom SQL ...
Installing indexes ...
Installed 0 object(s) from 0 fixture(s)
(env)verdor@enlamina ~/src/entorno/mysite$ python manage.py runserver
Ya podemos introducir algún post por la zona de admin http://localhost:8000/admin/ y luego verlo http://localhost:8000/post/1/
Consola Django
(env)verdor@enlamina ~/src/entorno/mysite$ python manage.py shell
Python 2.7.3 (default, Feb 27 2014, 19:58:35)
[GCC 4.6.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> import django
>>> from blog.models import Post, Category
>>> Category.objects.all()
[, ]
>>> Category.objects.all()[0]
>>> Category.objects.all()[0].id
1
>>> Category.objects.all()[0].name
u'ruby'
>>> Category.objects.all()[1].name
u'lorem'
>>>
Para que la salida de los objetos por la consola sea mas amigable, tendremos que añadir a los modelos los métodos "def __str__(self):" quedando el fichero bog/models.py de esta manera:
from django.db import models
# Create your models here.
class Category(models.Model):
name = models.CharField(max_length=200)
def __str__(self):
return self.name
class Post(models.Model):
title = models.CharField(max_length=200)
content = models.TextField()
category = models.ForeignKey(Category)
creation_date = models.DateTimeField(auto_now_add=True)
def __str__(self):
return '%s %s' % (self.title, self.creation_date)
jueves, 17 de abril de 2014
Raspberry Pi: Desplegando aplicación Rails,RVM,Thin en nginx con Capistrano
Configuración en el servidor:
Instalación de RVM multi-usuario [script]:
pi@raspberrypi ~ $ sudo su
root@raspberrypi:/home/pi# curl -L get.rvm.io | bash -s stable
#source /etc/profile.d/rvm.sh
root@raspberrypi:/home/pi# source /etc/profile
root@raspberrypi:/home/pi# rvm requirements;
root@raspberrypi:/home/pi# apt-get install build-essential openssl libreadline6 libreadline6-dev curl git-core zlib1g zlib1g-dev libssl-dev libyaml-dev libsqlite3-dev sqlite3 libxml2-dev libxslt-dev autoconf libc6-dev ncurses-dev automake libtool bison subversion pkg-config
root@raspberrypi:/home/pi# rvm install 2.0.0
Tenemos que instalar Nginx. Esta explicado en la anterior entrada: Cambiando Apache por Nginx
Vamos a crear el usuario que realizara los deploy de capistrano. El aprovechamos para crear con un home diferente /var/deploy y alojar ahí las aplicaciones. Luego bloqueamos la contraseña, solo podremos logarnos y deployar a través de ssh.
root@raspberrypi:/home/pi# adduser --home /var/deploy deploy
root@raspberrypi:/home/pi# passwd -l deploy
Nos vamos ponernos como usuario deploy y lo configuramos para poder autenticarnos por ssh como el usuario deploy (explicado en entrada anterior):
root@raspberrypi:/home/pi# su - deploy
deploy@raspberrypi ~ $ pwd #comprobamos donde estamos y si es igual al HOME esperado
/var/deploy
deploy@raspberrypi ~ $ mkdir .ssh
deploy@raspberrypi ~ $ vim .ssh/authorized_keys #introducimos la llave publica a autorizar
Vamos a crear el gemset de nuestra aplicación y como instalaríamos thin:
deploy@raspberrypi ~ $ rvm use 2.0.0@showip --create
deploy@raspberrypi ~ $ rvm gemset create showip
deploy@raspberrypi ~ $ # gem install thin
Configuración en nuestra aplicación (entorno de desarrollo):
En el Gemfile añadimos capistrano y thin [ejemplo thin, ejemplo unicorn]:
# Use Capistrano for deployment
group :development do
gem 'capistrano'
gem "rvm-capistrano"
end
# Use Thin for production
gem 'thin', group: :production
Si no tenemos instalado ningún motor de Javascript en el servidor, tenemos que descomentar también la linea de therubyracer. Otra opción, instalar en el servidor nodejs.
Ejecutamos un bundle y comando para crear ficheros de capistrano:
$ bundle install
$ capify .
[add] writing './Capfile'
[add] writing './config/deploy.rb'
[done] capified!
Configuramos el fichero de /config/deploy.rb, (lo creamos si es necesario). En mi caso queda así:
require "rvm/capistrano"
#require "capistrano/ext/multistage"
require "bundler/capistrano"
#set :stages, %w(staging production) #Si queremos mas de un entorno
set :application, "showip"
set :repository, "git@github.com:verdor/showip.git"
default_run_options[:pty] = true
ssh_options[:forward_agent] = true
# la versión de ruby tiene que estar instalada y el gemset existir
# antes del cap deploy:setup
set :rvm_ruby_string, 'ruby-2.0.0-p451@showip'
set :rvm_type, :system
set :scm, :git
set :git_shallow_clone, 1
server "192.168.1.10", :app, :web, :db, primary: true
#server "showip.tk", :app, :web, :db, primary: true
set :user, "deploy"
set :keep_releases, 5
set :use_sudo, false
#set :port, 22 #sustituye con el puerto que usas
# Capistrano's default location "/u/apps/#{application}"
set :deploy_to, "/var/#{user}/apps/#{application}"
set :deploy_via, :remote_cache
set :branch, "master"
after "deploy:finalize_update" , "symlinks"
after "deploy", "deploy:cleanup"
namespace :deploy do
desc "Despues de ejecutar el setup subimos ficheros de configuracion"
task :setup_config, roles: :app do
#run "mkdir #{shared_path}/config"
#run "#{try_sudo} mkdir #{shared_path}/config"
top.upload("config/nginx.conf", "#{shared_path}/nginx.conf", via: :scp)
top.upload("config/thin_config.yml", "#{shared_path}/thin_config.yml", via: :scp)
top.upload("config/database.yml", "#{shared_path}/database.yml", via: :scp)
#top.upload(".rvmrc", "#{shared_path}/.rvmrc", via: :scp)
top.upload(".versions.conf", "#{shared_path}/.versions.conf", via: :scp)
#sudo "mv #{shared_path}/config/nginx.conf /etc/nginx/sites-available/showip"
#sudo "ln -nfs /etc/nginx/sites-available/showip /etc/nginx/sites-enabled/showip"
end
after "deploy:setup", "deploy:setup_config"
end
task :symlinks, roles: [:app] do
run <<-CMD
ln -s #{shared_path}/cache #{release_path}/public/;
ln -s #{shared_path}/database.yml #{release_path}/config/;
ln -s #{shared_path}/thin_config.yml #{release_path}/config/;
ln -s #{shared_path}/.versions.conf #{release_path}/;
CMD
end
namespace :deploy do
desc "Start the Thin processes"
task :start do
run <<-CMD
cd #{current_path}; bundle exec thin start -C config/thin_config.yml
CMD
end
desc "Stop the Thin processes"
task :stop do
run <<-CMD
cd #{current_path}; bundle exec thin stop -C config/thin_config.yml
CMD
end
desc "Restart the Thin processes"
task :restart do
run <<-CMD
cd #{current_path}; bundle exec thin restart -C config/thin_config.yml
CMD
end
end
Un a vez hecho esto, queremos ver el listado de tareas capistrano:
verdor@enlamina ~$ cap -T
Creamos el fichero de configuración del servidor en nginx para nuestra aplicación:
upstream showip {
server 127.0.0.1:3000;
}
server {
listen 80;
server_name showip.pi showip.jeronima.tk showip.tk;
root /var/deploy/apps/showip/current/public/;
access_log /var/log/nginx/showip-access.log;
error_log /var/log/nginx/showip-error.log;
rewrite_log on;
location ~ ^/assets/ {
root /var/deploy/apps/showip/current/public;
gzip_static on;
expires 1y;
add_header Cache-Control public;
add_header ETag "";
break;
}
location / {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
client_max_body_size 10m;
client_body_buffer_size 128k;
proxy_connect_timeout 90;
proxy_send_timeout 90;
proxy_read_timeout 90;
proxy_buffer_size 4k;
proxy_buffers 4 32k;
proxy_busy_buffers_size 64k;
proxy_temp_file_write_size 64k;
proxy_redirect off;
if (!-f $request_filename) {
proxy_pass http://showip;
break;
}
}
if (-f $document_root/system/maintenance.html) {
return 503;
}
error_page 503 @maintenance;
location @maintenance {
rewrite ^(.*)$ /system/maintenance.html last;
break;
}
error_page 500 502 503 504 /50x.html;
}
Escribimos nuestro fichero de configuracion del thin, pero al final no lo usamos y lo generamos con thin en el propio servidor, probar ejecutando thin -h:
---
chdir: /var/deploy/apps/showip/current
environment: production
address: 0.0.0.0
port: 3000
timeout: 30
log: /var/deploy/apps/showip/current/log/thin.log
pid: /var/deploy/apps/showip/current/tmp/pids/thin.pid
max_conns: 1024
max_persistent_conns: 100
require: []
wait: 30
threadpool_size: 20
servers: 1
user: deploy
group: deploy
daemonize: true
Ahora tenemos que preparar el servidor con capistrano:
verdor@enlamina ~$ cap deploy:update
verdor@enlamina ~$ cap deploy:start
* Ojo, la aplicación no tiene base de datos, ni asset.
Más configuración en el servidor. WRAPPERS. Que wrappers.
Queremos que nuestra aplicación se inicie como un servicio más (init.d):
pi@raspberrypi ~ $ sudo su
root@raspberrypi:/home/pi# source /etc/profile #cargamos rvm
root@raspberrypi:/home/pi# rvm use ruby-2.0.0-p451@showip
root@raspberrypi:/home/pi# thin install
Installing thin service at /etc/init.d/thin ...
mkdir -p /etc/init.d
writing /etc/init.d/thin
chmod +x /etc/init.d/thin
mkdir -p /etc/thin
To configure thin to start at system boot:
on RedHat like systems:
sudo /sbin/chkconfig --level 345 thin on
on Debian-like systems (Ubuntu):
sudo /usr/sbin/update-rc.d -f thin defaults
on Gentoo:
sudo rc-update add thin default
Then put your config files in /etc/thin
Genera el el fichero /etc/init.d/thin, mostramos como se crea, pero luego lo renombraremos y editaremos:
#!/bin/sh
### BEGIN INIT INFO
# Provides: thin
# Required-Start: $local_fs $remote_fs
# Required-Stop: $local_fs $remote_fs
# Default-Start: 2 3 4 5
# Default-Stop: S 0 1 6
# Short-Description: thin initscript
# Description: thin
### END INIT INFO
# Original author: Forrest Robertson
# Do NOT "set -e"
DAEMON=/usr/local/rvm/gems/ruby-2.0.0-p451@showip/bin/thin
SCRIPT_NAME=/etc/init.d/thin
CONFIG_PATH=/etc/thin
# Exit if the package is not installed
[ -x "$DAEMON" ] || exit 0
case "$1" in
start)
$DAEMON start --all $CONFIG_PATH
;;
stop)
$DAEMON stop --all $CONFIG_PATH
;;
restart)
$DAEMON restart --all $CONFIG_PATH
;;
*)
echo "Usage: $SCRIPT_NAME {start|stop|restart}" >&2
exit 3
;;
esac
:
Si vamos a tener más de una aplicación que use thin, renombramos el fichero /etc/init.d/thin, en nuestro caso por /etc/init.d/showip y modificamos...
SCRIPT_NAME=/etc/init.d/showip
CONFIG_PATH=/etc/showip #var/deploy/showip
Lo renombramos y ponemos en el arranque:
root@raspberrypi:~# mv /etc/init.d/thin /etc/init.d/showip
root@raspberrypi:~# sudo /usr/sbin/update-rc.d -f showip defaults
Generamos la configuracion del thin para nuestra aplicacion showip
root@raspberrypi:~# thin config -C /etc/thin/showip.yml -c /var/deploy/apps/showip/current --servers 1 -p 3000
Wrote configuration to /etc/thin/showip.yml
Editamos el fichero del config /etc/thin/showip.yml para ver si le damos algun retoque:
---
chdir: /var/deploy/apps/showip/current
environment: production
address: 0.0.0.0
port: 3000
timeout: 30
log: log/thin.log
pid: /var/deploy/apps/showip/current/tmp/pids/thin.pid
max_conns: 1024
max_persistent_conns: 100
require: []
wait: 30
threadpool_size: 20
servers: 1
user: deploy
group: deploy
daemonize: true
Generamos el wrapper de RVM ya que la ruta /usr/local/rvm/gems/ruby-2.0.0-p451@showip/bin/thin no nos acaba de funcionar, despues editaremos de forma definitiva /etc/init.d/showip
root@raspberrypi:~# rvm wrapper ruby-2.0.0-p451@showip showip thin
Regenerating ruby-2.0.0-p451@showip wrappers.........
Comprobamos que se ha generado (es un enlace blando):
root@raspberrypi:~# ls /usr/local/rvm/bin/ | grep showip
showip_thin
Podemos probarlo y si hay algun fallo en el fichero de configuracion, nos lo dira:
root@raspberrypi:~# /usr/local/rvm/bin/showip_thin start -C /etc/thin/showip.yml
/usr/local/rvm/rubies/ruby-2.0.0-p451/lib/ruby/2.0.0/psych.rb:205:in `parse': (/etc/thin/showip.yml): could not find expected ':' while scanning a simple key at line 15 column 1 (Psych::SyntaxError)
#o funcionara
Starting server on 0.0.0.0:3000 ...
root@raspberrypi:~# /usr/local/rvm/bin/showip_thin stop -C /etc/thin/showip.yml
Stopping server on 0.0.0.0:3000 ...
Sending QUIT signal to process 3001 ...
Exiting!
Ya generado el wrapper editamos /etc/init.d/showip dejandolo como queda:
#!/bin/sh
### BEGIN INIT INFO
# Provides: thin
# Required-Start: $local_fs $remote_fs
# Required-Stop: $local_fs $remote_fs
# Default-Start: 2 3 4 5
# Default-Stop: S 0 1 6
# Short-Description: thin initscript
# Description: thin
### END INIT INFO
# Original author: Forrest Robertson
# Do NOT "set -e"
DAEMON=/usr/local/rvm/bin/showip_thin
SCRIPT_NAME=/etc/init.d/showip
CONFIG_PATH=/etc/thin/showip.yml
#chown=/bin/chown
#mkdir=/bin/mkdir
# Exit if the package is not installed
[ -x "$DAEMON" ] || exit 0
case "$1" in
start)
$DAEMON start -C $CONFIG_PATH
;;
stop)
$DAEMON stop -C $CONFIG_PATH
;;
restart)
$DAEMON restart -C $CONFIG_PATH
;;
*)
echo "Usage: $SCRIPT_NAME {start|stop|restart}" >&2
exit 3
;;
esac
:
Los fichero creados los ponemos como propiedad del usuario deploy:
chown deploy:deploy /etc/init.d/showip
Hacemos una pruaba antes de reiniciar y ver que arranca la aplicación:
pi@raspberrypi ~ $ sudo service showip start
Starting server on 0.0.0.0:3000 ...
Ya podemos ir desarrollando, subir al repositorio y hacer deploy con las ultimas versiones del código.
verdor@enlamina$ cap deploy
Tendríamos que dar algunos retoques si tuviéramos mas de un entrono (entorno de pruebas) y la aplicación necesitase de base de datos, etc...
Enlaces:
miércoles, 16 de abril de 2014
Tips Linux
df -h
Conocer espacio ocupado de cache apt:
du -sh /var/cache/apt/archives
Elimina del cache los paquetes .deb con versiones anteriores a los de los programas que tienes instalados:
sudo apt-get autoclean
sudo apt-get clean #Elimina todos los paquetes del cache.
sudo apt-get autoremove #Borra los paquetes huérfanos
Ver RAM ocupada en megas y SWAP:
free -m -t
Lista de procesos que se están ejecutando:
top
Cuanto tiempo lleva arrancada su máquina:
uptime
Ejecuta un script/programa en el arranque:
sudo vi /etc/init.d/miscript #creamos script
sudo chmod 755 /etc/init.d/miscript #le damos permisos de ejecución
sudo /etc/init.d/miscript start #lo probamos
sudo /etc/init.d/miscript stop #lo paramos
sudo update-rc.d miscript defaults #lo metemos en el arranque
sudo update-rc.d -f miscript remove #cuando lo queramos eliminar del arranque
Instalar servidor escritorio remoto
sudo apt-get install xrdp
Instalar cliente escritorio remoto
sudo aptitude install remmina remmina-gnome