Python Crash Course读书笔记 - 第18章:GETTING STARTED WITH DJANGO
Django是一个web框架。可用来构建交互式网站。
设置项目
首先需要写项目说明书(spec
)。
然后需要创建虚拟环境(virtual environment
)。
虚拟环境是一个隔离的环境,可以单独virtual environment
)。
虚拟环境是一个隔离的环境,可以单独为应用安装package,而非整个系统可见
首先创建虚拟环境,并在其中安装Django模块:
# 为显示美观,需设置提示符
$ export PS1='$ '
$ mkdir learning_log
$ cd learning_log
# 注意使用python3而非python, venv是虚拟环境模块,ll_env是虚拟环境的名字
$ python3 -m venv ll_env
# 激活虚拟环境,停用虚拟环境输入deactivate
$ source ll_env/bin/activate
(ll_env) $
# 升级pip,本步骤可选
(ll_env) $ pip install --upgrade pip
# 在虚拟环境下安装django,此package只在此环境下可见。也就是说,每个虚拟环境下都需要安装一次。
(ll_env) $ pip install django
然后创建Django项目learning_log:
# 创建项目,learning_log为项目名
(ll_env) $ django-admin startproject learning_log .
# 查看当前目录,和操作系统下的显示是一致的
(ll_env) $ ls
learning_log ll_env manage.py
# 查看learning_log目录
(ll_env) $ ls learning_log
asgi.py __init__.py settings.py urls.py wsgi.py
# 查看ll_env目录,似乎操作系统下的命令也可以在虚拟环境中执行
(ll_env) $ ls ll_env
bin include lib lib64 pip-selfcheck.json pyvenv.cfg
(ll_env) $ du -sk ll_env
49544 ll_env
以上的几个文件说明以下,详细说明见这里:
- manage.py,此项目的主程序,接受参数并传递给Django执行
- learning_log/settings.py, 项目配置文件
- learning_log/urls.py,针对浏览器请求,构建什么页面
- learning_log/wsgi.py,web server gateway interface配置文件
- learning_log/asgi.py,Asynchronous Server Gateway Interface配置文件
接下来创建数据库,因Django需要用其存放数据:
# migrate命令会确保数据库与项目的当前状态匹配,第一次执行时会创建数据库
# 数据库使用的是SQLite,数据库名为db.sqlite3,生成在当前目录下
# 另外,在虚拟环境下,直接用python而非python3,因其会自动匹配python版本
(ll_env) $ python manage.py migrate
Operations to perform:Apply all migrations: admin, auth, contenttypes, sessions
Running migrations:Applying contenttypes.0001_initial... OKApplying auth.0001_initial... OKApplying admin.0001_initial... OKApplying admin.0002_logentry_remove_auto_add... OKApplying admin.0003_logentry_add_action_flag_choices... OKApplying contenttypes.0002_remove_content_type_name... OKApplying auth.0002_alter_permission_name_max_length... OKApplying auth.0003_alter_user_email_max_length... OKApplying auth.0004_alter_user_username_opts... OKApplying auth.0005_alter_user_last_login_null... OKApplying auth.0006_require_contenttypes_0002... OKApplying auth.0007_alter_validators_add_error_messages... OKApplying auth.0008_alter_user_username_max_length... OKApplying auth.0009_alter_user_last_name_max_length... OKApplying auth.0010_alter_group_name_max_length... OKApplying auth.0011_update_proxy_permissions... OKApplying sessions.0001_initial... OK
如果你在运行以上migrate
命令时,报错说SQLite版本过低,则需要升级SQLite,参照此文。
大略过程如下,请用root执行:
# cd ~
# wget https://www.sqlite.org/2019/sqlite-autoconf-3270200.tar.gz
# tar -zxvf sqlite-autoconf-3270200.tar.gz
# cd sqlite-autoconf-3270200
# ./configure --prefix=/usr/local
# make && make install
# mv /usr/bin/sqlite3 /usr/bin/sqlite3_old
# ln -s /usr/local/bin/sqlite3 /usr/bin/sqlite3
# OS中查看版本
# sqlite3 --version
3.27.2 2019-02-25 16:06:06 bd49a8271d650fa89e446b42e513b595a717b9212c91dd384aab871fc1d0f6d7
# 下面的环境变量设置非常重要,请写在用户启动文件中,如.bash_profile
# export LD_LIBRARY_PATH=$$LD_LIBRARY_PATH:/usr/local/lib
# Python中查看版本,这里显示对了才是真起作用。如果不设置LD_LIBRARY_PATH则仍显示老版本
# python3
Python 3.6.8 (default, Aug 7 2019, 08:02:28)
[GCC 4.8.5 20150623 (Red Hat 4.8.5-39.0.1)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import sqlite3
>>> sqlite3.sqlite_version
'3.27.2'
查看项目:
# 以前台方式运行server,默认监听端口是8000,在runserver后面可以直接指定其它端口号
(ll_env) $ python manage.py runserver
Watching for file changes with StatReloader
Performing system checks...System check identified no issues (0 silenced).
January 18, 2020 - 08:00:19
Django version 3.0.2, using settings 'learning_log.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C. <- 就停在这了
这时在其它终端可以测试server是否正常:
$ netstat -an|grep 8000
tcp 0 0 127.0.0.1:8000 0.0.0.0:* LISTEN$ curl http://127.0.0.1:8000/
如果用浏览器看,就是下面这个样子:
启动应用
Django项目由多个应用组成,我们先启动一个应用。以下命令需另启一终端执行:
$ source ll_env/bin/activate
# 应用名称为learning_logs,比项目名称learning_log多一个s
(ll_env) $ python manage.py startapp learning_logs
(ll_env) $ ls
db.sqlite3 learning_log learning_logs ll_env manage.py
(ll_env) $ ls learning_logs
admin.py apps.py __init__.py migrations models.py __pycache__ tests.py views.py
接下来定义Model,也就是业务模型,代码层面就是Class。
用户可创建多个topic,每个topic可有多个entry。entry为文本类型,同时需要记录时间。因此,在应用目录下编辑文件models.py
如下:
from django.db import models# Create your models here.
class Topic(models.Model):"""A topic the user is learning about."""text = models.CharField(max_length=200)date_added = models.DateTimeField(auto_now_add=True)def __str__(self):"""Return a string representation of the model."""return self.textclass Entry(models.Model):"""Something specific learned about a topic."""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 a string representation of the model."""return f"{self.text[:50]}..."
然后需要激活模型,在项目的settings.py文件中先添加应用,放在最前,余下的是系统应用:
INSTALLED_APPS = ['learning_logs',
...'django.contrib.messages','django.contrib.staticfiles',
]
因为发生了修改,因此就需要应用这些修改,步骤如下。。
(ll_env) $ python manage.py makemigrations learning_logs
Migrations for 'learning_logs':learning_logs/migrations/0001_initial.py- Create model Topic(ll_env) $ python manage.py migrate
Operations to perform:Apply all migrations: admin, auth, contenttypes, learning_logs, sessions
Running migrations:Applying learning_logs.0001_initial... OK
以后每次发生修改都需要这么做,例如第二次应用变更时的输出如下:
(ll_env) $ python manage.py makemigrations learning_logs
Migrations for 'learning_logs':learning_logs/migrations/0002_entry.py- Create model Entry
(ll_env) $ python manage.py migrate
Operations to perform:Apply all migrations: admin, auth, contenttypes, learning_logs, sessions
Running migrations:Applying learning_logs.0002_entry... OK
一些操作可通过Django管理站点(Admin Site)来做,例如添加Topic,添加Entry。不过首先需要创建管理用户:
(ll_env) $ python manage.py createsuperuser
Username (leave blank to use 'vagrant'): ll_admin
Email address:
Password: Welcome1
Password (again): Welcome1
This password is too common.
Bypass password validation and create user anyway? [y/N]: y
Superuser created successfully.
创建完用户后,然后将model加入到应用的admin.py文件中:
from django.contrib import admin# Register your models here.
from .models import Topic, Entry
admin.site.register(Topic)
admin.site.register(Entry)
然后就可以访问管理站点http://localhost:8000/admin/
了。
在管理站点添加Chess
和Rock Climbing
两个Topic。为Chess
创建1个entry,Rock Climbing
创建2个entry:
在本节最后,我们介绍Django Shell,是一个交互式终端,主要用于调试和故障排除。
## 进入Shell
(ll_env) $ python manage.py shell
Python 3.6.8 (default, Aug 7 2019, 08:02:28)
[GCC 4.8.5 20150623 (Red Hat 4.8.5-39.0.1)] on linux
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> from learning_logs.models import Topic
>>> Topic.objects.all()
<QuerySet [<Topic: Chess>, <Topic: Rock Climbing>]>
>>> topics = Topic.objects.all()
>>> for topic in topics:
... print(topic.id, topic)
...
1 Chess
2 Rock Climbing
>>> t = Topic.objects.get(id=1)
>>> t.text
'Chess'
>>> t.date_added
datetime.datetime(2020, 1, 19, 4, 5, 27, 998766, tzinfo=<UTC>)
>>> t.entry_set.all()
<QuerySet [<Entry: The opening is the first part of the game, roughly...>, <Entry: In the opening phase of the game, it’s important t...>]>
# 退出Shell
>>> <Ctrl+D>
now exiting InteractiveConsole...
构建主页
Django中制作页面包括3步:
- 定义URL
- 写view,每一个URL对应一个view
- 写template,view使用template做渲染,template决定了页面的模样。
首先在项目目录下定义URL,编辑urls.py文件如下:
from django.contrib import admin
from django.urls import path, includeurlpatterns = [path('admin/', admin.site.urls), # 这个是已有的管理主页path('', include('learning_logs.urls')), # 这个是新增的主页]
在以上文件中,path('admin/', admin.site.urls)
是已有的行,表示路径admin/
下的页面由模块admin.site.urls
定义。
然后我们进入应用目录learning_log,编辑urls.py文件如下:
"""Defines URL patterns for learning_logs."""from django.urls import pathfrom . import viewsapp_name = 'learning_logs'
urlpatterns = [# Home page# 第一个参数表示URL的模式,''表示主页,也就是http://localhost:8000/;# 第二个参数表示当URL匹配时,调用的函数,这里就是views.py中的index()函数。# 第三个参数是URL的快捷名称,方便引用。path('', views.index, name='index'),
]
至此,URL定义完毕,开始写view。
在应用目录下编辑文件views.py如下,可以看到请求被转向了learning_logs/index.html
:
from django.shortcuts import render# Create your views here.
def index(request):"""The home page for Learning Log."""return render(request, 'learning_logs/index.html')
接下来需要写template,在应用目录下创建templates
目录,然后再创建目录learning_logs
。
在最里一层目录编辑文件index.html
如下:
<p>Learning Log</p><p>Learning Log helps you keep track of your learning, for any topic you're
learning about.</p>
好了,此时如访问页面http://localhost:8000/
,显示如下:
如果遇到ModuleNotFoundError: No module named 'learning_logs.urls'
的错误,<Ctrl+C>
退出服务,然后重新启动服务即可:
python manage.py runserver
理解这个页面的运转流程非常重要,虽然看似复杂,但将URL,view和template分开的架构不就是MVC架构吗,架构人员,编程人员,Web设计人员可以专注于自己的领域。
构建其它页面
制作两个页面,分别显示所有的topic和特定topic下的所有view。
如果一些元素在每个页面中都需要,就可以定义基础模板,然后其它模板全部继承此基础模板。
在index.html
同一目录下编辑文件base.html
如下:
<p><a href="{% url 'learning_logs:index' %}">Learning Log</a>
</p>{% block content %}{% endblock content %}
包含在% %
之间的称为template tag,可以理解为占位符。最后一行{% block content %}{% endblock content %}
是需要各子目标实现的部分。
然后重写index.html
以继承基础模板:
{% extends "learning_logs/base.html" %}{% block content %}<p>Learning Log helps you keep track of your learning, for any topic you'relearning about.</p>
{% endblock content %}
接下来定义topic页面。在应用目录修改urls.py
如下:
"""Defines URL patterns for learning_logs."""from django.urls import pathfrom . import viewsapp_name = 'learning_logs'
urlpatterns = [# Home pagepath('', views.index, name='index'),path('topics/', views.topics, name='topics'),
]
然后为topic页面写view。在应用目录下修改views.py
如下:
from django.shortcuts import render
from .models import Topic# Create your views here.
def index(request):"""The home page for Learning Log."""return render(request, 'learning_logs/index.html')def topics(request):"""Show all topics."""topics = Topic.objects.order_by('date_added')context = {'topics': topics}return render(request, 'learning_logs/topics.html', context)
在以上文件中,context是需要传递给template的数据。在本例中就是字典。
然后为topic定义template。在index.html
同一目录下编辑文件topics.html
如下:
{% 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 %}
然后修改基础模板添加指向topics.html的链接。修改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 %}
此时测试页面http://localhost:8000/topics/
,显示如下:
接下来需要为每一个topic设计页面,我们准备用topic ID来区分,例如http://localhost:8000/topics/1/
。
因此我们修改urls.py
如下:
"""Defines URL patterns for learning_logs."""from django.urls import pathfrom . import viewsapp_name = 'learning_logs'
urlpatterns = [# Home pagepath('', views.index, name='index'),path('topics/', views.topics, name='topics'),path('topics/<int:topic_id>/', views.topic, name='topic'),
]
然后为topic(注意是topic不是topics)定义view。修改view文件views.py
如下:
from django.shortcuts import render
from .models import Topic# Create your views here.
def index(request):"""The home page for Learning Log."""return render(request, 'learning_logs/index.html')def topics(request):"""Show all topics."""topics = Topic.objects.order_by('date_added')context = {'topics': topics}return render(request, 'learning_logs/topics.html', context)def topic(request, topic_id):"""Show a single topic and all its entries."""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)
然后为topic定义view。创建topic.html
文件如下:
{% 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 %}
最后,在topics.html
页面中添加指向各topic的链接。修改topics.html
如下:
{% extends "learning_logs/base.html" %}{% block content %}<p>Topics</p><ul>{% for topic in topics %}<a href="{% url 'learning_logs:topic' topic.id %}">{{ topic }}</a> {% empty %}<li>No topics have been added yet.</li>{% endfor %}</ul>{% endblock content %}
测试效果如下:
最后,我们回顾一下目录结构:
$ ls -1
db.sqlite3 # SQLite数据库
learning_log
learning_logs # 应用目录
ll_env # 虚拟环境
manage.py # Django主程序# 查看应用目录
$ tree learning_logs
learning_logs
├── admin.py
├── apps.py
├── __init__.py
├── migrations
│ ├── 0001_initial.py
│ ├── 0002_entry.py
│ ├── __init__.py
│ └── __pycache__
│ ├── 0001_initial.cpython-36.pyc
│ ├── 0002_entry.cpython-36.pyc
│ └── __init__.cpython-36.pyc
├── models.py
├── __pycache__
│ ├── admin.cpython-36.pyc
│ ├── __init__.cpython-36.pyc
│ ├── models.cpython-36.pyc
│ ├── urls.cpython-36.pyc
│ └── views.cpython-36.pyc
├── templates
│ └── learning_logs
│ ├── base.html
│ ├── index.html
│ ├── topic.html
│ └── topics.html
├── tests.py
├── urls.py
└── views.py5 directories, 22 files
Python Crash Course读书笔记 - 第18章:GETTING STARTED WITH DJANGO相关推荐
- Python Crash Course读书笔记 - 第19章:USER ACCOUNTS
允许用户输入数据 目前用户数据Topic和Entry都是通过管理站点输入的,我们希望用户可以新增和编辑数据. 允许用户输入和提交数据的Web页面称为form,在Django中可使用ModelForm. ...
- Python Crash Course读书笔记 - 第2章:Variables and Simple Data Types
变量 文件hello_world.py中, .py是python文件的后缀,因此会用Python interpreter解析. $ cat hello_world.py print("Hel ...
- Python Crash Course读书笔记 - 第16章:DOWNLOADING DATA
本章首先探索在线公开数据源.然后介绍CSV和JSON格式数据的处理,并分别用Matplotlib和Plotly做可视化. CSV文件格式 CSV(comma-separated values)格式,正 ...
- Python Crash Course读书笔记 - 第15章:GENERATING DATA
数据可视化是指通过可视化的手段探索数据,和数据分析紧密关联.通过代码来探索数据集的模式. 和显示酷炫的图片无关,而是让用户之前并不知道的数据含义和模式. Python被广泛应用于遗传学,气候研究,政治 ...
- python第三章上机实践_《机器学习Python实践》读书笔记-第三章
<机器学习Python实践>,第三章,第一个机器学习项目 以往目录:橘猫吃不胖:<机器学习Python实践>读书笔记-第一章zhuanlan.zhihu.com 书中介绍了一 ...
- 开始读Python Crash Course读书笔记
2020年1月13日晚开始读Python Crash Cours第二版.Crash Course是速成班的意思. 简要信息如下: Python Crash Course, 2nd Edition A ...
- python基础教程读书笔记——第三章 字符串
第三章 字符串 摘要: %s , $x , find() , join() , split() , lower() , title() , strip() 1.字符串格式化 format = &qu ...
- 《TCP/IP具体解释》读书笔记(18章)-TCP连接的建立与中止
TCP是一个面向连接的协议.不管哪一方向还有一方发送数据之前.都必须在两方之间建立一条连接.这样的两端间连接的建立与无连接协议UDP不同.UDP向还有一端发送数据报时,无需不论什么预告的握手. 1.建 ...
- 《TCP/IP详解》读书笔记(18章)-TCP连接的建立与中止
TCP是一个面向连接的协议.无论哪一方向另一方发送数据之前,都必须在双方之间建立一条连接.这种两端间连接的建立与无连接协议UDP不同,UDP向另一端发送数据报时,无需任何预告的握手. 1.建立连接的协 ...
最新文章
- C#Dictionary源码
- 316. Remove Duplicate Letters 去除重复字母
- pandas输出列名_pandas中的DataFrame按指定顺序输出所有列的方法
- python 程序运行计时 动态,在python中运行计时器几分钟
- ubuntu 安装java_Hadoop3.1.3安装教程_单机/伪分布式配置
- jquert ajax文件 mvc,jquery ajax file upload NET MVC 无刷新文件上传
- daily scrum 12.2
- memcpy和strcpy的区别
- 数据库的数据进行改动,Cognos报表展示未及时更新
- Indesign CS6怎么添加框线_InDesign用插件快速给文本文字添加拼音的方法
- 专业的电脑版录音软件哪个最好用
- PC浏览器播放HLS协议的视频
- 膜拜 丹尼斯·里奇(纪念 C 语言之父离世 6 周年) 我们欠他的不止是张电影票
- 球体弹性碰撞位置和速度计算算法
- mysql给一张表做快照_MySQL之快照读
- 在fpga中用Cordic算法来产生正弦函数
- 判断手机设备是否支持5G无线频段
- 高斯混合模型(GMM)实现和可视化
- Axon Framework架构概述
- 8021什么意思_ox004a8021 指令引用的 0x01ac1100内存 是什么意思?
热门文章
- 解决:Connections could not be acquired from the unde
- 科技新品 | 富士胶片研发出全球最大容量数据流磁带;iGame发布内存新品“古德白”...
- ajax hover,jQuery / 使用hover()和toggle()切换事件 - 汇智网
- 如何进行微信登录授权测试?
- 杭州公司java开发工程师常见面试问题
- Spring注解开发配置
- 外贸须知:和各国客户做生意需要注意的点
- 基于微信小程序云开发(校园许愿墙app)2.0稳定版,以发布上线
- Gartner:新兴技术成熟度曲线2018(中文—历年)
- EAUML日拱一卒--序列图(Sequence Diagram)::交互和交互使用