Autor Tema: [TUTORIAL]Creando un CRUD desde cero con el Framework Django(Python)+AJAX+MySQL  (Leído 21776 veces)

0 Usuarios y 1 Visitante están viendo este tema.

Desconectado edu_guerr

  • Sv Member
  • ***
  • Mensajes: 463
**Estimados, por aquí les dejo este pequeño tutorial que hice conforme voy avanzando ,por si a alguien le sirve, es sobre como crear un CRUD usando Python(Django) AJAX MySQL.

*Es de mencionar que Django posee un sitio de administracion por default, pero puede resultar mas didactico aprender a crearlo por nosotros mismos, asi se comprende mejor la arquitectura MVC y la forma de programacion Web en Python, en la presentacion usando AJAX con conexión a base de datos MySQL.

Recursos:
_________________________________________________________________
Se uso:
*Python 2.6
*Framework Django V.1.0
*MySQL  5.1
Libro de django v.1 | El Libro de Django | python | espanol |  lo pueden encontrar aquí:
http://www.svcommunity.org/forum/programacioacuten/lista-de-recursos/
*Como sugerencia, prefiero usar el Framework en Linux, por la rapida configuracion y que ya tiene instalado Python y MySQL.

Introduccion:
______________________________________________________________
Que es MVC?
Modelo Vista Controlador (MVC) es un patrón de arquitectura de software que separa los datos de una aplicación, la interfaz de usuario, y la lógica de negocio en tres componentes distintos. El patrón de llamada y retorno MVC (según CMU), se ve frecuentemente en aplicaciones web, donde la vista es la página HTML y el código que provee de datos dinámicos a la página. El modelo es el Sistema de Gestión de Base de Datos y la Lógica de negocio, y el controlador es el responsable de recibir los eventos de entrada desde la vista.
Fuente:http://es.wikipedia.org/wiki/Modelo_Vista_Controlador
_______________________________________________________________
Que es un CRUD?
En computación CRUD es el acrónimo de Crear, Obtener, Actualizar y Borrar (del original en inglés: Create, Read, Update and Delete). Es usado para referirse a las funciones básicas en bases de datos o la capa de persistencia en un sistema de software.
Fuente:http://es.wikipedia.org/wiki/CRUD
_____________________________________________________________
Por que un CRUD?
El CRUD esta presente casi siempre en cualquier sistema de usuario normal y siempre en el sistema de usuario administrador, sea este escritorio, Web, sin importar el lenguaje.
_____________________________________________________________
Resumiendo se hara lo siguiente:

*Ejemplo de un modelo sencillo en django.
*Ejemplo de vistas en django
  -Actualizar
  -Eliminar
  -Editar
  -Consultar
*Uso de plantillas en Django con respecto a las vistas.
  -Extendiendo de otras plantillas
  -Uso de validaciones en la plantilla usando django
  -Uso de variables enviadas desde la vista a la plantilla.
-AJAX
  -Validaciones en ajax
  -ajax en consultas,eliminar,actualizacion y edicion de los registros.
*Configurando urls.py para uso  ccs  y Javascript desde Django.

[Las primeras 100 paginas del libro django v.1 abarcan parte de este contenido, pero como ejemplo interesante solo muestra como hacer una consulta a una base de datos y no muestra el uso del Framework con AJAX]
_______________________________________________________________________
Parte del resultado final:

*Haciendo de caso que esta instalado Python,Django, MySQL.

-Creamos un directorio crud_django.

En la consola:
Código: [Seleccionar]
>mkdir crud_django
>cd crud_django
>django-admin.py startproject miproyecto
Crea un directorio 'miproyecto' con la siguiente estructura:
Código: [Seleccionar]
/miproyecto
    /__init__.py
    /manage.py
/settings.py
/urls.py

*Nos cambiamos al directorio 'miproyecto' desde la consola y ejecutamos:
Código: [Seleccionar]
python manage.py runserver
Ya debe estar funcionando el servidor de django.[Este servidor solo procesa una peticion a la vez]
Código: [Seleccionar]
http://localhost:8000/




*CONFIGURANDO LA CONEXION A LA BASE DE DATOS EN EL ARCHIVO 'SETTINGS.PY'[solo se hace una vez y ya!!]

*Quedaria la siguiente configuracion:
Código: [Seleccionar]
DATABASE_ENGINE = 'mysql'           # 'postgresql_psycopg2', 'postgresql', 'mysql', 'sqlite3' or 'ado_mssql'.
DATABASE_NAME = 'bd_prueba'             # Or path to database file if using sqlite3.
DATABASE_USER = 'user'             # Not used with sqlite3.
DATABASE_PASSWORD = 'password'         # Not used with sqlite3.
DATABASE_HOST = ''             # Set to empty string for localhost. Not used with sqlite3.
DATABASE_PORT = '3306'             # Set to empty string for default. Not used with sqlite3.
Una forma para confirmar que la base de datos ha sido bien configurada correctamente es la siguiente, estando en el directorio 'miproyecto', Python nos da la oportunidad de ejecutar el shell dentro del proyecto creado 'miproyecto' y asi interactuar con los archivos creados.

Código: [Seleccionar]
/miproyecto> python manage.py shell

Código: [Seleccionar]
Python 2.6.5 (r265:79063, Jul  5 2010, 11:47:21)
[GCC 4.5.0 20100604 [gcc-4_5-branch revision 160292]] on linux2
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> from django.db import connection
>>> cursor=connection.cursor()
*Si ejecutamos estos comandos y no tenemos ningun problema, es porque tenemos configurada correctamente la base de datos en el archivo 'settings.py'.

*CREANDO LA APLICACION
Código: [Seleccionar]
/miproyecto> python manage.py startapp micrud

*Creara un directorio 'micrud':
Código: [Seleccionar]
/micrud
__init__.py
models.py
views.py

*DEFINIENDO DONDE ESTARAN LAS PLANTILLAS

*Crear el directorio 'templates' en la siguiente ruta:
/crud_django/miproyecto/
Y luego editar  el archivo 'settings.py':
Código: [Seleccionar]
TEMPLATE_DIRS = (
  '/home/eduardo/crud_django/miproyecto/templates',
   # 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.
)
Dentro de  /home/eduardo/crud_django/miproyecto/templates   crearemos los directorios para CCS y Javascript

Código: [Seleccionar]
/templates
/ccs
/js


*CREANDO EL MODELO
En /home/eduardo/crud_django/miproyecto/micrud/models.py
Código: [Seleccionar]
from django.db import models
class Agenda(models.Model):
nombre = models.CharField(maxlength=30)
apellido = models.CharField(maxlength=40)
pais = models.CharField(maxlength=30)
correo = models.EmailField()

def __str__(self):
return ' %s %s' % (self.nombre, self.pais)

En el archivo 'settings.py' , instalando el modelo, agregando la siguiente linea: ''miproyecto.micrud',
donde 'miproyecto' es el nombre de mi proyecto y 'micrud' es el nombre de mi app.

Código: [Seleccionar]
INSTALLED_APPS = (
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.sites',
    'miproyecto.micrud',
)

*Validando la sintaxis del modelo:
Código: [Seleccionar]
crud_django/miproyecto> python manage.py validate
0 errors found.
Si no hay problema..ejecutamos

Código: [Seleccionar]
crud_django/miproyecto> python manage.py sqlall micrud
BEGIN;
CREATE TABLE `micrud_agenda` (
    `id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY,
    `nombre` varchar(30) NOT NULL,
    `apellido` varchar(40) NOT NULL,
    `pais` varchar(30) NOT NULL,
    `correo` varchar(75) NOT NULL
);
COMMIT;

Lo interesante:
-Nos crea una llave primaria por default llamada 'id'.
sqlall no ha tocado o creado aun la base de datos en MySQL, solo muestra como queda CREATE TABLE.

*Creando las tablas de MySQL desde el Framework[Mencionar que ya tengo creada una base de datos llamada bd_prueba que se determino en la configuracion de la base de datos en 'settings.py']

Código: [Seleccionar]
crud_django/miproyecto> python manage.py syncdb
Creating table auth_message
Creating table auth_group
Creating table auth_user
Creating table auth_permission
Creating table django_content_type
Creating table django_session
Creating table django_site
Creating table micrud_agenda
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 'eduardo'): admin
E-mail address: correo@server.com
Password:
Password (again):
Superuser created successfully.
Installing index for auth.Message model
Installing index for auth.Permission model
Loading 'initial_data' fixtures...
No fixtures found.

*Nos crea la tabla
Código: [Seleccionar]
Creating table micrud_agenda
Y un superusers con las tablas de privilegios por si queremos usar el sitio de administracion por default de django, pero este no se explica en este momento.

 
*CREANDO EL CRUD
*Creando la consulta:

-Dentro de /templates/css se ha creado un archivo llamado 'estilo.css' no colocare el codigo porque es bastante.

-Se creara una consulta usando un combo y otra introduciendo el registro a buscar:
Creando el archivo ajax dentro de /templates/js lo llamaremos ajax.js 'function ConsultaFiltrado(Pag,objId,objIdVacio)' se usara para consultar usando el combo o el valor introducido por el usuario.

En el archivo urls.py se debe editar para que django encuentre los archivos ccs y javascript y a la vez defino donde esta las vistas y que funcion de 'views.py' deben ejecutar.

Código: [Seleccionar]
from django.conf.urls.defaults import *
import settings
urlpatterns = patterns('',
(r'^buscar/$','miproyecto.micrud.views.consulta'),
    (r'^combo/$','miproyecto.micrud.views.combo'),
   
    (r'css/(?P<path>.*)$', 'django.views.static.serve',
    {'document_root': settings.STATIC_ROOT   'templates/css'}),
   
    (r'js/(?P<path>.*)$', 'django.views.static.serve',
{'document_root': settings.STATIC_ROOT   'templates/js'}),
    # Example:
    # (r'^miproyecto/', include('miproyecto.foo.urls')),

    # Uncomment this for admin:
#     (r'^admin/', include('django.contrib.admin.urls')),
)

Ahora en 'settings.py' al final del archivo debo agregar la ruta donde estan mis archivs js y css.
Código: [Seleccionar]
STATIC_ROOT = '/home/eduardo/crud_django/miproyecto/'
STATIC_ROOT   'templates/',

http://snatverk.blogspot.com/2011/01/anadir-hoja-de-estilo-en-django.html

ajax.js
Código: [Seleccionar]
/*____________________________________________________________________*/
function objetoAjax(){
        var xmlhttp=false;
        try {
                xmlhttp = new ActiveXObject("Msxml2.XMLHTTP");
        } catch (e) {
                try {
                   xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
                } catch (E) {
                        xmlhttp = false;
                }
        }
        if (!xmlhttp && typeof XMLHttpRequest!='undefined') {
                xmlhttp = new XMLHttpRequest();
        }
        return xmlhttp;
}
/*____________________________________________________________________*/
function ConsultaFiltrado(Pag,objId,objIdVacio){
divVacios=document.getElementById(objIdVacio);
if (document.formulario.q.value=="")
           {
            divVacios.innerHTML ="<div class='mensaje' align='justify'>Complete la informacion</div>"
          }
        else
        {
divResultado = document.getElementById(objId);
valor=document.formulario.q.value
      ajax=objetoAjax();
        ajax.open("GET",Pag "?q=" valor);
        ajax.onreadystatechange=function() {
             if (ajax.readyState==4) {
                        divResultado.innerHTML = ajax.responseText
                        divVacios.innerHTML =""
                }
        }
        ajax.send(null)
   }
}
/*____________________________________________________________________*/

Creando las vistas:
En el archivo views.py:

Código: [Seleccionar]
# Create your views here.
#from django.db.models import Q
from django.shortcuts import render_to_response
from models import Agenda
################################################################################
def consulta(request):
consulta = request.GET.get('q', '')
if consulta:
results=Agenda.objects.filter(pais=consulta).order_by('id')
return render_to_response("consulta.html", { "results": results,"consulta": consulta})
return render_to_response("consulta.html", { "results": [],"consulta": consulta})
##############################################################################
def combo(request):
query = request.GET.get('q', '')
elementos= Agenda.objects.values('pais').distinct()
if query:
results=Agenda.objects.filter(pais=query)
return render_to_response("consulta_combo.html",{"results": results,"query": query,"elementos": elementos} )
return render_to_response("consulta_combo.html",{"results": elementos,"query": query,"elementos": elementos} )
################################################################################
Dentro del diretorio /template crearemos un archivo html que servira de base para todos los demas, se extendera y no sera necesario estar repitiendo codigo en cada archivo:

Lo interesante {% block X%}{% endblock %} puedo definir contenido en “la base” y luego solo “extentenderlo” desde cualquier archivo html con {% extends "base.html" %}

base.html
Código: [Seleccionar]
{# Comentario #}
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
    <head>
        <title>{% block title %}{% endblock %}</title>   
        {% block javascript %}<script language="Javascript" src="/js/scripts.js"></script>{% endblock %}
        {% block ajax %}<script language="Javascript" src="/js/ajax.js"></script>{% endblock %}           
        {% block css %}<link rel="stylesheet" href="/css/estilo.css"  type="text/css"/>{% endblock %}
        <meta name="Title" content="Django[Python]"/>
        <meta name="Author" content="edu_guerr" />
        <meta name="Subject" content="Django[Python]" />
        <meta name="Description" content="Aprendiendo Django[Python]" />
        <meta name="Keywords" content="django,python,programacion" />
        <meta name="Language" content="Spanish" />
        <meta name="Revisit" content="15 days" />
        <meta name="Distribution" content="Local" />
        <meta name="Robots" content="All" />       
    </head>
    <body>
{% block contenido %}
{% block encabezado %}{% endblock%}
{% endblock %}
{% block pie %} <hr><p>Creando un [CRUD] con [Django]</p>{% endblock %}
</body>
</html>

La plantilla para la consulta:

Consulta.html
Código: [Seleccionar]
{% extends "base.html" %}
{% block title %}Django[Python]{% endblock %}
{% block contenido %}
<div id="resultado" >
{% block encabezado %}<h1>Busqueda filtrada</h1>{% endblock%}
<form class='estiloform' name='formulario'  action=""  onsubmit="ConsultaFiltrado('http://localhost:8000/buscar/','resultado','Vacios'); return false">
<div><label for="p">Buscar: </label></div> <div><input type="text" name="q" value="{{ consulta|escape }}"></div>
<div><input type="submit" value="Aceptar"></div>
{% if consulta %}  
   <h1>Resultados para "{{ consulta|escape }}":</h1>
{% if results %}
<table id='tabla_'>
<tr><td>Nombre</td><td>Apellido</td><td>Correo</td><td>Pais</td></tr>
{% for agenda in results %}
<tr><td>{{agenda.nombre|upper}}</td><td >{{agenda.apellido|upper}}</td>
<td>{{agenda.correo|upper}}</td><td >{{agenda.pais|upper}} </td>
</tr>
{% endfor %}
</table>
{% else %}
<div class="mensaje" align="justify">No hay resultados</div>
{% endif %}
{% endif %}
</form>
<div id=Vacios align="center" ></div>
{% endblock %}

La plantilla para la consulta usando el combo:

Consulta_combo.html
Código: [Seleccionar]
{% extends "base.html" %}
{% block title %}Django[Python]{% endblock %}
{% block contenido %}
<div id="resultado" >
{% block encabezado %}<h1>Busqueda filtrada usando combo</h1>{% endblock%}
<form class='estiloform' name='formulario'  action=""  >
<div><label for="q">Buscar: </label></div>
<SELECT NAME="q"  onChange="ConsultaFiltrado('http://localhost:8000/combo/','resultado','Vacios'); return false">
<OPTION VALUE= "" >Seleccione</OPTION>
{% for agenda in elementos %}<OPTION VALUE= '{{agenda.pais}}' >{{agenda.pais}}</OPTION>{% endfor %}
</SELECT>
{% if query %}
<h2>Resultados para "{{ query|escape }}":</h2>
{% if results %}
<table id='tabla_'>
<tr><td>Nombre</td><td>Apellido</td><td>Correo</td><td>Pais</td></tr>
{% for agenda in results %}
<tr><td>{{agenda.nombre|upper}}</td><td >{{agenda.apellido|upper}}</td>
<td>{{agenda.correo|upper}}</td><td >{{agenda.pais|upper}} </td></tr>
{% endfor %}
</table>
{% else %}
<div class="mensaje" align="justify">No hay resultados</div>
{% endif %}
{% endif %}
</form>
<div id=Vacios align="center" ></div>
{% endblock %}
</div>

Código: [Seleccionar]
-  {% extends "base.html" %} extiendo del archivo base.html
-"ConsultaFiltrado('http://localhost:8000/buscar/','resultado','Vacios'); return false" funcion que tengo definia en ajax.js
-onChange="ConsultaFiltrado('http://localhost:8000/combo/','resultado','Vacios'); return false" la misma funcion , solo que se llama desde el combo.


*Inserta unos registros en la base de datos bd_prueba en la tabla micrud_agenda

Y en el navegador:

Código: [Seleccionar]
http://localhost:8000/buscar/

Código: [Seleccionar]
http://localhost:8000/combo

-buscar y combo son los nombrres que se definieron en views.py, aquí hace su trabaja urls.py cuando se llama a 'buscar' o 'combo' define que mostrar.

Resultado: Hasta aqui tenemos una consulta a base de datos MySQL usando el Django AJAX y un poco de estilo:















AGREGAR UN REGISTRO:

La funcion ajax en el archivo ajax.js

Código: [Seleccionar]
function insertar(Pag,objId,objIdVacio) {
        divVacios=document.getElementById(objIdVacio);
        if (document.formulario.nom.value=="" || document.formulario.ape.value=="" || document.formulario.pais.value=="" || document.formulario.correo.value=="")
        {
            divVacios.innerHTML ="<div class='mensaje' align='justify'>Complete la informacion</div>"
        }
        else
        {
divResultado = document.getElementById(objId);
        nom=document.formulario.nom.value
        ape=document.formulario.ape.value
        pais=document.formulario.pais.value
        correo=document.formulario.correo.value
        ajax=objetoAjax();
        ajax.open("GET",Pag "?nom=" nom "&ape=" ape "&pais=" pais "&correo=" correo,true);
        ajax.onreadystatechange=function() {
                if (ajax.readyState==4) {
                        divResultado.innerHTML = ajax.responseText
                        divVacios.innerHTML =""                       
                }
        }
        ajax.send(null)
        }
}

en /templates creando la plantilla:

agregar.html
Código: [Seleccionar]
{% extends "base.html" %}
{% block title %}Django[Python]{% endblock %}
{% block contenido %}
<div id="resultado" >
{% block encabezado %}<h1>Agregar un registro</h1>{% endblock%}
<form  class='estiloform' name='formulario'  action=""  onsubmit="insertar('http://localhost:8000/agregar/','resultado','Vacios'); return false">
<table >
<tr><td><div><label for="q">Nombre:</label></td><td><input type="text" name="nom" value="{{ query|escape }}" onkeypress='return sololetra(event)'></div></td></tr>
<tr><td><div><label for="q">Apellido:</label></td><td><input type="text" name="ape" value="{{ query|escape }}"  onkeypress='return sololetra(event)'></div></td></tr>
<tr><td><div><label for="q">Pais: </label></td><td><input type="text" name="pais" value="{{ query|escape }}"  onkeypress='return sololetra(event)'><div></td></tr>
<tr><td><div><label for="q">Correo: </label></td><td><input type="text" name="correo" value="{{ query|escape }}"><div></td></tr>
<tr><td><div><input type="submit" value="Aceptar"></td><td></div>
<div><input type="reset" value="Limpiar"></div></td></tr></tr><tr>
</table>
</form>
{% if exito %}
<div class="mensaje" align="justify">Registro agregado</div>
{% endif %}
<div id=Vacios align="center" ></div>
{% endblock %}
</div>
-Siempre 'extendiendo' de base.html {% extends "base.html" %}, recordemos que en la base defino donde esta el archivo ajax.js

-onsubmit="insertar('http://localhost:8000/agregar/','resultado','Vacios'); return false funcion insertar que esta en ajax.js

Agregado la vista a views.py, recordemos que en este mismo archivo ya tenemos agragadas las vistas 'combo' y 'buscar'

Código: [Seleccionar]
def agregar_registro(request):
nom = request.GET.get('nom','')
ape = request.GET.get('ape','')
pais = request.GET.get('pais','')
correo = request.GET.get('correo','')
if nom:
if ape:
if pais:
if correo:
p=Agenda(nombre=nom,apellido=ape,pais=pais,correo=correo)
p.save()
return render_to_response('agregar.html',{"exito":True})
else:
return render_to_response('agregar.html')


Ahora es necesario definir cuando se va a llamar a la vista que recien se creo, eso se hace en 'urls.py'

agregaremos al archivo

Código: [Seleccionar]
(r'^agregar/$','miproyecto.micrud.views.agregar_registro'),
-Por ser una tupla, en Python requiere una ',' al final.
-Puedes ver como el string que se define en la tupla sigue lo siguiente:

miproyecto.micrud.views.agregar_registro=Proyecto-App-vista-nombre de la funcion.


El archivo urls.py quedaria asi:

Código: [Seleccionar]
from django.conf.urls.defaults import *
import settings
urlpatterns = patterns('',
    (r'^buscar/$','miproyecto.micrud.views.consulta'),
    (r'^combo/$','miproyecto.micrud.views.combo'),
    (r'^agregar/$','miproyecto.micrud.views.agregar_registro'),
   
    (r'css/(?P<path>.*)$', 'django.views.static.serve',
    {'document_root': settings.STATIC_ROOT   'templates/css'}),
   
    (r'js/(?P<path>.*)$', 'django.views.static.serve',
{'document_root': settings.STATIC_ROOT   'templates/js'}),
    # Example:
    # (r'^miproyecto/', include('miproyecto.foo.urls')),

    # Uncomment this for admin:
#     (r'^admin/', include('django.contrib.admin.urls')),
)

En el navegador:

Código: [Seleccionar]
http://localhost:8000/agregar/

Resultado:




ELIMINAR UN REGISTRO:

La funcion ajax en el archivo ajax.js
Código: [Seleccionar]
function eliminar(Pag,objId,idEliminar) {
divResultado = document.getElementById(objId);
var agree=confirm('Eliminar el registro #' idEliminar '?');
if (agree){
ajax=objetoAjax();
ajax.open("GET",Pag,true);
ajax.onreadystatechange=function() {
if (ajax.readyState==4) {
divResultado.innerHTML = ajax.responseText
}
}
ajax.send(null)
}
}


en /templates creando la plantilla:

eliminar.html

Código: [Seleccionar]
{% extends "base.html" %}
{% block title %}Django[Python]{% endblock %}
{% block contenido %}
<div id="resultado" >
{% block encabezado %}<h1>Eliminar registro</h1>{% endblock%}
<form class='estiloform' name='formulario'  action="" >
{% if results %}
<table  id="tabla_">
<tr><td>Nombre</td><td>Apellido</td><td>Correo</td><td>Pais</td><td>Accion</td></tr>
{% for agenda in results %}
<tr><td>{{agenda.nombre|upper}}</td><td>{{agenda.apellido|upper}}</td>
<td>{{agenda.correo|upper}}</td><td>{{agenda.pais|upper}} </td>
<td><a href=# onclick="eliminar('http://localhost:8000/eliminar/?codigo={{agenda.id}}','resultado','{{agenda.id}}'); return false">Eliminar</A></td>
</tr>
{% endfor %}
</table>
{% else %}
<p>Datos no encontrados</p>
{% endif %}
</form>
{% if exito %}
<div class="mensaje" align="justify">Registro #{{cod}} eliminado</div>
{% endif %}
{% endblock %}
</div>
-Siempre 'extendiendo' de base.html {% extends "base.html" %}, recordemos que en la base defino donde esta el archivo ajax.js

-onclick="eliminar('http://localhost:8000/eliminar/codigo={{agenda.id}}','resultado','{{agenda.id}}'); return false" funcion eliminar  que esta en ajax.js

Agregado la vista a views.py, recordemos que en este mismo archivo ya tenemos agragadas las vistas 'combo' y 'buscar' y 'agregar'


Código: [Seleccionar]
def eliminar_registro(request):
cod=request.GET.get('codigo','')
results=Agenda.objects.all().order_by('id')
if cod:
p = Agenda.objects.get(id=cod)
p.delete()
return render_to_response('eliminar.html',{"results": results,"cod":cod,"exito":True})
return render_to_response('eliminar.html',{"results": results})
Ahora es necesario definir cuando se va a llamar a la vista que recien se creo, eso se hace en 'urls.py'

agregaremos al archivo la linea:

Código: [Seleccionar]
(r'^eliminar/$','miproyecto.micrud.views.eliminar_registro'),

donde 'miproyecto.micrud.views.eliminar_registro=Proyecto-App-vista-nombre de la funcion.

En el navegador:

Código: [Seleccionar]
http://localhost:8000/eliminar/
Mensajes de confirmacion antes de eliminar:


Accion realizada:


[                                                             ]
EDITAR UN REGISTRO
Las funciones en el archivo ajax.js
Código: [Seleccionar]
function detalle_actualizar(Pag,objId,idActualizar) {
divResultado = document.getElementById(objId);
var agree=confirm('Actualizar el registro #' idActualizar '?');
if (agree){
ajax=objetoAjax();
ajax.open("GET",Pag,true);
ajax.onreadystatechange=function() {
if (ajax.readyState==4) {
divResultado.innerHTML = ajax.responseText
}
}
ajax.send(null)
}

}
/*____________________________________________________________________*/
function actualizar(Pag,objId,objIdVacio) {
        divVacios=document.getElementById(objIdVacio);
        if (document.formulario.nom.value=="" || document.formulario.ape.value=="" || document.formulario.pais.value=="" || document.formulario.correo.value=="")
        {
            divVacios.innerHTML ="<div class='mensaje' align='justify'>Complete la informacion</div>"
        }
        else
        {
divResultado = document.getElementById(objId);
id=document.formulario.id.value
        nom=document.formulario.nom.value
        ape=document.formulario.ape.value
        pais=document.formulario.pais.value
        correo=document.formulario.correo.value
        ajax=objetoAjax();
        ajax.open("GET",Pag "?id=" id "&nom=" nom "&ape=" ape "&pais=" pais "&correo=" correo,true);
        ajax.onreadystatechange=function() {
                if (ajax.readyState==4) {
                        divResultado.innerHTML = ajax.responseText
                        divVacios.innerHTML =""                       
                }
        }
        ajax.send(null)
        }
}

Para esto se crearan dos archivos html


-ver_detalle.html y actualizar.html, el primero mostrara los registros de forma individual para actualizar, y el segundo mostrara todos los registros con opcion de elegir el que se desea editar.

ver_detalle.html

Código: [Seleccionar]
{% extends "base.html" %}
{% block title %}Django[Python]{% endblock %}
{% block contenido %}
<div id="resultado" >
{% block encabezado %}<h1>Actualizar un registro</h1>{% endblock%}
<form  class='estiloform' name='formulario'  action=""  onsubmit="actualizar('http://localhost:8000/actualizar/','resultado','Vacios'); return false">
{% if results %}
<table id="tabla_" >
{% for agenda in results %}
<tr>
<tr><td><label for="q">Codigo:</label></td><td><input type="text" name="id" value="{{agenda.id}}" readonly></td></tr>
<tr><td><label for="q">Nombre:</label></td><td><input type="text" name="nom" value="{{agenda.nombre}}" onkeypress='return sololetra(event)'></td></tr>
<tr><td><label for="q">Apellido:</label></td><td><input type="text" name="ape" value="{{agenda.apellido}}" onkeypress='return sololetra(event)'></td></tr>
<tr><td><label for="q">Pais: </label></td><td><input type="text" name="pais" value="{{agenda.pais}}"  onkeypress='return sololetra(event)'></td></tr>
<tr><td><label for="q">Correo: </label></td><td><input type="text" name="correo" value="{{agenda.correo}}"</td></tr>
<tr><td colspan=2><input type="submit" value="Actualizar"></td></tr></tr><tr>
</tr>
</table>
{% endfor %}
{% else %}
<p>Datos no encontrados</p>
{% endif %}
</form>
<div id=Vacios align="center" ></div>
{% endblock %}
</div>

actualizar.html

Código: [Seleccionar]
{% extends "base.html" %}
{% block title %}Django[Python]{% endblock %}
{% block contenido %}
<div id="resultado" >
{% block encabezado %}<h1>Actualizar un registro</h1>{% endblock%}
<form  class='estiloform'  name='formulario' action="." method="GET" >
{% if results %}
<table id="tabla_">
<tr><td>Nombre</td><td>Apellido</td><td>Correo</td><td>Pais</td><td>Accion</td></tr>
{% for agenda in results %}
<tr>
<td>{{agenda.nombre|upper}}</td><td>{{agenda.apellido|upper}}</td>
<td>{{agenda.pais|upper}}</td><td>{{agenda.correo|upper}}</td>
<td><a href=# onclick="detalle_actualizar('http://localhost:8000/actualizar/?id={{agenda.id}}','resultado','{{agenda.id}}'); return false">Actualizar</A>
</tr>
{% endfor %}
</table>
{% else %}
<p>Datos no encontrados</p>
{% endif %}
</form>
{% if exito %}
<div class="mensaje" align="justify">Registro #{{id}} actualizado</div>
{% endif %}
{% endblock %}
</div>

-Siempre se 'extendiende' de el archivo base html.
-Funciones definidas en ajax.js
Código: [Seleccionar]
onclick="detalle_actualizar('http://localhost:8000/actualizar/id={{agenda.id}}','resultado','{{agenda.id}}'); return false

Código: [Seleccionar]
actualizar('http://localhost:8000/actualizar/','resultado','Vacios'); return false"


La funcion en la vista
Código: [Seleccionar]
def actualizar_registro(request):
id = request.GET.get('id','')
results=Agenda.objects.all().order_by('id')
if id: # si solo obtengo el id , mostrar el detalle
if not request.GET.get('nom',''):
if not request.GET.get('ape',''):
if not request.GET.get('pais',''):
if not request.GET.get('correo',''):
results=Agenda.objects.filter(id=id).order_by('id')
return render_to_response('ver_detalle.html',{"results":results})
if id:
if  request.GET.get('nom',''):
if request.GET.get('ape',''):
if request.GET.get('pais',''):
if request.GET.get('correo',''):
p=Agenda.objects.get(id=request.GET.get('id',''))# Que registro va a actualizar
p.id=request.GET.get('id','')
p.nombre=request.GET.get('nom','')
p.apellido=request.GET.get('ape','')
p.pais=request.GET.get('pais','')
p.correo=request.GET.get('correo','')
p.save()
results=Agenda.objects.all().order_by('id')
return render_to_response('actualizar.html',{"results":results,"id":id,"exito":True})
return render_to_response('actualizar.html',{"results":results})

En urls.py definimos la funcion creada en views.py.
Código: [Seleccionar]
(r'^actualizar/$','miproyecto.micrud.views.actualizar_registro'),

En el navegador:

Código: [Seleccionar]
http://localhost:8000/actualizar/

Todos los registros:


Editando de forma individual:


Regresa al formulario principal:



[                                                  ]
Algunas cosas que resaltar:

-Lo interesante es que cuando configuramos el archivo 'settings.py'  solo nos debemos preocupar por crear las plantillas, funciones en la vista y definir las rutas en urls.py

-Nunca mas se habla de la conexión a la base de datos, solo se define una vez los parametros y ya.

-Si alguien le interesa el codigo completo mandenme un mp y se los envio completo, junto al archivo css.

-Espero les sirva, y mencionar que a veces por un pequeño error nuestro, de sintaxis o una ruta mal puesta ,no podria funcionar XD

-Se debe tener cuidado con la Indentación en Python.
« Última Modificación: abril 30, 2012, 03:14:25 pm por edu_guerr »

Desconectado JaiMe

  • Global Moderator
  • The Communiter-
  • *
  • Mensajes: 1485
  • λ | h+
@edu_guerr gracias por traernos un tuto.

Sugiero que hagas una cuenta en github para poder clonar el projecto en el futuro y experimentar.

Alguna razón por la cual decidiste usar tu propio objeto Ajax en lugar de jQuery?

Lastima que no estoy tan familiarizado con Django como para poder expandir como se debe sobre el tema. Pero aqui te dejo mis observaciones sobre el código del lado del cliente, por que veo que se puede mejorar en esa area:

Cuidado con tu función ConsultaFiltrado en JavaScript, las variables divVacios, divResultados y valor están declaradas implicitamente como variables globales - esto te puede crear bastantes bugs y memory leaks - el remedio es facil: siempre agrega la keyword var antes del nombre al momento de declarar variables.

Veo que usas las variables divXXXX otra ves en la función insertar, lo que podes hacer es declararlas afuera de ambas funciones en el ambito superior (upper scope), de esta manera ambas funciones tienen acceso a estas variables.

Siempre agrega ";" al final de cada statement. El interprete de JS los agrega automaticamente cuando hacen falta, pero a veces esto te puede producir un monton bugs que son bastante dificiles de encontrar.

Veo que estas repitiendo este block dos veces por cada peticion Ajax

Código: [Seleccionar]
       ajax = objetoAjax();
       ajax.open(tipo, url, bool);
       ajax.onreadystatechange = function() {
               if (ajax.readyState == 4) {
                       divResultado.innerHTML = ajax.responseText
                       divVacios.innerHTML = ""                       
               }
       }
       ajax.send(null)
       
Lo cual podes acortar y usar de la siguiente manera, asumiendo que queres todas las peticiones como GET y que sean asíncronas

Código: [Seleccionar]
        objetoAjax(url, function(respuesta){
             divResultado.innerHTML = respuesta;
             divVacios.innerHTML = "";
        });

Veras que esto es mucho mas corto - y lo podes acortar aun mas. Lo unico que tenes que hacer es modificar la declaración de objetoAjax

Código: [Seleccionar]
    function objetoAjax(url, successFun){
        // .. mismo codigo, pero replazar "return xmlhttp" con esto
        xmlhttp.open('GET', url, true);
        xmlhttp.onreadystatechange=function() {
            if (xmlhttp.readyState==4) {
                successFun( xmlhttp.responseText );
            }
        }
        xmlhttp.send( null );
    } 


Este pedazo de código no sera tan claro al principio debido a que la declaración de la función objetoAjax tiene otra función (successFun) como parametro, pero ejemplifica una de las fortalezas de JavaScript: funciones como ciudadanos de primera clase.

Tambien, recomiendo empezar a escribir todo el código JavaScript de manera unobstrusiva, es decir evitar llamar funciones JS desde atributos HTML.
"Unless you try to do something beyond what you have already mastered, you will never grow."
― Ralph Waldo Emerson

Desconectado edu_guerr

  • Sv Member
  • ***
  • Mensajes: 463
CREANDO UN LOGIN BASICO CON Framework Django(Python) V.1.0

Aquí un pequeño ejemplo del uso de credenciales usando django( se usan las credenciales creadas para el usuario administrador de django), esta parte es bastante extensa en django, por lo que esto es lo mas resumido.
Citar
Libro de django v.1 | El Libro de Django | python | espanol |  lo pueden encontrar aquí:
http://www.svcommunity.org/forum/programacioacuten/lista-de-recursos/

-En miproyecto/settings.py incluir  'django.contrib.auth' dentro de tu INSTALLED_APPS  normalmente ya viene incluido:
Código: [Seleccionar]
INSTALLED_APPS = (
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.sites',
    'miproyecto.micrud',
)
   
Si ya esta incluido no sera necesario hacer manage.py syncdb,  verificar que  'django.contrib.sessions.middleware.SessionMiddleware' y  'django.contrib.auth.middleware.AuthenticationMiddleware' esten incluidas
Código: [Seleccionar]
MIDDLEWARE_CLASSES = (
    'django.middleware.common.CommonMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.middleware.doc.XViewMiddleware',
)
Para trabajar con los datos del usuario dentro de una vista se puede usar  'user' , este tiene varios metodos que facilitaran muchas cosas, entre ellos:
Código: [Seleccionar]
is_authenticated()
is_anonymous()
is_staff
Y con esos metodos puedo hacer por ejemplo:  si el usuario está autenticado o no con el método is_authenticated():
Código: [Seleccionar]
if request.user.is_authenticated():
# Do something for authenticated users.
else:
# Do something for anonymous users.

-En urls.py se va a modificar, el login, logout  seran una vista cada uno,ademas se creara una vista con un mensaje de 'usuario no existente' que se llamara 'nologin' por lo que se van a mapear las vistas para loguarse y desloguearse, se tendria que agregar:
Código: [Seleccionar]
(r'^login/$', 'miproyecto.micrud.views.login'),
(r'^logout/$', 'miproyecto.micrud.views.logout'),
(r'^nologin/$', 'miproyecto.micrud.views.nologin'),


Creando la plantilla login, se usara la 'base' de html ya creada antes que me incluye encabezados, css, etc..

Código: [Seleccionar]
{% extends "base.html" %}
{% block title %}Django[Python]{% endblock %}
{% block contenido %}
{% block encabezado %}<h1>Login</h1>{% endblock %}
{% if bienvenida %}
<div class="mensaje" align="justify">Ingrese su usuario y password</div>
{% endif %}
<form action='.' method='post'>
<table>
<tr>
<td><label for="username">User name:</label></td><td> <input type="text" name="username" value="" id="username"></td>
</tr>
<tr>
<td><label for="password">Password:</label></td><td><input type="password" name="password" value="" id="password"></td>
</tr>
<tr>
<td colspan=2><input type="submit" value="login" /></td>
</tr>
<tr>
<td colspan=2><input type="hidden" name="next" value="{{ next|escape }}" /></td>
</tr>
</table>
<form action='.' method='post'>
{% endblock %}

Vista plantilla login:


-Creando mis vistas en views.py

Agregar al inicio de el archivo views.py
Código: [Seleccionar]
from django.contrib import auth
from django.http import HttpResponseRedirect

En este caso  HttpResponseRedirect() se usara para redireccionar por ejemplo:
Código: [Seleccionar]
return HttpResponseRedirect("/nologin")

Las vistas login,logout, error si usuario no existe:
Código: [Seleccionar]
########################################################################################
def login(request):
if request.POST.get('username',''):
if request.POST.get('password',''):
username = request.POST['username']
password = request.POST['password']
user = auth.authenticate(username=username, password=password)
if user is not None and user.is_active:
# Correct password, and the user is marked "active"
auth.login(request, user)
# Redirect to a success page.
return HttpResponseRedirect("/agregar")
else:
# Show an error page
return HttpResponseRedirect("/nologin")
return render_to_response('login.html',{"login":True})
########################################################################################
def logout(request):
auth.logout(request)
# Redirect to a success page.
return HttpResponseRedirect("/login")
########################################################################################
def nologin(request):
return render_to_response('nologueado.html',{"error":True})
def login(request)  :
Con 'if user is not None and user.is_active' verifico mi usuario, en mi caso uso el que cree para la parte de administracion de django y luego solo redirecciono si existe voy  a /agregar(creada anteriormente en el crud) , en todo caso esta ruta puede ser /index o /principal de nuestra pagina, de lo contrario redirecciono a  la vista /nologin la cual mostrara una plantilla  con el mensaje de error:




-Plantilla nologueado.html(plantilla  con el mensaje de error)

Código: [Seleccionar]
{% extends "base.html" %}
{% block title %}Django[Python]{% endblock %}
{% block contenido %}
{% if error %}
<div class="error" align="justify">Su usuario o password no existe</div>
{% endif %}
{% endblock %}

Con {% if error %} tomo 'True' enviado desde mi vista: return render_to_response('nologueado.html',{"error":True})    

-En en index(que en mi caso es /agregar) llamaremos a la vista /logout la cual mandara a /login

Agrego a mi plantila /agregar(que en mi caso es la principal o index)
Código: [Seleccionar]
<a href='/logout'>Logout</a>

Vista logout:
Código: [Seleccionar]
def logout(request):
auth.logout(request)
# Redirect to a success page.
return HttpResponseRedirect("/login")

--------------------------
Y eso es todo  :drinks:

Desconectado darkness51

  • Sv Member
  • ***
  • Mensajes: 208
    • DWD&Solutions
Hola,

Muy bueno el tema, solo tengo una duda, porque estas usando la versión 1.0 cuando Django ya va por la versión 1.4.1 y de la 1.3 en adelante el framework sufre bastantes cambios.

Por ejemplo, en 1.4 se cambia la estructura por default del proyecto. Deberías de actualizar tus tutos a la última versión de Django y si aún quieres trabajar con las versiones anteriores, puedes usar virtualenv.

Respecto a javascript, estoy de acuerdo con el compañero Jaime, porque usas tu propio objecto y no jQuery???

Por lo demás, felicitarte por tu iniciativa de aprender Django, el framework es muy interesante y por si te interesa ver algo de código de 1.4 te dejo este proyecto: http://goo.gl/pj6hs

Es un proyecto personal para crear un panel de control de hosting libre usando python + django + otras herramientas.

Saludos.
http://www.houseofsysadmin.com
http://www.dwdandsolutions.com

Desconectado edu_guerr

  • Sv Member
  • ***
  • Mensajes: 463
Hola,

Muy bueno el tema, solo tengo una duda, porque estas usando la versión 1.0 cuando Django ya va por la versión 1.4.1 y de la 1.3 en adelante el framework sufre bastantes cambios.

Por ejemplo, en 1.4 se cambia la estructura por default del proyecto. Deberías de actualizar tus tutos a la última versión de Django y si aún quieres trabajar con las versiones anteriores, puedes usar virtualenv.

Respecto a javascript, estoy de acuerdo con el compañero Jaime, porque usas tu propio objecto y no jQuery???

Por lo demás, felicitarte por tu iniciativa de aprender Django, el framework es muy interesante y por si te interesa ver algo de código de 1.4 te dejo este proyecto: http://goo.gl/pj6hs

Es un proyecto personal para crear un panel de control de hosting libre usando python + django + otras herramientas.

Saludos.
Fíjate que si he estado viendo algo del 1.4 para pasar a esa versión y si cambian muchas cosas , se ve interesante el proyecto que tienes le voy a dar seguimiento al repositorio, darkness51 cuando tengas chance no caería mal un tutorial básico de la ultima versión.

Desconectado darkness51

  • Sv Member
  • ***
  • Mensajes: 208
    • DWD&Solutions
Te dejo el video en Youtube de un pequeño taller de Django que tuve la oportunidad de dar en post.mejorando.la

http://goo.gl/ZxUcb

Saludos.
http://www.houseofsysadmin.com
http://www.dwdandsolutions.com

Desconectado edu_guerr

  • Sv Member
  • ***
  • Mensajes: 463
Agregando un poco mas al tema de: CREANDO UN LOGIN BASICO CON Framework Django(Python) V.1.0 y la parte de la autenticacion que ofrece Django.

-La funcion que nos permite loguearnos (def login) y , otra que nos permite hacer logout, asi mismo una funcion (def nologin )la cual se utiliza por  si intentamos ingresar un usuario y contrasena que no existe.

Código: [Seleccionar]
def login(request):
if request.POST.get('username',''):
if request.POST.get('password',''):
username = request.POST['username']
password = request.POST['password']
user = auth.authenticate(username=username, password=password)
if user is not None and user.is_active:
# Correct password, and the user is marked "active"
auth.login(request, user)
# Redirect to a success page.
return HttpResponseRedirect("/agregar")
else:
# Show an error page
return HttpResponseRedirect("/nologin")
return render_to_response('login.html',{"login":True})

def logout(request):
auth.logout(request)
# Redirect to a success page.
return HttpResponseRedirect("/login")

def nologin(request):
return render_to_response('nologueado.html',{"error":True})


Modificamos un poco los metodos orginales, el objetivo  es que ninguna pagina pueda ser vista, a menos que el usuario este autenticado algo que antes de esto no se había echo(pequeño detalle), si intenta colocar una ruta por ejemplo:  http://localhost:8000/buscar/ y no esta autenticado lo vamos a hacer que redirecciones a una “vista” creada mostrando un error, usando la "vista" : nologin.


Cuando nos loguemos usamos: user = auth.authenticate(username=username, password=password), se usara “user” para hacer esa validacion en cada metodo, de esta forma:

user.is_authenticated()

Quedando el metodo ya modificado asi( esta condicion tendria que aplicarse en cada funcion):

Código: [Seleccionar]
def consulta(request):
if request.user.is_authenticated():
consulta = request.GET.get('q', '')
if consulta:
results=Agenda.objects.filter(pais=consulta).order_by('id')
return render_to_response("consulta.html", { "results": results,"consulta": consulta})
return render_to_response("consulta.html", { "results": [],"consulta": consulta})
else:
return HttpResponseRedirect("/nologin")


Antes de hacer la validación el método estaba así, lo cual permitía que si se "llamaba" aunque no estuviera autenticado el usuario, se la iba
a mostrar:
Código: [Seleccionar]
def consulta(request):
consulta = request.GET.get('q', '')
if consulta:
results=Agenda.objects.filter(pais=consulta).order_by('id')
return render_to_response("consulta.html", { "results": results,"consulta": consulta})
return render_to_response("consulta.html", { "results": [],"consulta": consulta})

Y como muchos saben, Django ya va adelante de esta versión que les muestro acá, pero en si este "concepto" de autenticacion que usa
Django, lo he visto en otros Framework y siempre es bueno manejar la idea.


Para mas informacion de la buena:
https://docs.djangoproject.com/en/dev/topics/auth/
« Última Modificación: junio 28, 2013, 09:31:03 pm por edu_guerr »

Desconectado Raul200

  • The newbie
  • *
  • Mensajes: 1
amigo me podias enviar el demo ?..ademas , como puedo hacer esto en windows , usando pycharm .me seria de gran ayuda su respuesta .gracias de antemano

Desconectado darkness51

  • Sv Member
  • ***
  • Mensajes: 208
    • DWD&Solutions
Recomendación si vas a usar Django, aprende a usar linux, con proyectos más avanzados, hay dependencias que no tienen un paquete para windows, como por ejemplo hiredis, etc.
http://www.houseofsysadmin.com
http://www.dwdandsolutions.com

Desconectado edu_guerr

  • Sv Member
  • ***
  • Mensajes: 463
amigo me podias enviar el demo ?..ademas , como puedo hacer esto en windows , usando pycharm .me seria de gran ayuda su respuesta .gracias de antemano

Para usar Django en Windows , puedes ver esto y ver si te sirve:
http://www.svcommunity.org/forum/programacioacuten/lista-de-recursos/msg868221/#msg868221

Si queres te mando el demo, solo pasame por mp tu correo y con gusto, solo toma en cuenta que el tutorial se hizo usando  con Python 2.6, Django V.1.0,  te escribo esto
por que  ya cambiaron las versiones, y asi como te dice darkness51, lo mejor seria que lo probaras en GNU/Linux.

Desconectado edu_guerr

  • Sv Member
  • ***
  • Mensajes: 463
Como menciono darkness51, el tutorial para este momento ya esta bastante desfasado por la versión de django, a pesar de eso, un día de estos alguien me solicito que se lo compartiera, por si le sirve a alguien de acá, igual les dejo el enlace para que lo descarguen:
https://www.dropbox.com/s/ks1jhrlo37uyyuo/crud_django_1.tar.gz