User Tools

Site Tools


informatica:linux:django

Django

django python framework

Instalacion

1. Instalar pip

sudo aptitude update; sudo aptitude install python-pip

2. Instalar ultima version de django:

sudo pip install Django==1.8

Primeros pasos

/srv/www/docroot

1. Crear proyecto:

django-admin.py startproject project1
└── project1
    ├── manage.py
    └── project1
        ├── __init__.py
        ├── settings.py
        ├── urls.py
        └── wsgi.py

2. Motor SGBD

vim settings.py

3. Crear aplicacion:

cd project
python manage.py startapp app1
├── app1
│   ├── admin.py
│   ├── __init__.py
│   ├── models.py
│   ├── tests.py
│   └── views.py
├── manage.py
└── project1
    ├── __init__.py
    ├── __init__.pyc
    ├── settings.py
    ├── settings.pyc
    ├── urls.py
    └── wsgi.py

4. Crear modelos:

A mano:

vim app1/models.py

O 'extraerlo' de una bd ya existente. Luego hay que pulir un poco:

python manage.py inspectdb >> app1/models.py

5. Activar modelo (seccion 'INSTALLED_APPS')

vim settings.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',
    'app1',
)

6. Crear bd y tablas:

python manage.py syncdb

7. Ingesta:

python manage.py loaddata app1/sql/regional.csv.json

8. Arrancar el servido:

python manage.py runserver 0.0.0.0:8080

Interfaz administrativa

Ahora la interfaz administrativa se activa por defecto

Crear superusuario

(Deprecated) Activar la interfaz administrativa

1

vim settings.py

Descomentar 'django.contrib.admin' en 'INSTALLED_APPS'

2

python manage.py syncdb

3

vim urls.py

Descomentar las siguientes lineas:

from django.contrib import admin
admin.autodiscover()

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

(Deprecated) Activar la interfaz administrativa en app1 y tabla 'Tabla1'

2.1 Crear:

vim app1/admin.py

Con el siguiente contenido:

from app1.models import Tabla1
from django.contrib import admin

admin.site.register(Tabla1)

Django + nginx

1. Instalar paquetes:

sudo aptitude install python-flup nginx

2. Configurar nginx:

sudo mv /etc/nginx/nginx.conf /etc/nginx/nginx.conf.old
sudo vim /etc/nginx/nginx.conf
user javi javi;

worker_processes  2;

error_log /var/log/nginx/error_log info;

events {
    worker_connections  1024;
    use epoll;
}

http {
    include     /etc/nginx/mime.types;
    default_type    application/octet-stream;

    log_format main
        '$remote_addr - $remote_user [$time_local] '
            '"$request" $status $bytes_sent '
        '"$http_referer" "$http_user_agent" '
        '"$gzip_ratio"';

    client_header_timeout   10m;
    client_body_timeout 10m;
    send_timeout        10m;

    connection_pool_size        256;
    client_header_buffer_size   1k;
    large_client_header_buffers 4 2k;
    request_pool_size       4k;

    gzip on;
    gzip_min_length 1100;
    gzip_buffers    4 8k;
    gzip_types  text/plain;

    output_buffers  1 32k;
    postpone_output 1460;

    sendfile    on;
    tcp_nopush  on;
    tcp_nodelay on;

    keepalive_timeout   75 20;

    ignore_invalid_headers  on;
    index index.html;

server {
        listen 80;
        server_name localhost;
        location /media {
            root /srv/test.facsimile/branches/1.1/proyecto2/media;
        }
        location ~* ^.+\.(jpg|jpeg|gif|png|ico|css|zip|tgz|gz|rar|bz2|doc|xls|exe|pdf|ppt|txt|tar|mid|midi|wav|bmp|rtf|js|mov) {
            access_log   off;
            expires      30d;
        }
        location / {
            # host and port to fastcgi server
            fastcgi_pass 0.0.0.0:8080;
            fastcgi_param PATH_INFO $fastcgi_script_name;
            fastcgi_param REQUEST_METHOD $request_method;
            fastcgi_param QUERY_STRING $query_string;
            fastcgi_param CONTENT_TYPE $content_type;
            fastcgi_param CONTENT_LENGTH $content_length;
            fastcgi_pass_header Authorization;
            fastcgi_intercept_errors off;
            }
        access_log  /var/log/nginx/localhost.access_log main;
        error_log   /var/log/nginx/localhost.error_log;
    }
}

Parametros a cambiar:

-Usuario que ejecuta nginx:

user javi javi;

-(Opcional) ruta a directorios multimedia (se puede eliminar)

        server_name localhost;
        location /media {
            root /srv/test.facsimile/branches/1.1/proyecto2/media;
        }

- Direccion ip y puerto en el que escucha django

fastcgi_pass 0.0.0.0:8080;

3. Arrancar django

Suponiendo que el directorio donde este el proyecto sea '/srv/test.facsimile/branches/1.1/proyecto2/':

cd /srv/test.facsimile/branches/1.1/proyecto2/; python manage.py runfcgi method=threaded host=0.0.0.0 port=8080

4. Arrancar nginx:

sudo /etc/init.d/nginx start

5. Probar:

http://localhost/accion_1

Nginx redirige la peticion a:

http://localhost:8080/accion_1

Archivos estaticos

OJO cuando ejecutamos el servidor de desarrollo, todo funciona magicamente. Pero cuando estamos en produccion probablemente serviremos los archivos desde Apache, lo que requiere configuracion adicional para los archivos estaticos

https://docs.djangoproject.com/en/1.6/howto/static-files/deployment/#serving-the-site-and-your-static-files-from-the-same-server

https://docs.djangoproject.com/en/1.6/howto/deployment/wsgi/modwsgi/#serving-files

1. Creamos el directorio desde donse se van a servir los archivos estaticos. Puede estar fuera del DocumentRoot de Apache

mkdir /tmp/static
 

2. Definir la variable “STATIC_ROOT” en el archivo “settings.py” del proyecto de django:

vim /srv/www/docroot/project1/project1/settings.py

...
STATIC_ROOT = '/tmp/static/'
... 

3. Entramos en el site de django y ejecutamos un comando para copiar todos los archivos estaticos a ese directorio:

cd /srv/www/docroot/project1
python manage.py collectstatic

You have requested to collect static files at the destination
location as specified in your settings.

This will overwrite existing files!
Are you sure you want to do this?

Type 'yes' to continue, or 'no' to cancel: yes
Copying '/usr/local/lib/python2.7/dist-packages/django/contrib/admin/static/admin/css/login.css'
...

Al final tenemos en “/tmp/static” todo un arbol con archivos estaticos (CSS, js, etc…)

4. Anyadir la entrada al VirtualHost de Apache (version < 2.4):

...
        Alias /static/ /tmp/static/
        <Directory /tmp/static>
                # Apache < 2.4
                Order deny,allow
                Allow from all
        </Directory>
...

Para Apache >= 2.4:

...
        Alias /static/ /tmp/static/
        <Directory /tmp/static>
                # Apache >= 2.4
                Require all granted
        </Directory>
...

5. Recargar la configuracion de Apache para que los cambios tomen efecto:

sudo service apache2 reload

Consultas

QuerySet

Tabla1.objects.filter(pub_date__year=2006)

Ejemplo aplicacion sin BBDD

1. Nos metemos dentro de un directorio fuera del docroot de apache:

cd /srv

2. Creamos el proyecto (utilizo sudo porque no tengo permisos en este directorio):

sudo django-admin.py startproject sms_project
sudo chown -R usuario:usuario sms_project

3. Creamos la app:

cd /srv/sms_project
python manage.py startapp sms_app

4. Creamos una vista por defecto (hello world). Editamos:

vim /srv/sms_project/sms_app

Y la dejamos tal que asi:

from django.http import HttpResponse

def index(request):
    return HttpResponse("Hello, world. You're at the sms index.")

5. Creamos una regla para que por defecto todas las peticiones que apunten a 'sms_app' muestren la vista 'index'. Editamos:

vim /srv/sms_project/sms_app/urls.py

Y la dejamos tal que asi:

from django.conf.urls import patterns, url

from sms_app import views

urlpatterns = patterns('',
    url(r'^$', views.index, name='index')
)

6. Creamos una regla para que cuando el servidor web reciba peticiones para “sms_app/” cargue el modulo “/srv/sms_project/sms_app/urls.py”

Editamos:

vim /srv/sms_project/sms_project/urls.py

Y la dejamos tal que asi:

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

urlpatterns = patterns('',
    url(r'^sms_app/', include('sms_app.urls')),
)

7. Arrancamos el servidor de prueba:

cd /srv/sms_project; python manage.py runserver

8. Pedimos una pagina web:

elinks http://localhost:8000/sms/sms_app/

Deberia responder:

Hello, world. You're at the sms index.

Apache mod_wsgi

Configuracion general de apache. Escenario:

/srv/www/docroot Document root
/srv/www/docroot/project1 Proyecto django
/srv/www/docroot/project1/project1/wsgi.py Creado al ejecutar “django-admin.py startproject project_tracker”

1. Instalar libapache2-mod-wsgi:

sudo aptitude update; sudo aptitude install libapache2-mod-wsgi

2. Habilitar modulo:

sudo a2enmod wsgi

3. Deshabilitar sitio por defecto:

sudo a2dissite 000-default 

4. Crear un nuevo sitio:

sudo vim /etc/apache2/sites-available/django 

Y dejarlo tal que asi:

<VirtualHost *:443>
        ServerName django.example.com
        ServerAdmin webmaster@localhost
        DocumentRoot /srv/www/docroot

        SSLEngine on
        SSLCertificateFile    /etc/ssl/certs/ssl-cert-snakeoil.pem
        SSLCertificateKeyFile /etc/ssl/private/ssl-cert-snakeoil.key

        WSGIScriptAlias / /srv/www/docroot/project1/project1/wsgi.py
        WSGIDaemonProcess django.example.com python-path=/srv/www/docroot/project1:/usr/local/lib/python2.7/site-packages
        WSGIProcessGroup django.example.com

        <Directory /srv/www/docroot/project1>
                <Files wsgi.py>
                        Order deny,allow
                        #Require all granted
                        Allow from all
                </Files>
        </Directory>

        ErrorLog ${APACHE_LOG_DIR}/django.example.com.error.log

        # Possible values include: debug, info, notice, warn, error, crit,
        # alert, emerg.
        LogLevel warn

        CustomLog ${APACHE_LOG_DIR}/django.example.com.access.log combined
</VirtualHost>

5. Habilitar el sitio:

sudo a2ensite django

6. Recargar apache:

sudo /etc/init.d/apache2 reload

Base de datos

Lo primero configurar la BD:

vim /srv/www/docroot/project1/project1/settings.py

Y editar las siguientes lineas:

...
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql', # Add 'postgresql_psycopg2', 'mysql', 'sqlite3' or 'oracle'.
        'NAME': 'django',                      # Or path to database file if using sqlite3.
        'USER': 'asterisk',                      # Not used with sqlite3.
        'PASSWORD': 'xxxxxx',                  # Not used with sqlite3.
        'HOST': 'mysql-1.dev.jj.com',                      # Set to empty string for localhost. Not used with sqlite3.
        'PORT': '',                      # Set to empty string for default. Not used with sqlite3.
    }
}
...

Flujo habitual para mantener el modelo:

1. Change your models (in **models.py**).
2. Run **python manage.py makemigrations** to create migrations for those changes
3. Run **python manage.py migrate** to apply those changes to the database.

django -> SGBD

Crea BBDD y las tablas a partir del modelo. Si 'model.py' no existe y se habilita el sistema de autenticacion de Django creara unas tablas:

cd /srv/sms_project; python manage.py syncdb
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

Crear cuenta superusuario:

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 'usuario'): 
E-mail address: javi@legido.com
Password: 
Password (again): 
Superuser created successfully.

SGBD -> django

AVISO: sobreescribiremos el archivo ya existente. Si queremos crear el modelo a partir de una BBDD que ya exista:

cd /srv/www/docroot/project1; python manage.py inspectdb >> app1/models.py

NOTA: si la BBDD es muy compleja probablemente habra que retocar 'model.py' (tipicamente cambiar el orden de las clases)

Django API

cd /srv/sms_project; python manage.py shell

Autenticacion

Templates

1. Incluir la app en settings:

vim /srv/www/docroot/project1/project1/settings.py

Y anyadir la siguiente linea en “INSTALLED_APPS”:

INSTALLED_APPS = (
    ...
    'app1',
)

2. Ejemplo de uso:

/srv/www/docroot/project1/app1/views.py
def invoice_query(request):
    ...
    return render_to_response('template1.html',d,\
                                            context_instance=RequestContext(request))

Que tomara la plantilla de la siguiente ruta:

/srv/www/docroot/project1/app1/templates/template1.html

Internacionalizacion

Flujo de trabajo tipico

https://docs.djangoproject.com/en/1.6/topics/i18n/translation/#url-internationalization

  • Estructura de archivos implicados en la internacionalizacion:
.
+-- project1
|   +-- __init__.py
|   +-- settings.py
|   +-- urls.py
|   +-- wsgi.py
+-- app1
|   +-- admin.py
|   +-- forms.py
|   +-- __init__.py
|   +-- locale
|   |   +-- es
|   |       +-- LC_MESSAGES
|   |           +-- django.mo
|   |           +-- django.po
|   +-- models.py
|   +-- tests.py
|   +-- urls.py
|   +-- views.py
+-- manage.py

1) Requisitos para habilitar internacionalizacion:

project1/settings.py

...
INSTALLED_APPS = (
...
'app1',
)
MIDDLEWARE_CLASSES = (
    ...
    'django.middleware.locale.LocaleMiddleware',
)
USE_I18N = True
USE_L10N = True

2. Crear translation strings con el identificador que se va a usar luego en los message file (uno por cada idioma) para traducir la cadena.

  • Ejemplo de uso en vista (translation string “hello_world”). Hemos usado el alias _, muy usado:
app1/views.py

from django.template import RequestContext
from django.shortcuts import render_to_response
from django.http import HttpResponseRedirect, HttpResponse
from django.utils.translation import ugettext as _

def test(request, ):
    output = _("hello_world"),' - ',  request.LANGUAGE_CODE
    return HttpResponse(output)
  • Ejemplo de uso en template (translation string “hello_world”):
{% load i18n %}

{% trans "hello_world" as hello_world %}

<p>{{ hello_world }}</p>

3. Crear la estructura de directorios (el archivo .po de momento no hace falta) adecuados (ver arbol al inicio de esta seccion). Por ejemplo:

mkdir -p locale/es/LC_MESSAGES

4. Crear de forma automatica los message files para todas las lenguas que tienen directorio:

django-admin.py makemessages -a
processing locale en
processing locale es
processing locale ca

5. Ahora tenemos los .po creados de forma automatica para todos los idiomas, cada uno de los cuales con sus trasnlation string. Ahora tenemos que completar el campo “msgstr” para cada una de las translation string con la traduccion. Ejemplo de archivo .po:

app1/locale/es/LC_MESSAGES/django.po

# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2014-02-18 08:58+0100\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"

#: views.py:43
msgid "hello_world"
msgstr "Hola mundo"

TODO: eliminar las lineas que contengan la palabra fuzzy

6. Una vez editados los .po para generar los binarios, los .mo:

django-admin.py compilemessagesprocessing file django.po in /srv/www/incasol/incasolproj/invoices/locale/en/LC_MESSAGES
processing file django.po in /srv/www/project/project/app/locale/es/LC_MESSAGES
processing file django.po in /srv/www/project/project/app/locale/ca/LC_MESSAGES

IMPORTANTE: tras compilar mensajes hay que reiniciar el servidor de paginas web para que los cambios tomen efecto

7. Reiniciar el servidor de paginas web para que tome los cambios efectuados en los archivos .po

Vista ya creada para cambiar el idioma

En este ejemplo cambiamos el lenguaje en una vista en funcion de un parametro que llega via GET:

http://example.com?newLang=ca

app1/views.py
from django.template import RequestContext
from django.shortcuts import render_to_response
from django.http import HttpResponseRedirect, HttpResponse
from invoices.models import Expedient, RawSqlQueries
from forms import InvoiceForm
from django.utils.translation import ugettext as _, activate

def test(request):
    lang = request.GET.get('newLang')
    activate(lang)
    output = _("Hello"),' - ',  request.LANGUAGE_CODE, ' - ',\
             request.session['django_language']
    return HttpResponse(output)

Sesiones

https://docs.djangoproject.com/en/dev/topics/http/sessions/

  • En archivos
docroot/project1/project1/settings.py
SESSION_ENGINE = "django.contrib.sessions.backends.file"

Para saber el directorio por defecto donde almacena los archivos temporales, siempre que 'SESSION_FILE_PATH' NO se haya especificado:

python -c "import tempfile; print tempfile.gettempdir()"

LDAP

pythonhosted.org/django-auth-ldap

1. Instalar modulo:

sudo aptitude install python-ldap
sudo pip install django-auth-ldap

2. Editar settings:

docroot/project1/project1/settings.py

# LDAP
import ldap
from django_auth_ldap.config import LDAPSearch
AUTHENTICATION_BACKENDS = (
    'django_auth_ldap.backend.LDAPBackend',
)
AUTH_LDAP_SERVER_URI = "ldaps://ldap.example.com"
AUTH_LDAP_BIND_DN = "cn=readonly,dc=example,dc=com"
AUTH_LDAP_BIND_PASSWORD = "secret"
#AUTH_LDAP_START_TLS = True
AUTH_LDAP_USER_SEARCH = LDAPSearch("dc=example,dc=com", ldap.SCOPE_SUBTREE,
                                   "(uid=%(user)s)")
# LDAP groups
from django_auth_ldap.config import LDAPSearch, GroupOfNamesType
AUTH_LDAP_GROUP_SEARCH = LDAPSearch("ou=groups,dc=example,dc=com",
    ldap.SCOPE_SUBTREE, "(objectClass=groupOfNames)"
)
AUTH_LDAP_GROUP_TYPE = GroupOfNamesType()
AUTH_LDAP_REQUIRE_GROUP = "cn=ldapgroup1,ou=groups,dc=example,dc=com"

En este ejemplo nos conectamos via TLS al servidor LDAP “ldap.example.com” y requerimos que el usuario pertenezca al grupo “ldapgroup1”, que es un objeto LDAP de tipo “groupOfNames”

3. Crear el modelo de base de datos, si es que no lo estaba ya:

cd docroot/project1; python manage.py syncdb

Contestar a las preguntas.

TODO: ver si hay alguna forma de evitar este paso, y que se almacenen todos los valores en sesiones. SOLUCION 1: sobreescribir _LDAPUser._get_or_create_user() de “/usr/local/lib/python2.7/dist-packages/django_auth_ldap/backend.py” SOLUCION 2: escribir nuestro propio backend tomando django_auth_ldap como ejemplo

4. Ejemplo de formulario con validacion de usuario:

from django.contrib.auth import authenticate

def login(request):
    ''' Displays/process login form'''
    d = {}
    if request.method == 'POST': # If the form has been submitted...
        d['form'] = LoginForm(request.POST) # A form bound to the POST data
        if d['form'].is_valid(): # All validation rules pass
            # Process the data in form.cleaned_data
            username = d['form'].cleaned_data['username']
            password = d['form'].cleaned_data['password']
            user = authenticate(username=username, password=password)
            if user is not None:
                logger.info(user)
                return HttpResponse('Success')
                if user.is_active:
                    login(request, user)
                    return HttpResponse('Success')
                else:
                    return HttpResponse('Disabled account')
            else:
                return HttpResponse('Invalid login')
        else:
            d['result'] = "There was an error processing the form"
    else:
        d['form'] = LoginForm() # An unbound form
    return render_to_response('login.html',d,\
           context_instance=RequestContext(request))

Falta el template y el resto de la vista. Es solo un ejemplo

Errores

The password is too similar to the username.

En realidad no es un error, es solo para documentar un atajo para evitar esta restricción a la hora de especificar una contraseña para un nuevo usuario desde la interfaz gráfica del módulo admin.

https://stackoverflow.com/a/35330167

1. Crear el usuario desde el admin:

http://localhost:8000/admin/auth/user/add/

2. Iniciar shell

cd /path/django && python manage.py shell

3. Cambiar la contraseña de ese usuario, en este ejemplo “your_user”:

from django.contrib.auth.models import User
user = User.objects.get(username='your_user')
user.set_password('simple')
user.save()

Error al crear app

Comando:

python manage.py startapp app1

Error:

  File "manage.py", line 16
    ) from exc
         ^
SyntaxError: invalid syntax

Solución:

python3 manage.py startapp app1
informatica/linux/django.txt · Last modified: 2019/05/19 16:55 by javi