22 KiB
Ir a: Repositorio, Wiki
Proyecto y Aplicacion(es)
Modularización
ej. Reutilización de webApps en dos proyectos
__________________________________ __________________________________
| Proyecto Tienda Online | | Proy. Gestión Almacen |
| | | |
| App1 App2 | | App1 App2 |
| [Panel Control] [Stock] | | [Proveedores] [Stock] |
| | | |
| App3 App4 | | App3 App4 |
| [Ventas] [Pagos] | | [Ventas] [Pagos] |
| | | |
| App5 App6 | | App5 App6 |
| [Envíos] [Promos] | | [Envíos] [Promos] |
|__________________________________| |__________________________________|
Recordar activar entorno virtual
*source /home/sat/weblocal/.django-env/bin/activate
Creación de proyecto : django-admin startproject TiendaOnline
Cambiar a carpeta de proy.: cd /TiendaOnline
Ajustar TZ en settings.py : TIME_ZONE = 'America/Santiago'
Creación primera app : python3 manage.py startapp gestionPedidos
/TiendaOnline/gestionPedidos/
- migrations/
- admin.py
- apps.py
- __init__.py
- models.py
- tests.py
- views.py
SQLite3 (default)
/gestionPedidos/models.py
from django.db import models
class Clientes(models.Model):
nombre = models.CharField(max_length=30)
direccion = models.CharField(max_length=50)
email = models.EmailField()
fono = models.CharField(max_length=10)
class Articulos(models.Model):
nombre = models.CharField(max_length=30)
seccion = models.CharField(max_length=20)
precio = models.IntegerField()
class Pedidos (models.Model):
numero = models.IntegerField()
fecha = models.DateField()
entregado = models.BooleanField()
settings.py
...
INSTALLED_APPS = [
...
'gestionPedidos',
]
...
Chequear código :
python3 manage.py check gestionPedidos
Creación del modelo Base de Datos :
python3 manage.py makemigrations
# Ver instrucciones SQL
python3 manage.py slqmigrate gestionPedidos 0001
Creación de BD:
python3 manage.py migrate
🔸️ acceder al 'shell de django': python3 manage.py shell
Insertar Registros
(InteractiveConsole)
>>> from gestionPedidos.models import Articulos
>>>
>>> art = Articulos(nombre='mesa', seccion='decoracion', precio=96)
>>> art.save()
>>>
>>> art2 = Articulos(nombre='camisa', seccion='vestuario', precio=25)
>>> art2.save()
>>>
>>> art3 = Articulos.objects.create(nombre='taladro', seccion='ferreteria', precio=65)
>>>
Actualizar Registros
>>> art.precio=99
>>> art.save()
>>>
Borrar Registros
>>> art5 = Articulos.objects.get(id=2)
>>> art5.delete()
(1, {'gestionPedidos.Articulos': 1})
>>>
Select
>>> ResConsulta = Articulos.objects.all()
>>> ResConsulta
<QuerySet [<Articulos: Articulos object (1)>, <Articulos: Articulos object (3)>]>
>>>
>>> # Ver instrucción SQL:
>>> ResConsulta.query.__str__()
'SELECT "gestionPedidos_articulos"."id", "gestionPedidos_articulos"."nombre", "gestionPedidos_articulos"."seccion", "gestionPedidos_articulos"."precio" FROM "gestionPedidos_articulos"'
>>>
PostgreSQL
Install
sudo apt install postgresql postgresql-contrib libpq-dev
Success. You can now start the database server using:
pg_ctlcluster 11 main start
# Cambiar a user postgres
sudo -i -u postgres
# sql cli
postgres@sat:~$ psql
# salir
postgres=# \q
# Crear usuario *ambiente de desarrollo
postgres@sat:~$ createuser -P --interactive
Enter name of role to add: django
Shall the new role be a superuser? (y/n) y
# Crear BD con nombre de usuario
(postgres automaticamente se conecta a un DB con el mismo nombre de usuario)
postgres@sat:~$ createdb django
# Crear password
postgres@ratsat:~$ psql
psql (11.9 (Raspbian 11.9-0+deb10u1))
Type "help" for help.
postgres=# \password django
postgres=# \q
postgres@ratsat:~$ psql -U django -W
Problemas con Log-in ?
sudo vim /etc/postgresql/11/main/pg_hba.conf
# CAMBIAR
# Database administrative login by Unix domain socket
local all postgres peer
por
# Database administrative login by Unix domain socket
local all postgres md5
# "local" is for Unix domain socket connections only
local all all md5
# Reiniciar servicio
sudo service postgresql restart
# Para borrar usuario
DROP OWNED BY your_user;
DROP USER your_user;
# Modificar
vim /etc/postgresql/10/main/postgresql.conf
...
listen_addresses = 'localhost,your-server-ip'
...
sudo vim /etc/postgresql/11/main/postgresql.conf
# IPv4 local connections:
host all all 192.168.0.0/24 md5
# Regla Firewall
sudo ufw allow proto tcp from 192.168.0.0/24 to any port 5432
Usar algun DBbrowser y crear bd ArticulosClientes
Instalar Python-Django PostgreSQL connector
pip3 install psycopg2
vim settings.py
# Modificar
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': BASE_DIR / 'db.sqlite3',
}
}
ej.
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql_psycopg2',
'NAME': 'articulosclientes',
'USER': 'nombre_usuario',
'PASSWORD': 'clave_usuario',
'HOST': '127.0.0.1',
'DATABASE_PORT': '5432',
}
}
# Check
python3 manage.py check
# Hacer migraciones
python3 manage.py makemigrations
# Migrar
python3 manage.py migrate
Crear un registro
python3 manage.py shell
(InteractiveConsole)
>>> from gestionPedidos.models import Clientes
>>>
>>> cli = Clientes(nombre='Pedro', direccion='dnd vive', email='pe@mail.ru', fono=123456789)
>>> cli.save()
>>>
Valores en tabla articulos
id | nombre | seccion | precio |
---|---|---|---|
1 | mesa | deco | 90 |
2 | lámpara | deco | 50 |
3 | pantalón | vestuario | 45 |
4 | destornillador | ferreteria | 5 |
5 | balón | deporte | 25 |
6 | raqueta | deporte | 105 |
7 | muñeca | juguetes | 15 |
8 | tren eléctrico | juguetes | 50 |
Intruccion SQL desde Django
# Select * ... where seccion='deporte';
>>> from gestionPedidos.models import Articulos
>>>
>>> Articulos.objects.filter(seccion='deporte')
<QuerySet [<Articulos: Articulos object (5)>, <Articulos: Articulos object (6)>]>
>>>
/TiendaOnline/gestionPedidos/models.py
class Articulos(models.Model):
nombre = models.CharField(max_length=30)
seccion = models.CharField(max_length=20)
precio = models.IntegerField()
def __str__(self):
return 'Nombre: %s, Depto. %s, Precio $ %s' % (self.nombre, self.seccion, self.precio)
python3 manage.py makemigrations
python3 manage.py migrate
python3 manage.py shell
>>> from gestionPedidos.models import Articulos
>>>
>>> Articulos.objects.filter(seccion='deporte')
>>> <QuerySet [<Articulos: Nombre: balón, Depto. deporte, Precio $ 25>,
<Articulos: Nombre: raqueta, Depto. deporte, Precio $ 105>]>
>>>
# Select * ... where nombre='mesa' seccion='deco';
>>> Articulos.objects.filter(nombre='mesa', seccion='deco')
<QuerySet [<Articulo: Nombre: mesa, Depto. deco, Precio $ 90>]>
>>>
# Para buscar por ej. un elemento con precio mayor a 100 desde la shell django
>>> Articulos.objects.filter(precio__gte=100)
<QuerySet [<Articulos: Articulo: raqueta, Depto. deporte, Precio $ 105>]>
otros: __tle, __range, ...).order_by(precio o -precio para inverso)
>>> Articulos.objects.filter(precio__range=(40,90))
>>>
<QuerySet [<Articulos: Nombre: mesa, Depto. deco, Precio $ 90>, <Articulos: Nombre: lámpara, Depto. deco, Precio $ 50>, <Articulos: Nombre: pantalón, Depto. vestuario, Precio $ 45>, <Articulos: Nombre: tren eléctrico, Depto. juguetes, Precio $ 50>]>
>>>
>>> Articulos.objects.filter(precio__gte=50).order_by('precio')
<QuerySet [<Articulos: Articulo: lámpara, Depto. deco, Precio $ 50>, <Articulos: Articulo: tren eléctrico, Depto. juguetes, Precio $ 50>, <Articulos: Articulo: mesa, Depto. deco, Precio $ 90>, <Articulos: Articulo: raqueta, Depto. deporte, Precio $ 105>]>
Panel de Administrador
Activo por defecto
settings.py
...
INSTALLED_APPS = [
'django.contrib.admin',
...
urls.py
...
urlpatterns = [
path('admin/', admin.site.urls),
...
Crear SuperUsuario, con perfíl de administrador
python3 manage.py createsuperuser
Username (leave blank to use 'sat'): Roberrrt
Email address: admin@gitea.com
Password:
Password (again):
Superuser created successfully.
Explorando la BD
tabla auth_user
id | password | last_login | is_superuser | username | first_name | last_name | is_staff | is_active | date_joined | |
---|---|---|---|---|---|---|---|---|---|---|
1 | pbkdf2_sha256$216000$zw4Zuc6weyCN$Vwn8SM6zPA3hIofcmQiz4mIuU6tL7U/vvWs= | 2020-11-13 02:40:20 | true | Roberrrt | admin@gitea.com | true | true | 2020-11-13 02:38:41 | ||
2 | pbkdf2_sha256$216000$188Gs3iRpsWb$X49lPG/2IlRlsaanXqUBZ6YOMIvctZ+U0Gg= | false | Roberrrt2 | false | true | 2020-11-13 02:41:43 |
Administrar tablas desde el Panel
admin.py
from django.contrib import admin
from gestionPedidos.models import Clientes
admin.site.register(Clientes)
Configurar campo 'email' como opcional, clase Cliente
models.py
...
class Clientes(models.Model):
...
email = models.EmailField(blank=True, null=True)
...
cambios en el modelo, requieren migración
python3 manage.py makemigrations
python3 manage.py migrate
Personalización del Panel
Admin. Clientes Django por defecto presenta los nombres de los campos capitalizados y elimina el texto posterior a '_' ( ej. modelo nombre_clientes ).
Columnas en el Panel de admin.
Add clientes
Nombre:
Direccion:
Email:
Fono:
Modificar nombre visible de tablas
Personalizar nombre a mostrar en panel, en el Modelo. models.py
class Clientes(models.Model):
...
direccion = models.CharField(max_length=50, verbose_name="La Direcc.:")
...
Vista Panel
Add clientes
Nombre:
La Direcc.:
Email:
Fono:
Ver otros campos de tablas a modificar en panel
gestionPedidos/admin.py
from django.contrib import admin
from gestionPedidos.models import Clientes, Articulos, Pedidos
class ClientesAdm(admin.ModelAdmin):
list_display("nombre", "direccion", "fono")
admin.site.register(Clientes, ClientesAdmin)
vista en Panel
Nombre | La Direcc. | Fono |
---|---|---|
Elejendre | calle 16 | 2445234234 |
Zerafín | dnd vive | 123456789 |
Pedro | ruta 2 | 9873456789 |
Agregar campo de busqueda
gestionPedidos/admin.py
class ClientesAdmin(admin.ModelAdmin):
list_display = ("nombre", "direccion", "fono")
# Campos de busqueda en la barra
search_fields = ("nombre","fono")
Agregar Filtros
admin.py
class ArticulosAdmin(admin.ModelAdmin):
list_filter = ("seccion",)
vista filtro en panel
Filter by Secion |
---|
All |
deco |
deporte |
ferreteria |
jugetes |
vestuario |
Tambien se puede filtar por fecha
admin.py
class PedidosAdmin(admin.ModelAdmin):
list_display = ("numero", "fecha")
list_filter = ("fecha",)
admin.site.register(Pedidos, PedidosAdmin)
vista filtro en panel
Filter by Fecha |
---|
Any date |
Today |
Past 7 days |
This month |
This Year |
Filtro de disposicion horizontal, estilo menú
admin.py
class PedidosAdmin(admin.ModelAdmin):
list_display = ("numero", "fecha")
list_filter = ("fecha",)
# Filtro-barra*
date_hierarchy = "fecha"
Vista del Panel de Administrador
Cambiar Idioma
settings.py
#LANGUAGE_CODE = 'en-us'
LANGUAGE_CODE = 'es-CL'
Agregar usuarios, perfiles
Usuarios STAFF, puede administrar el sitio desde el panel, se puede limitar.
Usuarios ACTIVO, puede entrar en partes del sitio que requieran autenticación.
Agregar grupos
Permite crear Grupos, con permisos específicos.
Se pueden agregar permisos extra pro usuario.
Formularios
Creacion del formulario
/TiendaOnline/gestionPedidos/templates/busqueda_prods.html
<html>
<head>
<title>Búsqueda de productos</title>
</head>
<body>
<form action="/buscar/" method="GET">
<input type="text" name="prod">
<input type="submit" value="Buscar">
</form>
</body>
</html>
Creación vista formulario
gestionPedidos/views.py
from django.shortcuts import render
# Create your views here.
def busqueda_productos(request):
return render(request, "busqueda_prods.html")
Restistrar url (path)
urls.py
...
from gestionPedidos import views
urlpatterns = [
....
path('buscar_productos/', views.busqueda_productos),
....
Crear vista para el submit 'buscar'
gestionPedidos/views.py
...
from django.http import HttpResponse
...
def buscar(request):
msj = "Estas búscando por: %r" %request.GET["prod"]
return HttpResponse(msj)
Registrar url
urls.py
...
urlpatterns = [
...
path('buscar/', views.buscar),
]
Metodo GET http://192.168.0.4:8000/buscar/?prod=alicate
Busqueda en BBDD
views.py
...
from gestionPedidos.models import Articulos
...
def buscar(request):
# Validación campo vacio
if request.GET["prod"]:
#msj = "Estas búscando por: %r" %request.GET["prod"]
prod_buscar = request.GET["prod"]
articulos = Articulos.objects.filter(nombre__icontains=prod_buscar)
return render(request, "resultado_busqueda.html", {"articulos":articulos, "query":prod_buscar})
else:
msj = "Debes introducir un termino de búsqueda"
return HttpResponse(msj)
__icontains similar a like SQL, busca en el campo indicado,
articulos que CONTENGAN la palabra a buscar.
resultado_busqueda.html
<body>
<p>Estás buscando <strong>{{query}}</strong></p>
{% if articulos %}
<p>Encontrados : {{articulos|length}} artículos</p>
<ul>
{% for articulo in articulos %}
<li>{{articulo.nombre}} {{articulo.seccion}} ${{articulo.precio}}</li>
{% endfor %}
</ul>
{% else %}
<p>Artículo no encontrado</p>
{% endif %}
</body>
Limitar cantidad de caracteres en busqueda
views.py
...
def buscar(request):
# Validación campo vacio
if request.GET["prod"]:
prod_buscar = request.GET["prod"]
if len(prod_buscar) > 20:
msj = "Termino de búsqueda demasiado largo"
else:
articulos = Articulos.objects.filter(nombre__icontains=prod_buscar)
return render(request, "resultado_busqueda.html", {"articulos":articulos, "query":prod_buscar})
...
Formulario de contacto
views.py
contacto.html
<body>
<h1>Formulario de contacto</h1>
<form action="/contacto/" method="POST">
{% csrf_token %}
<p>Asunto: <input type="text" name="asunto"></p>
<p>Mail : <input type="text" name="mail"></p>
<p>Mensaje: </p>
<p><textarea name="mensaje" rows="15" cols="45"></textarea></p>
<input type="submit" value="Enviar">
</form>
</body>
{% csrf_token %} Protección contra CSRF
This should not be done for POST forms that target external URLs, since that would cause the CSRF token to be leaked, leading to a vulnerability.
gracias.html
...
<h1>Gracias por contactarnos</h1>
...
views.py
...
def contacto(request):
if request.method == "POST":
return render(request, "gracias.html")
return render(request, "contacto.html")
urlpatterns urls.py
...
path('contacto/', views.contacto),`
...
Envio de Mails
Libreria core.mail
settings.py
EMAIL_BACKEND = 'django.core.imail.backends.smtp.EmailBackend'
EMAIL_HOST = 'smtp.gmail.com'
EMAIL_USE_TLS = True
EMAIL_PORT = 587
EMAIL_HOST_USER = 'ejemplo@gmail.com'
EMAIL_HOST_PASSWORD = 'clave-ejemplo'
settings-doc django.core.mail-doc
🔸️python3 manage.py shell
(InteractiveConsole)
>>> from django.core.mail import send_mail
>>>
>>> send_mail('Test Django Admin',
'Mensaje desde la consola de django',
'webmaster@django.net',
['destinatario@mail.com'],
fail_silently = False,
)
Envio de mail desde formulario de contacto
views.py
...
from django.core.mail import send_mail
from django.conf import settings
...
def contacto(request):
if request.method == "POST":
subject = request.POST['asunto']
message = request.POST['mensaje']+' '+request.POST['email']
email_from = settings.EMAIL_HOST_USER
recipient_list = ['ratablastard@gmail.com']
send_mail(subject, message, email_from, recipient_list)
return render(request, "gracias.html")
return render(request, "contacto.html")
API Forms
Creación de formularios con API Forms
Simplifica la creación de formularios e incluye validacion.
API Forms doc
Indice Forms Api doc
Crear /TiendaOnline/gestionPedidos/forms.py
from django import forms
class FormContacto(forms.Form):
asunto = forms.CharField(max_length=35, required=False, initial='Contacto')
email = forms.EmailField(max_length=35)
msj = forms.CharField(widget=forms.Textarea(attrs={'rows': 5, 'cols': 26}))
🔸️python3 manage.py shell
(InteractiveConsole)
>>> from gestionPedidos.forms import FormContacto
>>>
>>> miForm = FormContacto()
>>>
>>> print(miForm)
<tr><th><label for="id_asunto">Asunto:</label></th><td><input type="text" name="asunto" required id="id_asunto"></td></tr>
<tr><th><label for="id_email">Email:</label></th><td><input type="email" name="email" required id="id_email"></td></tr>
<tr><th><label for="id_msj">Msj:</label></th><td><input type="text" name="msj" required id="id_msj"></td></tr>
>>>
El formulario esta formateado como tabla.
Crea las etiquetas 'label', les da un nombre.
Crea los asuntos e inputs.
Por defecto estos son requeridos.
Cambiando el formato del formulario
ej. como parrafo
>>> print(miForm.as_p())
<p><label for="id_asunto">Asunto:</label> <input type="text" name="asunto" required id="id_asunto"></p>
<p><label for="id_email">Email:</label> <input type="email" name="email" required id="id_email"></p>
<p><label for="id_msj">Msj:</label> <input type="text" name="msj" required id="id_msj"></p>
>>>
ej. como lista (unsorted list)
>>> print(miForm.as_ul())
<li><label for="id_asunto">Asunto:</label> <input type="text" name="asunto" required id="id_asunto"></li>
<li><label for="id_email">Email:</label> <input type="email" name="email" required id="id_email"></li>
<li><label for="id_msj">Msj:</label> <input type="text" name="msj" required id="id_msj"></li>
>>>
Probando el formulario is_valid() y cleaned_data
>>> miForm = FormContacto({'asunto':'prueba', 'email':'test@mail.com', 'msj':'mensaje de prueba'})
>>>
>>> miForm.is_valid()
True
>>>
>>> miForm.cleaned_data
{'asunto': 'prueba', 'email': 'test@mail.com', 'msj': 'mensaje de prueba'}
>>>
Campo email invalido
>>> miForm = FormContacto({'asunto':'prueba', 'email':'test@mailcom', 'msj':'mensaje de prueba'})
>>>
>>> miForm.is_valid()
False
>>>
>>> miForm.cleaned_data
{'asunto': 'prueba', 'msj': 'mensaje de prueba'}
>>>
Cambiando views.py para usar el Api Forms
...
from gestionPedidos.forms import FormContacto
...
def contacto(request):
if request.method == "POST":
miForm = FormContacto(request.POST)
if miForm.is_valid():
contenido = miForm.cleaned_data
send_mail(contenido['asunto'], contenido['msj'],
contenido.get('email',''),['webmasterd@test.com'],)
return render(request, 'gracias.html')
else:
miForm = FormContacto()
return render(request, 'form_contacto.html', {"form":miForm})
templates/form_contacto.html
...
<body>
<h1>Formulario de contacto</h1>
{% if forms.errors %}
<p style="color:red;"> Por favor revisa este campo</p>
{% endif %}
<form action="" method="POST">{% csrf_token %}
<table>
{{ form.as_table}}
</table>
<input type="submit" value="Enviar">
</form>
</body>
...
Ir a: Repositorio, Wiki