创建虚拟环境
使用pycharm建立虚拟环境,不需要书上那样复杂。File -> New Project 项目名改为learning_log,修改使用的新环境为虚拟环境(虚拟环境的好处书上有说明)。
安装Django
打开pycharm的终端输入
pip install django
上面那样不指定版本会安装最新的Django,想要安装指定版本的Django在django后面加上版本号。
示例安装2.2版本:
pip install django==2.2
具体安装那个版本的Django可以参考下图,由于python从入门到实践这本书使用的Django版本肯定要滞后于最新的Django发行版,因此使用后续的版本可能会有语句的改变。python从入门到实践第一版用的Django的版本是1.11,python从入门到实践第二版使用的2.2版。如果你使用的Django版本和书的版本不一致的话可能会出现一些语法的不支持。
截图来源为Django官方文档地址
在此我安装的版本为Django 2.2版
创建Django项目
在终端中运行
django-admin startproject learning_log .
得到一个行的learning_log文件夹,目录结构如下图。
目录结构分析
learning_log(外层):为项目根目录
learning_log(内层):Django项目文件
venv:虚拟环境文件夹。这个文件夹是创建虚拟环境时出现的,它的里面包括python运行的基本文件。
manage.py:管理Django项目的命令行工具,用来管理项目(运行它要让终端进入它自己的目录下运行)。命令行命令的文档地址
learning_log(内层)文件夹中的文件:
__init __.py :空文件,所有python模块都有的一个文件。
settings.py :配置文件——包括目录、安全、语言、时区等信息。官方文档关于settings.py的介绍
urls.py :路由配置(就像一个网站的目录)。官方文档关于urls.py的介绍
wsgi.py:实现WSGI(Web Server Gateway Interface),用于服务器部署。官方文档关于wsgi.py的介绍
创建数据库
迁移数据库(修改数据库)
运行所有的manage.py的命令都要进入它自己所在的目录下运行
python manage.py migrate
运行过程
运行完后会出现一个新的文件db.sqlite3,这个是python自带的一个轻量级的数据库。
新目录
运行服务
在终端(命令行)运行服务命令,默认使用8000端口。
python manage.py runserver
当报错8000端口被占用时可以用下面的命令更(改运行服务并设置端口号[在本地测试时用的])
python manage.py runserver [port]
运行服务并设置ip(布置服务器时用的,在本地运行时用前两个即可)
python manage.py runserver [ip:port]
得到一个界面。
可以看到屏幕上的显示,安装工作成功也就是说Django能够正常工作了。You are seeing this page because DEBUG=True is in your settings file and you have not configured any URLs.(您看到此页面是因为DEBUG=True在您的设置文件中,并且您尚未配置任何URL。)到这就意味着准备工作已经做好了。
添加应用
python manage.py startapp learning_logs
添加一个应用,在目录中出现一个新的文件夹learning_logs。
目录结构
-
/migrations:数据迁移管理器——用于数据在各种格式、库之间的迁移。
-
/admin.py :App管理(模块管理)——比如 Model
-
/apps.py :App配置
-
/models.py :模型文件(数据model)
-
/tests.py :测试用例(测试集)
-
/views.py :视图文件,实质上是控制作用
定义模型
进入learning_logs文件夹,编写models.py文件。
from django.db import models
# Create your models here.在这里创建模型
class Topic(models.Model): # 继承Django的models包的Midel模块
"""
用户学习的主题
模型会在数据库中映射出一个数据库表。
模型实际上是操作数据库的。
文档链接 https://docs.djangoproject.com/zh-hans/2.2/topics/db/models/#fields
"""
text = models.CharField(max_length=200) # Topic的每一个属性都是数据库的一个字段
date_added = models.DateTimeField(auto_now_add=True) # 使用函数自动获取时间戳
def __str__(self):
"""返回模型的字符串表示"""
return self.text
激活模型
进入learning_log文件夹设置settings.py文件。
"""
Django settings for learning_log project.
Generated by 'django-admin startproject' using Django 2.2.
For more information on this file, see
https://docs.djangoproject.com/en/2.2/topics/settings/
For the full list of settings and their values, see
https://docs.djangoproject.com/en/2.2/ref/settings/
"""
import os
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/2.2/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = 'k)m(tgw3!xy%umq1am8!5lowyrp1lr_v35lw)t3#zj&hgu(3l3'
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
ALLOWED_HOSTS = []
# Application definition
INSTALLED_APPS = [
# My apps
'learning_logs',
# Default django apps
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
]
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
ROOT_URLCONF = 'learning_log.urls'
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
WSGI_APPLICATION = 'learning_log.wsgi.application'
# Database
# https://docs.djangoproject.com/en/2.2/ref/settings/#databases
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
}
}
# Password validation
# https://docs.djangoproject.com/en/2.2/ref/settings/#auth-password-validators
AUTH_PASSWORD_VALIDATORS = [
{
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
},
]
# Internationalization
# https://docs.djangoproject.com/en/2.2/topics/i18n/
LANGUAGE_CODE = 'en-us'
TIME_ZONE = 'UTC'
USE_I18N = True
USE_L10N = True
USE_TZ = True
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/2.2/howto/static-files/
STATIC_URL = '/static/'
修改数据库
将models.py定义的数据模型创建一个数据库表。
python manage.py makemigrations learning_logs
将刚才创建的数据模型修改入数据库。
python manage.py migrate
Django管理网站
创建超级用户(管理员)
python manage.py createsuperuser
设置使用者、电子邮件(可以不填回车跳过)、password(密码不显示出来,设置的简易的话,可能不通过要重设)
向管理网站注册模型
进入learning_logs文件夹下的admin.py文件
from django.contrib import admin
from learning_logs.models import Topic
# Register your models here.注册你的模型
admin.site.register(Topic)
运行服务(已经运行了就不用了,可以开两个终端窗口一个用来运行服务,另一个用来进行终端命令的输入。开两个终端的方法就是点击terminal后面的加号)访问管理员,在8000端口后面加上/admin进入管理员界面,输入管理员和密码。
添加主题
点击Topics后面的Add添加主题输入在text中填入Chess后,save保存。再按同样的方法添加Rock Climbing,这样就要两个主题了。
定义Entry模型
进入learning_logs文件夹下的models.py文件添加Entry模型的代码
from django.db import models
# Create your models here.在这里创建模型
class Topic(models.Model): # 继承Django的models包的Midel模块
"""
用户学习的主题
模型会在数据库中映射出一个数据库表。
模型实际上是操作数据库的。
文档链接 https://docs.djangoproject.com/zh-hans/2.2/topics/db/models/#fields
"""
text = models.CharField(max_length=200) # Topic的每一个属性都是数据库的一个字段
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 self.text[:50] + '...' # 只显示前50个字
下面像前面添加应用的过程一样。
迁移Entry数据、向管理网址注册Entry模型
迁移模型
python manage.py makemigrations learning_logs
python manage.py migrate
向管理网址注册Entry模型
进入learning_logs文件夹下的admin.py文件添加Entry模型来激活模型。
from django.contrib import admin
from learning_logs.models import Topic
from learning_logs.models import Entry
# Register your models here.注册你的模型
admin.site.register(Topic)
admin.site.register(Entry)
进入管理员界面添加Entry
添加Entry,将书上的内容输入。
Entry设置的是只显示前50个字看下图每个标题显示的就是前50个字加三个点。
创建网页:学习笔记主页
Django创建网页的过程通常分为三部分:定义URL、编写视图、编写模板。
映射URL
进入learning_log的urls.py文件添加URL。这个是项目的整个路由目录。
"""learning_log URL Configuration
The `urlpatterns` list routes URLs to views. For more information please see:
https://docs.djangoproject.com/en/2.2/topics/http/urls/
Examples:
Function views
1. Add an import: from my_app import views
2. Add a URL to urlpatterns: path('', views.home, name='home')
Class-based views
1. Add an import: from other_app.views import Home
2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
Including another URLconf
1. Import the include() function: from django.urls import include, path
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
"""
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('',include('learning_logs.urls')) # 空代表从根目录开始,包含learning_logs的路由表
]
urls模块的文档地址
path()方法返回urlpatterns中的一个元素,一共有4个参数,两个必须,两个可选。
- route(必须):是一个匹配URL的准则(类似正则表达式)。当 Django响应一个请求时,它会从 urlpatterns的第一项开始,按顺序依次匹配列表中的项,直到找到匹配的项。这些准则不会匹配 GET 和POST 参数或域名。
- view(必须):找到匹配准则后会,调用视图函数并传入一个HttpRequest对象作为第一个参数,被捕获的参数以关键字形式传入。
- kwargs(可选):任意个关键字参数可以作为一个字典传递给目标视图函数。
- name(可选):为你的 URL 取名能使你在Django 的任意地方唯一地引用它,尤其是在模板中。这个有用的特性允许你只改一个文件就能全局地修改某个 URL 模式。
在learning_logs中创建子路由表urls.py。
from django.urls import path
from . import views
app_name = 'learning_logs'
urlpatterns = [
path('', views.index, name='index'),
]
编写views.py
Django 中的视图的概念是「一类具有相同功能和模板的网页的集合」。在 Django 中,网页和其他内容都是从视图派生而来。每一个视图表现为一个简单的 Python 函数(或者说方法,如果是在基于类的视图里的话)。Django 将会根据用户请求的 URL 来选择使用哪个视图(更准确的说,是根据 URL 中域名之后的部分)。每个视图必须要做的只有两件事:返回一个包含被请求页面内容的 HttpResponse 对象,或者抛出一个异常,比如 Http404 。
进入learning_logs文件夹下的views.py文件。
from django.shortcuts import render
# Create your views here. 在这创建你的视图
def index(request):
'''学习笔记的主页面'''
return render(request, 'learning_logs/index.html')
「载入模板,填充上下文,再返回由它生成的 HttpResponse 对象」是一个非常常用的操作流程。于是 Django 提供了一个快捷函数,我们用它来重写 index() 视图。
编写模板
在learning_logs文件夹下新建templates文件,再在templates文件夹下建立learning_logs文件夹,最后创建index.html文件。
结构如图:
为什么要这么复杂的创建文件呢,来我们看看官方文档:
首先,在你的应用(这里就是learning_logs了)目录里创建一个 templates 目录。Django 将会在这个目录里查找模板文件。
你项目的 TEMPLATES 配置项描述了 Django 如何载入和渲染模板。默认的设置文件设置了DjangoTemplates 后端,并将 APP_DIRS 设置成了 True。这一选项将会让 DjangoTemplates 在每个 INSTALLED_APPS 文件夹中寻找 “templates” 子目录。这就是为什么尽管我们没有像在第二部分中那样修改 DIRS 设置,Django 也能正确找到模板位置的原因。
在你刚刚创建的 templates 目录里,再创建一个目录 (第二个learning_logs文件夹),然后在其中新建一个文件 (index.html) 。换句话说,你的模板文件的路径应该是 learning_logs/templates/learning_logs/index.html 。因为 Django 会寻找到对应的 app_directories (也就是learning_logs/templates),所以你只需要使用 learning_logs/index.html 就可以引用到这一模板了。
模板命名空间
虽然我们现在可以将模板文件直接放在 learning_logs/templates 文件夹中(而不是再建立一个 learning_logs 子文件夹),但是这样做不太好。Django 将会选择第一个匹配的模板文件,如果你有一个模板文件正好和另一个应用中的某个模板文件重名,Django 没有办法 区分 它们。我们需要帮助 Django 选择正确的模板,最简单的方法就是把他们放入各自的 命名空间 中,也就是把这些模板放入一个和 自身 应用重名的子文件夹里。
模板内容:
<p>learning_log</p>
<p>Learning Log helps you keep track of your learning, for any topic you're learning about.</p>
运行服务界面:
创建其他网页
模板模块的官方文档
模板继承
- 父模板
<p>
<a href="{% url 'learning_logs:index' %}">Learning Log</a>
</p>
{% block content %}{% endblock content %}
{% %}为模板标签,a为链接标签。a的href属性用模板标签给出了URL
2. 子模板
{% 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 %}
显示所有主题的页面
定义显示所有主题的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'),
]
编写视图
进入learning_logs文件夹下的views.py文件,添加视图。
from django.shortcuts import render
from .models import Topic
# Create your views here. 在这创建你的视图
def index(request):
'''学习笔记的主页面'''
return render(request, 'learning_logs/index.html')
def topics(request):
"""显示所有主题"""
topics = Topic.objects.order_by('date_added') # 从数据库中将按data_added排序的Topic对象读出
content = {'topics': topics} # 按字典的形式将数据进行存储
return render(request,'learning_logs/topics.html',content)
object是创建模型时自动建立的一个管理数据库的对象。文档地址
添加模板
在模板文件夹下添加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 %}
修改父模板
<p>
<a href="{% url 'learning_logs:index' %}">Learning Log</a> - <a href="{% url 'learning_logs:topics' %}">Topics</a>
</p>
{% block content %}{% endblock content %}
运行服务
显示特定主题页面
设置主题的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('topics/<int:topic_id>/', views.topic, name='topic'),
]
添加视图
进入learning_logs文件夹下的views.py文件,添加视图。
from django.shortcuts import render
from .models import Topic
# Create your views here. 在这创建你的视图
def index(request):
'''学习笔记的主页面'''
return render(request, 'learning_logs/index.html')
def topics(request):
"""显示所有主题"""
topics = Topic.objects.order_by('date_added')
content = {'topics': topics}
return render(request,'learning_logs/topics.html',content)
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)
编写单个主题的模板
进入模板目录新建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 %}
修改显示所以主题的模板
{% 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 %}
运行服务得到页面
-
首页
-
显示所以主题的页面
-
Chess页面
-
Rock Climbing页面