Python编程-数据可视化:第18章-从Django入手

建立项目的方法

建立项目时,首先需要以规范的方式对项目进行描述,再建立虚拟环境,以便在其中创建项目。

制定规范

1、完整的规范详细说明了项目的目标

2、阐述了项目的功能

3、并讨论了项目的外观和用户界面。

4、只列出一些明确的目标,以突出开发的重点。

Warning

与任何良好的项目规划和商业计划书一样,规范应突出重点。帮助避免项目偏离归档。

项目规范

  1. 我们要编写一个名为“学习笔记”的Web应用程序

  2. 让用户能够记录感兴趣的主题,并在学习每个主题的过程中添加日志条目。

  3. 学习笔记”的主页对这个网站进行描述,并邀请用户注册或登录。

  4. 用户登录后,可以创建新主题、添加新条目以及阅读既有的条目。

完整的规范详细说明了项目的目标

建立虚拟环境

Linux 下建立虚拟环境

创建虚拟环境

python -m venv ll_env

这里运行了模块venv ,并使用它创建了一个名为ll_env的虚拟环境。(请注意,ll_env的开头是两个小写字母l,而不是数字1。)如果你运行程序或安装包时使用的是命令 python3 ,这里也务必使用同样的命令。

Note

其实就是在当前运行命令的目录下创建一个目录,这个目录包含所需的依赖包和运行环境

激活虚拟环境

source ll_env/bin/activate

安装Django

激活后,执行命令安装Django:

Warning

以下命令都需要激活虚拟环境。
pip 版本需要升级到最新版本,否则无法安装Django.

(ll_env) [python@node1 learning_log]$pip install --upgrade pip
(ll_env) [python@node1 learning_log]$ pip install django

由于是虚拟环境,所以不会在操作系统级别和用户级别的环境下安装依赖包。保证其他环境的干净,和本项目的独立性。

!Python 依赖包生效的级别.svg

Warning

注意: 每隔大约8个月,Django 新版本就会发布,因此你安装Django ,可能不会出问题,但是如果出了问题 请使用2.2 版本。

在Django 中创建项目

在虚拟环境激活的下:

diango-admin start startprojesct learning_log .
ls

处的命令让Django新建一个名为learning_log的项目。这个命令末尾的句点让新项目使用合适的目录结构,这样开发完成后可轻松地将应用程序部署到服务器。

创建数据库

Django将大部分与项目相关的信息存储在数据库中,因此需要创建一个供Django使用的数据库。为给项目“学习笔记”创建数据库,请在虚拟环境处于活动状态的情况下执行下面的命令

(ll_env) [python@node1 learning_log]$ python manage.py migrate

djangodatabase|300

我们将修改数据库称为迁移 (migrate)数据库。首次执行命令migrate 时,将让Django确保数据库与项目的当前状态匹配
Django将新建一个数据库。在❶处,Django指出它将准备好数据库,用于存储执行管理和身份验证任务所需的信息。

Warning

这里使用到的数据库为SQLite。

db.sqlite3|300

启动web 项目

source ~/ll_env/bin/activate
python manage.py  runserver

Django web启动界面|300

Warning

注意:这种启动方式,时这个项目只会在本地127.0.0.1地址进行监听,换句话说,你只能通过http://127.0.0.1:800/ 才能访问到web页面。
如果想要

Django 永久更改 的监听地址和PORT
Django 临时修改 的地址和端口

Warning

注意 如果出现错误消息That port is already in use(指定端口被占用).
可以使用命令行python manage.py runserver 8001 让Django使用另一个端口。

查看网页界面

Django 初始化页面|300

创建应用程序

创建应用程序

learning_log$ source ll_env/bin/activate
(ll_env)learning_log$ python manage.py startapp learning_logs
(ll_env)learning_log$ ls
db.sqlite3 learning_log learning_logs ll_env manage.py
(ll_env)learning_log$ ls learning_logs/
__init__.py admin.py apps.py migrations models.py tests.py views.py

命令startapp appname 让Django搭建创建应用程序所需的基础设施。我们将使用models.py来定义要在应用程序中管理的数据,

定义模型

from django.db import models
  
# Create your models here.


class Topic(models.Model):
    """用户学习的主题。"""
    text = models.CharField(max_length=200)
    date_added = models.DateTimeField(auto_now_add=True)
    
    def __str__(self):
        """返回模型的字符串表示。"""
        return self.text

上述代码创建了一个Topic 的类,是从models 继承而来。里面定义了模型的基本功能。我们给Topic类添加了两个属性:text 和date_added 。

属性text 是一个CharField 是文本类型。用户存储少量文本,如标题等,max_length=200 限制的文本的长度(200字符)。对于大多数存储标题名足够了。

date_added 是一个DateTimeField时间类型。用于记录日期和时间的数据。
auto_now_add=True 每当用户创建新主题时,Django都会设置为当前日期和时间。

Note

想要学习模型中使用的各种字段。参阅
Model field reference | Django documentation | Django (djangoproject.com)

需要告诉Django ,默认使用哪个属性来显示有关主题的信息。
Django 调用方法___str__() 来显示模型。

激活模型

要使用这些模型,必须使用Django 键前述应用程序包含到项目中。
打开setting.py ,其中有个片段告诉Django那些1应用程序被安装到了项目并协同工作。

INSTALLED_APPS = [
    # 我的应用程序
    'learning_logs',
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
]

随着项目不断增大,包含更多应用程序时,有助与应用程序进行跟踪。
这里的"我的应用程序" 片段。当前它只能包含应用程序”learning_logs" 。无比将自己创建的应用程序放在默认应用程序的签名啊这样能够覆盖应用程序的默认行为。
接下来需要让Django 去将应用程序加载到数据库中,让数据库能够存储Topic 相关对象信息。

python manage.py makemigrations learning_logs
output:----------
Migrations for 'learning_logs':
  learning_logs/migrations/0001_initial.py
    - Create model Topic
选项
makemigrations 告诉Django 如何去修改数据,确定数据库模型。
0001_initial.py 这个文件将在数据库中创建一个表

修改数据库,并启用新应用

python manage.py migrate

总结

每次修改"学习笔记" 管理的数据时,都采取如下三个步骤:

  1. 修改models.py,
  2. learning_logs 调用markmigrations
  3. 迁移项目。

Django 管理网站

Django 提供管理网站的一系列模型和命令。网站管理员可以使用这些命令管理网站。

创建超级用户

Django 语序创建异一定权限的用户,即超级用户。权限可以限制用户的操作。
一般分为以下几类:

  1. 超级用户
  2. 普通用户
  3. 匿名用户(guest)。
(ll_env) [python@node1 learning_log]$ python manage.py createsuperuser
output:----------------------------------------------------------------
Username (leave blank to use 'python'): ll_admin
Email address: 
Password: 
Password (again): 
Superuser created successfully.

你执行命令createsuperuser 时,Django提示输入超级用户的用户名(见❶)。这里输入的是ll_admin,但可输入任何用户名。如果你愿意,可以输入电子邮箱地址,也可让这个字段为空(见❷)。需要输入密码两次(见❸)。

Warning

一些敏感信息可能会向网站管理员隐藏。例如,Django并不存储你输入的密码,二十从密码生成一个加密值,成为散列值。每当输入密码时,Django都会计算散列值,并将结果和存储的散列值进行比较,如果两个散列值相同,登录成功。由于密码时散列值,所以黑客获取到了网站数据库的访问权。也只能获取散列值,无法获取密码。

像管理网站注册模型

Django自动在管理网站中添加了一些模型,如User 和Group ,但对于我们创建的模型,必须手工进行注册。
我们创建应用程序learning_logs 时,Django在models.py所在的目录中创建了一个名为admin.py的文件:

admin.py

(ll_env) [python@node1 learning_logs]$ cat admin.py 
from django.contrib import admin
from .models import Topic
# Register your models here.
admin.site.register(Topic)

现在可以打开Log in | Django site admin 进行网页界面操作

添加主题

  1. 点击Topics 右边ADD 图标,添加新的笔记主题

添加主题|300
2. 查看主题
提交后查看主题|300

定义模型Entry(条目)

要记录学到的国际象棋和攀岩知识,用户必须能够在学习笔记中添加条目。为此,需要定义相关的模型。每个条目都与特定主题相关联,这种关系称为多对一关系 ,即多个条目可关联到同一个主题。
models.py

from django.db import models
  
# Create your models here.


class Topic(models.Model):
    """用户学习的主题。"""
    text = models.CharField(max_length=200)
    date_added = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        """返回模型的字符串表示。"""
        return self.text

class Entry(models.Model):
    """学到的有关某个主题的具体只是。"""
    topic = models.ForeignKey(Topic, on_delete=models.CASCADE)
    text = models.TextField()
    date_added = models.DateTimeField(auto_now_add=True)

    class Meta:
        verbose_name_plural = 'entries'

    def __str__(self):
        """返回模型的字符串表示。"""
        return f"{self.text[:50]}..."

和Topic 一样,Entry 也继承了Django 基类Model 。
第一个属性 topic 是个ForeignKey 实例。 也叫外键,他会在Topic 和Entry 之间建立主外键管理,表示两个数据的练习。 on_delete=CASCADE 是指级联删除,如果每个topic 的条目不存在了,则 级联删除Entry。每创建一个主题时,自动分配一个键(ID)。

接下来是 text ,它是一个TextField 实例。这种字段长度不受限制,因此不想限制条目的长度。而属性date_added 能够按照时间排序,并显示时间戳。

class Meta 处: 嵌套了Meta类。Meta 存储管理模型的额外信息。可以使用entries 这种条目进行分类。

方法__str__() 告诉Django 需要展示哪些信息。由于Entry 条目很长,所以只展示前50个字符。

迁移模型Entry

python manage.py makemigrations learning_logs
python manage.py migrate

管理网站注册Entry

(ll_env) [python@node1 learning_log]$ cat learning_logs/admin.py 
from django.contrib import admin
from .models import Topic,Entry

# Register your models here.
admin.site.register(Topic)
admin.site.register(Entry)

添加条目

  1. 再次查看页面时,发现多了条目(Entry),点击+add 添加新条目。

Django shell

输入一些数据后,就可通过交互式终端会话以编程方式查看这些数据了。这种交互式环境称为Django shell ,是测试项目和排除故障的理想之地。下面是一个交互式shell会话示例

(ll_env) [python@node1 learning_log]$ python manage.py  shell
Python 3.6.8 (default, Nov  9 2021, 14:44:26) 
[GCC 8.5.0 20210514 (Red Hat 8.5.0-3)] on linux
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> from learning_logs.models import Topic 
>>> Topic.objects.all()
命令 说明
python manage.py shell 启动python解释器
from learning_logs.models import Topic 导入模块Tpic
Topic.objects.all() 获取Topic 所有实例,这称之为查询的列表
>>> topics = Topic.objects.all()
>>> for topic in topics:
...     print(topic.id, topic)
... 
1 我的第一篇笔记
2 我的第一个python web 界面

返回的结果集存储再topics 中,打印每个主题的ID 属性和字符串表示。从输出可知,主题都由自增序列来管理。

使用方法Topic.objects.get() 获取该对象并查看其属性。

>>> t = Topic.objects.get(id =1)
>>> t.text
'我的第一篇笔记'
Warning

创建页面:学习笔记主页

每个URL都被映射到特定的视图 ——视图函数获取并处理页面所需的数据。视图函数通常使用模板 来渲染页面,而模板定义页面的总体结构。为明白其中的工作原理,我们来创建学习笔记的主页。这包括定义该主页的URL,编写其视图函数并创建一个简单的模板。

映射URL

1、添加所有可以请求的URL。
urls.py

(ll_env) [python@node1 learning_log]$ vi urls.py 
from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', include('learning_logs.urls)),
  1. 添加learning_logs 应用中的链接文件
    urls.py
"""定义learning_logs的URL模式。"""  
  
from django.urls import path
from . import views

app_name = 'learning_logs'  
urlpatterns = [  
# 主页  
path('', views.index, name='index'),  
]

编写视图

(ll_env) [python@node1 learning_logs]$ vi views.py 
from django.shortcuts import render

# Create your views here.

def index(request):
    """学习笔记的主页。"""
    return render(request, 'learning_logs/index.html')

编写模板

mkdir -p  learning_logs/templates/learning_logs
cd learning_logs/templates/learning_logs
vi index.html
--------------------input------------------------------
<p>Learning Log</p>  
  
<p>Learning Log helps you keep track of your learning, for any topic you're  
learning about.</p>

页面|300

创建其他页面

模板继承,创建父模板

<p>
  <a href="{% url 'learning_logs:index' %}">Learning Log</a>
</p>  

{% block content %}{% endblock content %}

子模版

  1. 需要重写index.html
{% extends "learning_logs/base.html" %}  
  
{% block content %}  
<p>Learning Log helps you keep track of your learning, for any topic  
you're 
learning about.</p>  
{% endblock content %}

如果将这些代码与原来的index.html进行比较,将发现标题Learning Log没有了,取而代之的是指定要继承哪个模板的代码(见❶)。子模板的第一行必须包含标签{% extends %} ,让Django知道它继承了哪个父模板。文件base.html位于文件夹learning_logs中,因此父模板路径中包含learning_logs。这行代码导入模板base.html的所有内容,让index.html能够指定要在content 块预留的空间中添加的内容。

在❷处,插入了一个名为content 的{% block %} 标签,以定义content块。不是从父模板继承的内容都包含在content 块中,在这里是一个描述项目“学习笔记”的段落。在❸处,使用标签{% endblock content %} 指出了内容定义的结束位置。在标签{% endblock %} 中,并非必须指定块名,但如果模板包含多个块,指定块名有助于确定结束的是哪个块。

显示所有主题

首先,定义显示所有主题的页面的URL。我们通常使用一个简单的URL片段来指出页面显示的信息,这里使用单词topics,因此URLhttp://localhost:8000/topics/将返回显示所有主题的页面。下面演示了该如何修改learning_logs/urls.py:

  1. 配置URL
from django.urls import path
from . import views

app_name = 'learning_logs'
urlpatterns = [
# 主页
    path('', views.index, name='index'),
    path('topics/', views.topics, name ='topics'),
]
  1. 配置视图
def topics(request):  
	"""显示所有的主题。"""  
	topics = Topic.objects.order_by('date_added')  
	context = {'topics': topics}  
	return render(request, 'learning_logs/topics.html', context)
  1. 配置topics 网页
{% extends "learning_logs/base.html" %}  
  
{% block content %}  
  
<p>Topics</p>  
  
<ul>  
  {% for topic in topics %}  
    <li>{{ topic }}</li>  
  {% empty %}  
    <li>No topics have been added yet.</li>  
  {% endfor %}  
</ul>  
  
{% endblock content %}
  1. 修改base.html
(ll_env) [python@node1 learning_logs]$ cat base.html 
<p> 
  <a href="{% url 'learning_logs:index' %}">Learning Log</a> 
  <a href="{% url 'learning_logs:topics' %}">Topics</a> 
</p> 
 
{% block content %}{% endblock content %}

显示特定主题的页面

接下来,需要创建一个专注于特定主题的页面,它显示该主题的名称以及所有条目。我们同样将定义一个新的URL模式,编写一个视图并创建一个模板。此外,还将修改显示所有主题的页面,让每个项目列表项都变为到相应主题页面的链接。

配置URL

编辑learning_logs/urls.py

from django.urls import path
from . import views

app_name = 'learning_logs'
urlpatterns = [
# 主页
    path('', views.index, name='index'),
    path('topics/', views.topics, name ='topics'),
    path('topic/<int:topic_id>/', views.topic, name='topic'),
]

视图

def topic(request, topic_id):  
"""显示单个主题及其所有的条目。"""  
    topic = Topic.objects.get(id=topic_id)  
    entries = topic.entry_set.order_by('-date_added')  
    context = {'topic': topic, 'entries': entries}  
    return render(request, 'learning_logs/topic.html', context)

模板

这个模板需要显示主题的名称和条目的内容。如果当前主题不包含任何条目,还需向用户指出这一点:

{% extends 'learning_logs/base.html' %}  
  
{% block content %}  
  
    <p>Topic: {{ topic }}</p>  
  
    <p>Entries:</p>  
    <ul>  
    {% for entry in entries %}

    <li>  
      <p>{{ entry.date_added|date:'M d, Y H:i' }}</p>  
      <p>{{ entry.text|linebreaks }}</p>  
    </li>  
   {% empty %}  
      <li>There are no entries for this topic yet.</li>  
   {% endfor %}  
</ul>  
  
{% endblock content %}

将显示所有主题的页面中的主题设置为链接

{% extends "learning_logs/base.html" %}

{% block content %}

<p>Topics</p>

<ul>
  {% for topic in topics %}
     <li>
       <a href="{% url 'learning_logs:topic' topic.id %}">{{ topic }}</a>
     </li>
  {% empty %}
    <li>No topics have been added yet.</li>
  {% endfor %}
</ul>

{% endblock content %}
~