2020-11-16 21:26:55 -03:00
|
|
|
**Ir a:**
|
|
|
|
[*Repositorio*](https://gitea.kickto.net/jp.av.dev/intro_Django#user-content-django-wiki),
|
|
|
|
[*Wiki*](https://gitea.kickto.net/jp.av.dev/intro_Django/wiki/_pages)
|
2020-11-16 21:21:10 -03:00
|
|
|
|
|
|
|
-------
|
|
|
|
|
|
|
|
## Proyecto y Aplicacion(es)
|
|
|
|
|
|
|
|
### Modularización
|
|
|
|
|
|
|
|
*ej. Proyecto1*
|
|
|
|
```
|
|
|
|
__________________________________
|
|
|
|
| Proyecto Tienda Online |
|
|
|
|
| |
|
|
|
|
| App1 App2 |
|
|
|
|
| [Panel Control] [Stock] |
|
|
|
|
| |
|
|
|
|
| App3 App4 |
|
|
|
|
| [Ventas] [Pagos] |
|
|
|
|
| |
|
|
|
|
| App5 App6 |
|
|
|
|
| [Envíos] [Promos] |
|
|
|
|
|__________________________________|
|
|
|
|
```
|
|
|
|
|
|
|
|
*ej. Proyecto2*
|
|
|
|
```
|
|
|
|
__________________________________
|
|
|
|
| Proy. Gestión Almacen |
|
|
|
|
| |
|
|
|
|
| App1 App2 |
|
|
|
|
| [Proveedores] [Stock] |
|
|
|
|
| |
|
|
|
|
| App3 App4 |
|
|
|
|
| [Ventas] [Pagos] |
|
|
|
|
| |
|
|
|
|
| App5 App6 |
|
|
|
|
| [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>]>
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
|
2020-11-16 21:26:55 -03:00
|
|
|
-------
|
|
|
|
|
2020-11-16 21:21:10 -03:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
## Panel de Administrador
|
|
|
|
|
|
|
|
### Activo por defecto
|
|
|
|
|
|
|
|
*settings.py*
|
|
|
|
```
|
|
|
|
...
|
|
|
|
INSTALLED_APPS = [
|
|
|
|
'django.contrib.admin',
|
|
|
|
...
|
|
|
|
```
|
|
|
|
*urls.py*
|
|
|
|
```
|
|
|
|
...
|
|
|
|
urlpatterns = [
|
|
|
|
path('admin/', admin.site.urls),
|
|
|
|
...
|
|
|
|
```
|
|
|
|
[*enlace a admin*](http://192.168.0.4:8000/admin/)
|
|
|
|
|
|
|
|
### 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|email|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*](http://192.168.0.4:8000/admin/gestionPedidos/clientes/add/)
|
|
|
|
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**
|
|
|
|
![img](https://gitea.kickto.net/jp.av.dev/intro_Django/raw/branch/master/TiendaOnline/gestionPedidos/img/admin-filtro-fecha.png)
|
|
|
|
|
|
|
|
|
|
|
|
### Cambiar Idioma
|
|
|
|
*settings.py*
|
|
|
|
```
|
|
|
|
#LANGUAGE_CODE = 'en-us'
|
|
|
|
LANGUAGE_CODE = 'es-CL'
|
|
|
|
```
|
|
|
|
- [LANGUAGE_CODE](http://www.i18nguy.com/unicode/language-identifiers.html)
|
|
|
|
- [Django-doc](https://docs.djangoproject.com/en/3.1/ref/contrib/admin/)
|
|
|
|
|
|
|
|
### 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.
|
|
|
|
|
|
|
|
|
|
|
|
|
2020-11-16 21:26:55 -03:00
|
|
|
-------
|
|
|
|
|
|
|
|
|
2020-11-16 21:21:10 -03:00
|
|
|
|
2020-11-16 21:26:55 -03:00
|
|
|
|
2020-11-16 21:21:10 -03:00
|
|
|
|
|
|
|
## Formularios
|
|
|
|
[*Forms doc*](https://docs.djangoproject.com/en/3.1/topics/forms/)
|
|
|
|
|
|
|
|
### 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**](https://docs.djangoproject.com/en/3.0/ref/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),`
|
|
|
|
...
|
|
|
|
```
|
|
|
|
|
2020-11-16 21:26:55 -03:00
|
|
|
|
|
|
|
-------
|
|
|
|
|
2020-11-16 21:21:10 -03:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
## 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](https://docs.djangoproject.com/en/dev/ref/settings/#email-host)
|
|
|
|
[django.core.mail-doc](https://docs.djangoproject.com/en/3.0/topics/email/#module-django.core.mail)
|
|
|
|
|
|
|
|
🔸️***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")
|
|
|
|
```
|
2020-11-16 21:26:55 -03:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
-------
|
2020-11-16 21:21:10 -03:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
## API Forms
|
|
|
|
|
|
|
|
### Creación de formularios con API Forms
|
|
|
|
|
|
|
|
Simplifica la creación de formularios e incluye validacion.
|
|
|
|
|
|
|
|
[*API Forms doc*](https://docs.djangoproject.com/en/3.1/ref/forms/api/)
|
|
|
|
[*Indice Forms Api doc*](https://docs.djangoproject.com/en/3.1/ref/forms/#forms)
|
|
|
|
|
|
|
|
|
|
|
|
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>
|
|
|
|
...
|
|
|
|
```
|
|
|
|
|
|
|
|
|
2020-11-16 21:26:55 -03:00
|
|
|
-------
|
|
|
|
|
|
|
|
|
|
|
|
**Ir a:**
|
|
|
|
[*Repositorio*](https://gitea.kickto.net/jp.av.dev/intro_Django#user-content-django-wiki),
|
|
|
|
[*Wiki*](https://gitea.kickto.net/jp.av.dev/intro_Django/wiki/_pages)
|