Este proyecto está basado con conocimientos básicos que se exponen en el repositorio de project-django. Se va a mencionar conceptos que fueron mencionados en ese repositorio y se va a ir complementando con forme se vaya aumentando la dificultad.
Recordar que las buenas prácticas consiste en:
- Crear carpeta del proyecto.
mkdir carpeta
- Inicializar git.
git init
- Crear entorno virtual.
python3 -m venv venv
- Activar entorno virtual.
source ./venv/bin/activate
- Hacer un documento txt en donde esten las dependencias que utilicemos.
pip freeze > requirements.txt
- Instalar dependencias:
pip install -r requirements.txt
Es importante recordar que a lo largo de la vida del proyecto hay que estar guardando las dependencias.
Hay que recordar que se tiene dos formas de instalar Django.
python3 -m pip install Django
ó
pip install django
Para verificar la versión es:
django-admin --version
El proyecto va a tener como nombre crud-auth
django-admin startproject crud-auth .
La aplicación se va a llamar tasks
pythn manage.py startapp tasks
python manage.py runserver
Cuando se crea la app hay que recordar que se tiene que vincualar con las app del proyecto, se abre la carpeta del proyecto y se va al archivo de settings.py, se busca el array con nombre de INSTALLED_APPS y se agrega al final la app que se hizo.
Para cuando se crea un nuevo modelo recordemos que se utiliza el siguiente comando:
python manage.py makemigrations
Para crear todos los modelos es con el siguiente comando:
python manage.py migrate
Url del proyecto
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('', include("tasks.urls"))
]
Url de la app
from django.urls import path
from . import views
urlpatterns = [
path('signup/', views.signup, name='signup')
]
from django.shortcuts import render, redirect
from django.http import HttpResponse
from django.contrib.auth.forms import UserCreationForm
#Ésta clase nos entrega el forms para el usuario
from django.contrib.auth.models import User
#Tabla User
def signup(request):
error = ''
if request.method == 'GET':
error= ''
else:
username = request.POST['username']
password1 = request.POST['password1']
password2 = request.POST['password2']
if password1 == password2:
try:
user = User.objects.create_user(username=username, password=password1)
user.save()
error = 'Usario creado'
except:
error = 'Usuario ya existe'
else:
error = 'Las contraseñas no son iguales'
# Al final retorna a la misma página y manda una cadena de texto
return render(request, 'signup.html', {
'forms': UserCreationForm,
'error': error
})
<h1>Signup</h1>
<form method="post">
<!-- Llave de seguridad -->
{% csrf_token %}
<!-- Formulario -->
{{ forms.as_p }}
<button>Guardar</button>
</form>
<h3>{{ error }}</h3>
Para hacer que quede registrado en las cookies hay que ingresar el siguiente módulo:
from django.contrib.auth import login
Se integra en la función:
...
if password1 == password2:
try:
user = User.objects.create_user(username=username, password=password1)
user.save()
error = 'Usario creado'
login(request, user)
# Registrar en la cokie el request y el usuario.
return redirect('/')
...
Para ver que ya guarden estos datos hay que inspeccionar el sitio web, en el panel que te abra te iras a Aplicación, le das clic en Cookies y se muestran todas las que tienen el sistema.
Hasta ahora el código para el url tiene lo siguiente:
from django.urls import path
from . import views
urlpatterns = [
path('signup/', views.signup, name='signup'),
path('', views.home, name='home'),
path('login/', views.sigin, name='login')
#Url de login
]
La función de la vista queda de la siguiente forma:
from django.contrib.auth import login, authenticate
def sigin(request):
error = ''
if request.method == 'GET':
error=''
else:
username = request.POST['username']
password = request.POST['password']
user = authenticate(request, username=username, password=password)
# Devuelve el nombre usuario si es que existe
if user is None:
error = 'Verifica usuario/contraseña'
else:
login(request, user)
return redirect('/')
return render(request, 'login.html', {
'form': AuthenticationForm,
'error': error
})
El código queda de la siguiente forma:
<h1>LOGIN</h1>
<form method="post">
{% csrf_token %}
{{form.as_p}}
<button>Login</button>
</form>
<h3>{{error}}</h3>
Esta sección se conoce en el project-django como Reutilizar plantillas
El código queda de la siguiente forma:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>DJANGO CRUD</title>
</head>
<body>
<ul>
{% if user.is_authenticated %}
{# Cuando se inicia sesión se crea una variable global con el nombre de user
Por esta variable se puede saber si ya inicio sesión o no el usuario
La variable user está relacionada con el metodo login de view #}
<li><a href="/logout">Cerrar sesión</a></li>
{% else %}
<li><a href="/login">Iniciar sesión</a></li>
{% endif %}
</ul>
{% block content %}
{% endblock content %}
</body>
</html>
from django.urls import path
from . import views
urlpatterns = [
path('signup/', views.signup, name='signup'),
path('', views.home, name='home'),
path('login/', views.sigin, name='login'),
path('logout/', views.signout, name='logout')
]
from django.contrib.auth import login, authenticate, logout
def signout(request):
logout(request)
return redirect('/login')
La plantilla es la de base.html
from django.db import models
from django.contrib.auth.models import User
# Create your models here.
class Task(models.Model):
title = models.CharField( max_length=50 )
# As TextInput
description = models.TextField( blank=True )
#As TextArea
created = models.DateTimeField( auto_now_add=True )
# As DateField
date_completed = models.DateTimeField( null=True )
important = models.BooleanField( default=False )
user = models.ForeignKey(User, on_delete=models.CASCADE)
#on_delete = models.CASCADE is for when deleted a user their tasks also deleted
def __str__(self) -> str:
#Es para la vista en la interfaz del adminstrador
return self.title + ' <- ' + self.user.username
Compilar las tablas.
python manage makemigrations
Después para ya crear las tablas es con:
python manage migrate
Para poder ver las tablas que se van creando al panel de administrador es necesario hacer lo siguiente:
- Ir al archivo admin.py de la app y agregar lo siguiente:
from django.contrib import admin
from .models import Task
admin.site.register(Task)
- Crear a un superusuario y su contraseña,
python manage.py createsuperuser
- En el archivo de admin.py de la aplicación agregar lo siguiente:
from django.contrib import admin
from .models import Task
admin.site.register(Task)
Se va a crear el archivo forms.py y dentro se va a poner el siguiente código:
from django.forms import ModelForm
#Clase que hace herencia para crear un forms
from .models import Task
#La tabla con la que se va hacer un forms.
class TaskForm(ModelForm):
class Meta:
model = Task
#Tabla
fields = ['title', 'description', 'important']
# Se agrega los campos que se quiere hacer el formulario
...
path('login/', views.sigin, name='login'),
path('logout/', views.signout, name='logout'),
path('task/', views.task, name='tasks'),
path('task/create/', views.task_create, name='create_task')
]
from .forms import TaskForm
#Importamos el formulario
def task_create(request):
txt = None
if request.method == 'GET':
txt = ''
else:
print(request.POST)
txt = 'Tarea creada'
return render(request, 'create_task.html',{
'form' : TaskForm,
'text': txt
})
{% extends 'base.html' %}
{% block content %}
Crear tarea
<form method="POST">
{% csrf_token %}
{{form.as_p}}
<button>Crear</button>
</form>
{{text}}
{% endblock content %}
Para almacenar la base de datos se puede hacer de dos formas:
- Es la forma en como se vio en el repositorio de project-django
- Utilizando el mismo formulario se puede guardar todos los datos, quedaria de la siguiente forma:
def task_create(request):
txt = None
if request.method == 'GET':
txt = ''
else:
try:
form = TaskForm(request.POST)
# Genera el formulario
new_task = form.save(commit=False)
# Se almacena los datos correspondiente a su campo
#Commit=false es para que no se guarde en una instancia de Base de Datos
new_task.user = request.user
#request.user es el usuario de quien inicio sesión
new_task.save()
#Se guarda en base de datos
txt = 'Tarea creada'
except:
txt = 'No se pudo guardar los datos'
return render(request, 'create_task.html',{
'form' : TaskForm,
'text': txt
})
- Crar el url.
...
path('task/create/', views.task_create, name='create_task'),
path('task/<int:task_id>/', views.task_detail, name='task_detail'),
]
- Crear la vista.
def task_detail(request, task_id):
txt = ''
task = get_object_or_404(Task, pk=task_id, user=request.user)
#Va a obtener los datos de la tabla Tarea mediente la llave primaria
if request.method == 'GET':
form = TaskForm(instance=task)
#Crea un formulario ya con los datos rellenos
else:
try:
form = TaskForm(request.POST, instance=task)
#Llena el formulario con la información mandada con el metodo post mediante la instancia de la tarea
form.save()
#Se guarda
return redirect('tasks')
except:
txt = 'Error al actualizar datos'
return render(request, 'task.html', {'task': task, 'form': form, 'text': txt})
- Crear el template.
{% extends 'base.html' %}
{% block content %}
<form method="POST">
{% csrf_token %}
{{form.as_p}}
<button>Actualizar</button>
</form>
{{text}}
{% endblock content %}
- Crear el url:
...
path('task/<int:task_id>/', views.task_detail, name='task_detail'),
path('task/<int:task_id>/complete/', views.task_complete, name='task_complete'),
]
- Crear la vista.
from django.utils import timezone
def task_complete(request, task_id):
task = get_object_or_404(Task, pk=task_id, user=request.user)
if request.method == 'POST':
task.date_completed = timezone.now()
task.save()
return redirect('tasks')
- Crear el template No creo un template nuevo, lo redirecciono a la vista de las tareas.
- Crear el url:
...
path('task/<int:task_id>/complete/', views.task_complete, name='task_complete'),
path('task/<int:task_id>/delete/', views.task_delete, name='task_delete'),
]
- Crear la vista:
def task_delete(request, task_id):
task = get_object_or_404(Task, pk=task_id, user=request.user)
if request.method == 'POST':
task.delete()
return redirect('tasks')
Hago que se redireccione a la página de las Tareas.
Suponiendo que ya se tiene el url entonces:
def task(request):
tasks = Task.objects.filter( user = request.user, date_completed__isnull=True )
tasks_complete = Task.objects.filter( user = request.user, date_completed__isnull=False )
return render(request, 'tasks.html',{
'tasks': tasks,
'task_complete': tasks_complete
})
{% extends 'base.html' %}
{% block content %}
{% if tasks != null %}
Todas tus tareas pendientes son:
{% for task in tasks %}
<section>
<ul>
<li>
{{task.title}}
{% if task.important %}
❗❗❗
{% else %}
🐢🐢🐢
{% endif %}
</li>
<h4>
{{task.description}}
</h4>
<button>Actualizar</button>
</ul>
</section>
{% endfor %}
{% endif %}
{% if tasks_complete != null %}
Las tareas completadas son:
{% for task in tasks_complete %}
<section>
<ul>
<li>
{{task.title}}
{% if task.important %}
❗❗❗
{% else %}
🐢🐢🐢
{% endif %}
</li>
<h4>
{{task.description}}
</h4>
<button>Actualizar</button>
</ul>
</section>
{% endfor %}
{% endif %}
{% endblock content %}
Hay que recordar que se puede solicitar variables en la url de la siguiente forma:
...
path('task/', views.task, name='tasks'),
path('task/create/', views.task_create, name='create_task'),
path('task/<int:task_id>/', views.task_detail, name='task_detail'),
# <tipo_variable: nombre_variable>
]
Asi que en la vista quedaria de la siguiente forma:
from django.shortcuts import get_object_or_404
def task_detail(request, task_id):
task = get_object_or_404(Task, pk=task_id)
return render(request, 'task.html', {'task': task})
Y para el template seria...
{% extends 'base.html' %}
{% block content %}
<h1>{{task.title}}</h1>
<h2>{{task.description}}</h2>
{% endblock content %}
Es para no acceder a lugares si no ha iniciado sesión. En el archivo de views.py se agrega lo siguiente:
from django.contrib.auth.decorators import login_required
#Lo ponemos arriba de la función de la vista en donde indiquemos que debe de iniciar sesión para acceder
Ya lo que queda es ponerlo arriba de las funciones de las vistas, en mi caso quedo de la siguiente forma:
@login_required
def home(request):
...
@login_required
def signout(request):
...
def logout(request)
...
@login_required
def task_delete(request, task_id):
...
En settings.py se debe de anexar lo siguiente debajo de STATIC_URL:
#STATIC_URL = 'static/'
LOGIN_URL = '/login'
# = '/ruta_inicial'