Crea una aplicación Todo con Django. Parte 1

Hola de nuevo. En previsión del comienzo del curso para desarrolladores web de Python, nuestro escritor independiente ha preparado material interesante que nos complace compartir con usted.




Django es un potente marco de aplicaciones web. Inicialmente, Django se creó para crear rápidamente, por ejemplo, sitios de noticias (u otros sitios que deben crearse lo más rápido posible). Y después de PHP nativo, la sensación de que estás manejando una máquina de desarrollo muy rápida no se va. Para ver todas sus características para un desarrollo rápido, intentaremos crear una aplicación Todo sencilla.



Comencemos con la redacción del corto t.z. Tendremos una pequeña aplicación web con diseño en Bulma (sí, realmente me gusta Bulma. Quizás algún día apague Bootstrap o Picnic, pero todo tiene su momento). Nosotros (hasta ahora) no tenemos autorizaciones y el usuario puede crear, editar y eliminar la categoría de tareas o la tarjeta de tareas, que está asociada con cualquier categoría que haya creado el usuario. Se puede eliminar una tarjeta o categoría Todo marcando la casilla de verificación y haciendo clic en el botón Eliminar.

Conceptos básicos de Django


Hablemos un poco sobre Django. Django implementa el patrón arquitectónico MVT (Model View Template), que es ligeramente diferente del conocido MVC (Model View Controller) que ejecuta Ruby on Rails y Laravel.

Modelo El modelo en Django describe el esquema de datos en la base de datos. Con Django ORM, puede describir de forma independiente los campos y cualquier otro tipo de datos, y realizar migraciones para simplificar el desarrollo.

Vista En una vista en Django, configura la lógica básica y los algoritmos de la aplicación, obtiene varios datos de la base de datos o los manipula. La vista generalmente se basa en las funciones de solicitud \ respuesta. La respuesta generalmente es redirección HTTP, error HTTP (404), MimeTypes o algún tipo de patrón.

ModeloLa plantilla en Django es un código HTML simple con un lenguaje de plantilla especial Django. DTL (Django Template Language) es un idioma con el que puede cambiar dinámicamente el contenido de una página (por ejemplo, cambiar el nombre de usuario en una página, dependiendo del nombre del usuario autorizado).

Configuración El archivo de configuración en Django, que contiene todas las configuraciones para su aplicación web. Incluye una clave secreta, carpetas de plantillas, middlewares (que son responsables, por ejemplo, de evitar que otros usuarios vean sus álbumes privados), una conexión de base de datos y mucho más.

Url El archivo de configuración de enrutamiento es casi el mismo que en Angular o Laravel. Esto asocia la vista con las solicitudes de URL.

Página de administrador Dado que Django se diseñó originalmente para la creación rápida de prototipos y la implementación de sitios de noticias, el panel de administración se incluye de forma predeterminada.

Instalar Python y Django


Retiro creativo
( ) . Python . , . , .

Versiones de Python


Hasta hace poco, dos ramas principales de Python fueron apoyadas y desarrolladas activamente: 2.7 y 3.x. Usaré la versión 3.7.3 en este artículo, pero de hecho no es tan importante. Si realmente quieres saber la diferencia entre los dos, hay un wiki especial . Por otro lado, ahora no tiene sentido usar Python versión 2.7: la actualización del idioma se detuvo en 2.7.17 (si entiendo la documentación en el sitio oficial correctamente). Esto significa que tiene sentido transferir proyectos escritos en Python 2.7.x a una nueva rama, pero escribir nuevos en 2 versiones es completamente inútil.

Instalación de Python


Si está trabajando en Mac o Ubuntu, probablemente ya tenga instalado Python, pero hay 2 versiones. Python de la tercera versión tendrá que descargarse por separado, y puede llamarlo en la línea de comando a través de python3. En cualquier caso, es mejor descargar la última versión aquí .

Crea tu propio entorno virtual


De hecho, puede comenzar a desarrollar la primera aplicación en Django sin crear su propio entorno virtual, pero la habilidad de crear un entorno virtual puede ser útil si, por ejemplo, desarrolla una aplicación con una versión específica de la biblioteca y no desea instalar bibliotecas a nivel mundial y ensuciar su sistema.

Entonces, ¿cómo se usa el entorno virtual?



1) La opción más fácil. Puede descargar el maravilloso IDE de JET BRAINS PyCharm Community Edition desde aquí . Después de instalar PyCharm, cree un nuevo proyecto, y Pycharm le ofrecerá crear Virtual Env por defecto, en el cual será posible instalar la versión requerida de Django (o por defecto la última, que al momento de escribir este artículo 3.0.2):

pip3 install django

2) Una opción un poco más hardcore:

¿Qué sucede si desea ejecutar Django en virtual env, por ejemplo, en su carpeta favorita?
Primero, cree una carpeta en la que crearemos:

	mkdir myfirstdjango && cd myfirstdjango

Luego, ingrese los siguientes comandos para activar venv, donde django_env es el nombre de nuestro entorno virtual:

	python3 -m venv django_env
	source django_env/bin/activate

Además, nuestro entorno virtual se activó. Podemos suministrar los paquetes necesarios. En nuestro caso, este es Django:

	pip3 install django

Si desea desactivar el entorno virtual para volver a su python global (volver al contexto del sistema), ingrese el siguiente comando:

    deactivate

Bueno, espero que hayamos descubierto el entorno virtual. Si tiene algún problema y preguntas adicionales, puede encontrar enlaces útiles aquí y aquí .

Creando el proyecto en sí


Suponga que elige una de las formas de crear su propio entorno virtual (o incluso hacer todo a nivel mundial, bueno, nadie le prohíbe hacerlo). Ahora vamos a la carpeta del proyecto y comenzamos su creación:

    django-admin startproject todo  #    
    cd todo #  
    python manage.py startapp todolist  #   todolist
	python3 manage.py runserver 8100 #      , 8000  
 

Entonces, después de que Django abrió la página de inicio, debe instalar nuestra aplicación todolist en la aplicación principal. Abra settings.pyy agregue a nuestra lista existente de aplicaciones nuestra propia lista de reproducción:

INSTALLED_APPS = [
	# ,     ,     
    'todolist',
]

El siguiente paso es vincular la aplicación con la base de datos. Si las bases de datos no son con lo que desea meterse, debe usar la solución predeterminada, SQlite. Decidí usar PostgreSQL: es popular y está relacionado clásicamente con Django, además, es posible que queramos aumentar el rendimiento de la aplicación. Hay muchas instrucciones sobre cómo instalar PostgreSQL en todos los sistemas operativos. Estoy desarrollando para MacOS y con algunos pequeños bailes con una pandereta, instalé esta base de datos descargando Postgres.app desde aquí . En cuanto a las interfaces para la base de datos, aquí utilicé Posticoy una versión de prueba para desarrollar la aplicación es suficiente para nosotros (aunque, en principio, puede prescindir de ella, porque toda nuestra interacción con la base de datos se desarrollará a través de la aplicación web y la migración). Además, tuve que poner psycopg2 en el entorno virtual del proyecto (sin este controlador, su aplicación no funcionará con la base de datos).

A continuación, debe configurar el trabajo de la estática. Todavía estamos editando el archivo settings.py, ahora al final agregamos trabajo con estadísticas:

STATIC_URL = '/static/'
PROJECT_ROOT = os.path.dirname(os.path.abspath(__file__))
STATIC_ROOT = os.path.join(PROJECT_ROOT, 'static')
STATICFILES_STORAGE = 'whitenoise.django.GzipManifestStaticFilesStorage'

Para que sus estadísticas funcionen, verifique que el paquete responsable de las estadísticas esté en la lista INSTALLED_APPS :

django.contrib.staticfiles,en caso de que ocurra un error.
Y lo último en el trabajo preparatorio, todavía necesitamos configurar el trabajo básico de url en el proyecto:

	from django.conf.urls import url
	from django.contrib import admin
	from todolist.views import todo
	from todolist.views import category
	from todolist.views import redirect_view
 
urlpatterns = [
	url(r'$^', redirect_view ),
	url(r'^admin/', admin.site.urls),
	url(r'^todo/', todo, name="TodoList"),
	url(r'^category/', category, name="Category"),
]

Agregué una redirección porque quiero que localhost vaya directamente a la subpágina de categoría desde la página predeterminada (para que Dios no permita que el usuario no se pierda). También tenemos enrutamiento de dos páginas: categorías y casos.

Entonces, espero que su aplicación no se bloquee. A continuación, finalmente podemos pasar a crear la aplicación en sí:

Creando un Modelo Todo y Categorías


A continuación, comenzaremos a crear un modelo que interactuará fundamentalmente con nuestra base de datos. Para crear un modelo, abra el archivo models.pyen nuestra lista de tareas y comience a crear. Comencemos creando una tabla de categorías:

from django.utils import timezone #     todo
from django.db import models
 
class Category(models.Model): #     models.Model
    name = models.CharField(max_length=100) #varchar.    
	class Meta:
    	verbose_name = ("Category") #   
    	verbose_name_plural = ("Categories")  #    
    def __str__(self):
        return self.name  # __str__      

¡Multa! Sí, aquí solo tendremos dos columnas en la tabla Categorías: id y nombre. Luego, crea una tabla para nuestros asuntos. Creo que todo está claro por los comentarios:

class TodoList(models.Model):
	title = models.CharField(max_length=250)
	content = models.TextField(blank=True) # 
	created = models.DateField(default=timezone.now().strftime("%Y-%m-%d")) #  
	due_date = models.DateField(default=timezone.now().strftime("%Y-%m-%d")) #      
	category = models.ForeignKey(Category, default="general",on_delete=models.PROTECT) # foreignkey          
	class Meta: #       
        ordering = ["-created"] #     
	def __str__(self):
    	return self.title

Una vez que su modelo esté listo, debe crear migraciones:

	python3 manage.py makemigrations

Y luego ejecutan las migraciones ellos mismos:

	python3 manage.py migrate

Crear vista


Abra el archivo view.pyen todolist y edítelo. Primero, agregue las importaciones necesarias y redirija de la categoría principal a la siguiente:

from django.shortcuts import render, redirect #      
from django.http import HttpResponse
from .models import TodoList, Category #   
 
def redirect_view(request):
	return redirect("/category") #     

Entonces comenzamos la creación de nuestro negocio. La instancia del caso tendrá campos del texto en sí, la fecha en que se debe completar el caso, la categoría del caso y el contenido combinado:

def todo(request):
	todos = TodoList.objects.all() #   todo   
    categories = Category.objects.all() #    

Después de eso, agregue las funciones de agregar y eliminar casos:

if request.method == "POST": #     POST
	if "Add" in request.POST: #   todo
    	title = request.POST["description"] # 
    	date = str(request.POST["date"]) #,      
        category = request.POST["category_select"] #,      .
        content = title + " -- " + date + " " + category #   
    	Todo = TodoList(title=title, content=content, due_date=date, category=Category.objects.get(name=category))
    	Todo.save() #   
        return redirect("/todo") #   (        )
    if "Delete" in request.POST: #     
        checkedlist = request.POST.getlist('checkedbox') #    ,    
        for i in range(len(checkedlist)): # -    
            todo = TodoList.objects.filter(id=int(checkedlist[i]))
        	todo.delete() # 
return render(request, "todo.html", {"todos": todos, "categories": categories})

Eso es todo con los dedos de los pies. Luego podemos ir a la página Categorías. Creamos una función de categorías en la que también tendremos la función de agregar y eliminar una categoría. Fundamentalmente, no habrá nada nuevo aquí, también tendremos la capacidad de agregar y eliminar:

def category(request):
	categories = Category.objects.all()  #   
	if request.method == "POST": #    POST
    	if "Add" in request.POST: #  
        	name = request.POST["name"] #  
        	category = Category(name=name) #     
            category.save() #   
        	return redirect("/category")
    	if "Delete" in request.POST: #    
            check = request.POST.getlist('check') #       todo,       
            for i in range(len(check)):
            	try:
                	ateg = Category.objects.filter(id=int(check[i]))
                	ateg.delete()   # 
            	except BaseException: #        ,       
                	return HttpResponse('<h1>     )</h1>')
	return render(request, "category.html", {"categories": categories})

Aquí es donde terminamos con el archivo viewy podemos pasar a las plantillas:

Trabaja con plantillas


Como recordarán, para no volver a escribir CSS, solía bulma.csssimplificar el diseño. Porque nuestras páginas de categoría y todo serán muy similares, creé tres archivos:
base.htmlque incluirán todo lo mismo que tenemos en las páginas, y en category.htmllas todo.htmldiferencias se ubicarán:



Crear base.htmly editar:

<!DOCTYPE html>
<html lang="ru">
<head>
  <meta charset="UTF-8">
  <title>   </title>
  {% load static %}
	<link rel="shortcut icon" type="image/png" href="{% static 'favicon.png' %}"/>
   <link rel="stylesheet" type="text/css" href="{% static 'bulma.min.css' %}">
	<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css">
</head>
<body>
<div django-app="TaskManager">
	<nav class ="navbar is-success" role="navigation" aria-label="main navigation">
     	<div class="navbar-menu ">
        	<div class="navbar-start">
        	<a class="navbar-item" href="../category"> </a>
        	<a class="navbar-item" href="../todo">   </a>
        	</div>
         </div>
	</nav>
<!--               -->
{% block content %}
{% endblock %}
</div>
</body>
</html>

A continuación, iremos a la página todo.htmly category.html:

Tudushka:

{% extends 'base.html' %}
{% block content %}
<div class="columns has-background-black-ter is-centered has-text-white-bis" style="min-height:101vh;">
	<!--        hero,     inline-css -->
	<div class="column is-half">
    	<h1 class="is-size-3 has-text-centered">   </h1>
    	<form action="" method="post">
        	{% csrf_token %}
        	<!-- csrf      -->
            <div class="field has-text-centered">
            	<label for="description" class="label has-text-white-bis"> </label>
            	<div class="control">
             	   <input type="text" id="description" class="input" placeholder="  ?"
                    	name="description" required>
            	</div>
        	</div>
        	<div class="columns">
            	<div class="column">
                	<label for="category"></label>
                	<div class="control">
                    	<div class="select">
                        	<select id="category" class="select" name="category_select" required>
                            	<!--  required,       .    -->
                            	<option class="disabled" value="">  </option>
                    	        {% for category in categories %}
 	                           <option class="" value="{{ category.name }}" name="{{ category.name }}">
                                    {{ category.name }}</option>
                            	{% endfor %}
                        	</select>
    	                </div>
                	</div>
            	</div>
            	<div class="column">
                	<label for="dueDate"> </label>
                	<input type="date" id="dueDate" class="input calendar" name="date" required>
            	</div>
        	</div>
        	<div class="column">
            	<div class="field">
                	<button class="button is-primary" name="Add" type="submit">
                    	<span class="icon is-small">
                        	<i class="fa fa-plus"></i>
                    	</span>
                    	<span> </span>
                	</button>
             	   <button class="button is-link" name="Delete" formnovalidate="" type="submit">
                    	<span class="icon is-small">
                        	<i class="fa fa-trash-o"></i>
                    	</span>
                    	<span>
                        	 
                    	</span>
                	</button>
            	</div>
        	</div>
        	<div class="list is-hoverable">
            	{% for todo in todos %}
            	<!--   django- for loop -->
            	<div class="list-item">
                	<label class="checkbox">
                    	<input type="checkbox" class=" checkbox" name="checkedbox" value="{{ todo.id }}">
                    	<span class="complete-">{{ todo.title }}</span>
                	</label>
                	<span class=" category-{{ todo.category }} has-text-info">{{ todo.category }}</span>
                	<strong class="is-pulled-right"><i class="fa fa-calendar"></i>{{ todo.created }} -
                    	{{ todo.due_date }}</strong>
            	</div>
            	{% endfor %}
        	</div>
    	</form>
	</div>
</div>
{% endblock %}

Y category.html. En él, no tenemos muchos cambios, no difiere fundamentalmente de todo.html:

{% extends 'base.html' %}
{% block content %}
<div class="columns has-background-link has-text-white is-centered" style="min-height: 101vh;">
	<div class="column is-half">
    	<h1 class="is-size-4 has-text-centered">    </h1>
    	<form action="" method="post">
        	{% csrf_token %}
        	<!-- csrf      -->
            <div class="field has-text-centered">
            	<label for="description" class="label has-text-white-bis">   </label>
            	<div class="control">
     	           <input type="text" id="description" class="input" placeholder="    ?"
                    	name="name" required>
            	</div>
            	<div class="field">
                	<button class="button is-primary" name="Add" type="submit">
                    	<span class="icon is-small">
                        	<i class="fa fa-plus"></i>
                    	</span>
                    	<span> </span>
                	</button>
                	<button class="button is-danger" name="Delete" formnovalidate="" type="submit">
                    	<span class="icon is-small">
           	             <i class="fa fa-trash-o"></i>
                    	</span>
	                    <span>   </span>
                	</button>
            	</div>
            </div>
 
            <!--  c   -->
            <div class="list is-hoverable">
            	{% for category in categories %}
            	<div class="list-item">
                	<label class="checkbox">
                    	<input type="checkbox" class="checkbox" name="check" value="{{category.id}}">
                    	<span class="complete-">{{ category.name }}</span>
                	</label>
            	</div>
            	{% endfor %}
 
        	</div>
    	</form>
	</div>
    {% endblock %}
 

¡Gracias a todos! Eso es todo. Quizás, en algún lugar, el diseño no es perfecto, o hay otras sugerencias para mejorar la aplicación, estoy esperando a todos en el comentario. Por tradición, algunos enlaces útiles:

  1. Django, 3
  2. ,
  3. PostgreSQL

All Articles