使用Django创建Todo应用程序。第1部分

再一次问好。期待Python Web Developer课程的开始我们的自由撰稿人准备了一些有趣的材料,我们很乐意与您分享。




Django是一个功能强大的Web应用程序框架。最初,创建Django是为了快速创建例如新闻站点(或需要尽快创建的其他站点)。在使用本机PHP之后,不会感到您正在使用非常快速的开发机器。为了查看其快速开发的所有功能,我们将尝试创建一个简单的Todo应用程序。



让我们从简短的t.z的措词开始。我们将有一个小型的Web应用程序,其布局在Bulma上(是的,我非常喜欢Bulma。也许有一天,我将关闭Bootstrap或Picnic,但一切都有时间)。我们(到目前为止)没有授权,用户可以创建,编辑和删除待办事项类别或待办事项卡,后者与用户创建的任何类别相关联。可以通过选中复选框并单击删除按钮来删除待办事项卡或类别。

Django核心概念


让我们谈谈Django。 Django实现了MVT(模型视图模板)架构模式,该模型与运行Ruby on Rails和Laravel的熟悉的MVC(模型视图控制器)略有不同。

模型 Django中的模型描述了数据库中的数据方案。使用Django ORM,您可以独立描述字段和任何其他数据类型,并进行迁移以简化开发。

查看在Django的视图,您设置的基本逻辑和应用的算法,从数据库中获取的各种数据或操纵它。该视图通常基于request \ response函数。响应通常是HTTP重定向,HTTP错误(404),MimeTypes或某种模式。

模板Django中的模板是带有特殊模板语言Django的简单HTML代码。 DTL(Django模板语言)是一种可以用来动态更改页面内容的语言(例如,根据授权用户的名称更改页面上的用户名)。

设置 Django中的设置文件,其中包含Web应用程序的所有设置。它包括一个秘密密钥,模板文件夹,中间件(例如,负责防止其他用户看到您的私人相册的中间件),数据库连接等等。

网址路由配置文件与Angular或Laravel中的大致相同。这会将视图与url请求相关联。

管理员页面 由于Django最初是为新闻网站的快速原型制作和部署而设计的,因此默认情况下包含管理面板。

安装Python和Django


创意撤退
( ) . Python . , . , .

Python版本


直到最近,两个主要的Python分支都得到了积极的支持和开发:2.7和3.x。我将在本文中使用3.7.3版,但实际上并不是那么重要。如果您真的想知道两者之间的区别,可以使用一个特殊的wiki另一方面,现在使用Python版本2.7是没有意义的-语言更新在2.7.17停止(如果我正确理解了官方网站上的文档)。这意味着将用Python 2.7.x编写的项目转移到一个新分支是有意义的,但是用2个版本编写新项目是完全没有意义的。

Python安装


如果您使用的是Mac或Ubuntu,则可能已经安装了Python,但是有2个版本。第三版本的Python必须单独下载,您可以通过python3在命令行上调用它。无论如何,最好在这里下载最新版本

创建自己的虚拟环境


实际上,您可以在不创建自己的虚拟环境的情况下开始在Django上开发第一个应用程序,但是例如,如果您开发的应用程序具有特定版本的库并且不想在全球范围内安装库并乱扔您的系统,则创建虚拟环境的技能会派上用场。

那么如何使用虚拟环境呢?



1)最简单的选择。您可以从此处从JET BRAINS PyCharm社区版下载出色的IDE 。安装PyCharm之后,创建一个新项目,Pycharm将默认为您提供创建Virtual Env的功能,可以在其中安装所需版本的Django(或默认情况下为最新版本,在撰写本文时为3.0.2):

pip3 install django

2)一个稍微强硬的选项:

如果要在虚拟环境中运行Django,例如在您喜欢的文件夹中怎么办?
首先,创建一个文件夹,我们将在其中创建:

	mkdir myfirstdjango && cd myfirstdjango

接下来,输入以下命令以激活venv,其中django_env是我们的虚拟环境的名称:

	python3 -m venv django_env
	source django_env/bin/activate

此外,我们的虚拟环境已激活。我们可以提供必要的包装。在我们的例子中,这是Django:

	pip3 install django

如果要关闭虚拟环境以返回到全局Python(返回到系统上下文),请输入以下命令:

    deactivate

好吧,我希望我们弄清楚了虚拟环境。如果您有任何问题和其他问题,可以在此处此处找到有用的链接

创建项目本身


假设您选择一种创建自己的虚拟环境的方法(或者甚至在全球范围内进行所有操作,没有人禁止您这样做)。现在,我们进入项目文件夹并开始创建:

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

因此,在Django打开起始页后,您需要在主应用程序中安装我们的todolist应用程序。打开settings.py我们自己的待办事项列表并将其添加到我们现有的应用程序列表中:

INSTALLED_APPS = [
	# ,     ,     
    'todolist',
]

下一步是将应用程序与数据库链接。如果数据库不是您想要弄乱的东西,则应使用默认解决方案SQlite。我决定使用PostgreSQL-此外,它很流行,并且与Django有关,在传统上,我们可能想提高应用程序的性能。关于如何在所有操作系统上安装PostgreSQL的说明很多。我正在为MacOS进行开发,并且有一些铃鼓的小舞蹈,因此我从此处下载Postgres.app安装了该数据库。至于数据库的接口,我在这里使用了Postico开发我们的应用程序的试用版对我们来说已经足够了(尽管原则上您可以不用它,因为我们与数据库的所有交互都将通过Web应用程序本身和迁移来构建)。另外,我必须将psycopg2放在项目的虚拟环境中(没有此驱动程序,您的应用程序将无法与数据库一起使用)。

接下来,您需要配置静态工作。我们仍在编辑文件settings.py,现在最后我们添加了静态函数:

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'

为了使您的静态代码正常工作,请检查负责静态消息软件包是否INSTALLED_APPS列表中

django.contrib.staticfiles,以防发生错误。
在准备工作的最后一件事,我们仍然需要在项目中配置url的基本工作:

	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"),
]

我添加了重定向,因为我希望localhost从默认页面直接转到类别页面(因此,上帝禁止用户不丢失)。我们还有两页的路由:类别和案例。

因此,希望您的应用程序不会崩溃。接下来,我们最终可以继续创建应用程序本身:

创建待办事项模型和类别


接下来,我们将开始创建一个模型,该模型将从根本上与我们的数据库进行交互。要创建模型,请models.py在我们的待办事项列表中打开文件并开始创建。让我们从创建类别表开始:

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__      

精细!是的,这里我们在类别表中只有两列:id和name。接下来,为我们的事务创建一个表。我认为所有评论都清楚:

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

模型准备就绪后,您需要创建迁移:

	python3 manage.py makemigrations

然后自己运行迁移:

	python3 manage.py migrate

建立检视


view.py在待办事项清单中 打开文件并进行编辑。首先,添加必要的导入并将其从主目录重定向到类别:

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

然后,我们开始创建业务。案例的实例将具有文本本身的字段,完成案例的日期,案例的类别以及合并的内容:

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

之后,添加添加和删除案例的功能:

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})

这就是脚趾。然后,我们可以转到“类别”页面。我们创建了一个类别功能,其中还具有添加和删除类别的功能。从根本上讲,这里没有新内容,我们还可以添加和删除:

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})

这是我们以文件结尾的位置view,可以移至模板:

使用模板


您还记得,为了不再次编写CSS,我曾经bulma.css简化了布局。因为 我们的类别页面和待办事项将非常相似,我创建了三个文件:
base.html它将包含我们在页面上拥有的所有文件,而在中category.html,将找到todo.html不同之处:



创建base.html和编辑它:

<!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>

接下来,我们将转到页面 todo.htmlcategory.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 %}

category.html在其中,我们没有太多变化,从根本上来说与以下内容没有什么不同 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 %}
 

谢谢大家!就这样。也许在某处布局不完美,或者还有其他建议可以改善应用程序,我正在等待所有人发表评论。按照传统,一些有用的链接:

  1. Django, 3
  2. ,
  3. PostgreSQL

All Articles