1. 对于任一django项目,拿到功能需求时都要思考的问题
1)去数据库里存什么
2)制作什么样的页面
3) 定义什么样的URL
4)页面与数据库之间的信息交换方式
5)时间如何考虑
6)数据库中方法被调用时显示方式
7)在Admin后台中的显示
2. HTML入门
2.1 文字类:h1~h6,p,a,label,span
<h1>一级标题</h1>
<h2>二级标题</h2>
<h3>三级标题</h3>
<h4>四级标题</h4>
<h5>五级标题</h5>
<h6>六级标题</h6>
<span></span>
<label></label>
<p></p>
<a href=""></a>
对于div,span,label的区别,可参阅:
简单来说,div是框架,可以包括span,span是组合文档的元素,label主要用来绑定表单元素.
2.2 组件类:table,input,form,button,textarea
<table>
<thead>
<th></th>
<th></th>
<th></th>
</thead>
<tbody>
<tr>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
</tr>
</tbody>
</table>
<form>
<label></label>
<input type='text' />
<br />
<select>
<option></option>
<option></option>
</select>
<textarea rows='10',cols='30'></textarea>
<button></button>
</form>
2.3 布局类:div,br
<div id='outer'>
<div id='inner'>
<input type='text'>
</div>
<div id='inner2'>
<button></button>
</div>
</div>
3.页面美化
3.1 CSS
CSS代码以三种方式代入进html文件中
方式1:特指特定的一个节点
方式2:选取一类节点
方式3:节点类型限制
方式4:层级限制
方式5:并集选取
3.2 bootstrap
步骤1:前往bootstrap官网下载文件,找到bootsrap.min.css文件并放入至django中的static文件夹下;
步骤2:在settings.py中注册静态文件路径
STATIC_URL = '/static/'
STATICFILES_DIRS = (os.path.join(BASE_DIR,"static"),) #BASE_DIR,项目所在目录
步骤3:在template模板中写入
<link rel="stylesheet" href="/static/bootstrap.min.css"/>
步骤4:前往bootstrap官网查看中意的样式然后拷贝进代码中并匹配自己的代码即可.
4.页面布局
4.1 页面布局的概念
页面中先定义行(row),然后定义列(colum);
一行分为12份
xs:小屏幕,md:中屏幕,
5.基础模板的制作
基础模板类似于基本页面,代码为:
<div class="container">
# code
{% block content %}
{% endblock %}
# code
</div>
子模板代码为:
{% extends 'base.html' %}
{% block content %}
# code
{% endblock %}
6. 数据存入数据库
6.1 示例代码
from django.contrib.auth.models import User
from django.db import models
from blocks.models import Block
import pytz
BEIJING_TZ = pytz.timezone('Asia/Shanghai')
class Article(models.Model):
owner = models.ForeignKey(User, verbose_name='作者')
block = models.ForeignKey(Block, verbose_name='版块ID')
title = models.CharField('模块名称', max_length=100)
content = models.CharField('模块描述', max_length=400000)
status = models.IntegerField('状态', choices=((0, '正常'), (1, '删除'),(10, '精华')))
create_timestamp = models.DateTimeField('创建时间', auto_now_add=True)
last_update_timestamp = models.DateTimeField('修改时间', auto_now=True)
def __str__(self):
return self.title
class Meta:
verbose_name = '文章'
verbose_name_plural = '文章'
6.2 数据库类的继承
从django.db中引入models,后面每一张数据表都会继承models
6.3 数据库中的数据类型
数据库中有如下类型:
1) CharField,字符类型
最常用的一种类型,存储字符串数据。
2) IntegerField,数字类型
存储数字,也可以如上图代码,存储类似与selectbox的内容
3) DateTimeField,时间类型
存储时间,其中在属性中设置auto_now_add=True 一般代表文章的创建时间,此时间不会变化,auto_now=True一般代表文章的最后更新时间,此时间会随着数据库被修改而变化。
6.4 数据库中的外键
数据库中的外键相当于数据库中每一张表的联系,比如文章的数据库需要连接到版块信息中,常用的外键如下:
1) ForeignKey,外键
代表此表与另外一张表建立了外键的联系,ForeignKey内部存储的实际上是int类型,即另外一张表的id.
2) OnetooneField:一对一关系
3) ManytoManyField:多对多关系
4) OnetoManyField:一对多关系
7. 版块应用的创建
7.1 建立版块application
1) 在terminal中进入manage.py所在目录下;
2) 利用python manage.py startapp +app名称(block)建立block这个app;
7.2 在settings.py中注册这个app
注意:后续章节会对app进行汉化,因此注册名称会发生变化。
INSTALLED_APPS = [
# ...
'blocks.apps.BlocksConfig',
# ...
]
7.3 在models.py中建立block
7.3.1 创建版块数据表前的思考
- 设想数据结构:需要版块名称,版块描述,版块所属管理员,版块状态;
- 必要的补充信息:被调用时返回的名称,在admin后台的汉化,时间的引入(此表不需要),外键的引用(此表不需要);
7.3.2 代码分解
from django.db import models
class Block(models.Model):
name = models.CharField('模块名称', max_length=100)
desc = models.CharField('模块描述', max_length=100)
manager_name = models.CharField('模块管理员名称', max_length=100)
status = models.IntegerField('状态', choices=((0, '正常'), (1, '删除')))
def __str__(self):
return self.name
class Meta:
verbose_name = '版块'
verbose_name_plural = '版块'
- 导入django.db.models
- 建立数据表Block,继承models.Model
- 按照设想的数据结构,建立:
- 版块名称name(CharField类型,中文名称,最大长度);
- 版块描述desc(CharField,中文名称,最大长度);
- 管理员名称manager_name(CharField,中文名称,最大长度);
- 版块状态status(InterField,中文名称,选择信息)
- 被调用时的名称str:版块名称name
- 在admin后台显示:verbose_name和verbose_name_plural都是“版块”
7.3.3 后台数据库中的显示
数据库会建立一张blocks_block的数据表,其中blocks为app名称,models中建立的表名,数据库会自动生成一列id列,此列一般被ForeignKey引用。
7.4 数据表在views中的引用
7.4.1 在views中导入数据表
from blocks.models import Block
7.4.2 定义函数及调用数据库数据,将数据传递至template
def index(request):
block_infos = Block.objects.all().filter(status=0).order_by('-id')
if request.user.is_authenticated():
msg_cnt = Usermessage.objects.filter(status=0, owner=request.user).count()
else:
msg_cnt = 0
return render(request, "index.html",{
'blocks':block_infos, 'msg_cnt': msg_cnt})
7.5 数据表在templates中的显示
在页面中使用for循环的语法是{% for b in blocks%};
通过b.id ,b.name及{
{ }}语法调用blocks表中的数据;
<div class="col-xs-12 col-md-10">
{% for b in blocks %}
<div class="panel panel-default">
<div class="panel-heading">
<a href="/article/list/{
{ b.id }}" style="font-size: 15px">{
{ b.name }}</a>
<span class="pull-right">{
{ b.manager_name }}</span>
</div>
<div class="panel-body">{
{ b.desc }}</div>
</div>
{% endfor %}
</div>
7.6 页面的显示效果
- 8.文章列表的创建
8.1 创建前的思考
去数据库里什么:只是作为各版块中每一篇文章的显示功能,不涉及具体数据库操作;
定义一个什么样的页面:包含导航功能,显示目前所处路径,包含一个table,显示文章标题,文章内容概要,文章作者,创建时间,最后修改时间
页面切换:版块概要页面文章列表页面文章详情页面或创建文章页面
时间管理:不涉及时间的管理
汉化功能:不涉及汉化功能;
其他功能:在文章太多的情况下,分页功能;
8.2 编写文章列表views
8.2.1 引入相关数据库
- 版块数据表Block
from blocks.models import Block
- 文章数据表
from .models import Article
8.2.2 编写views函数
def article_list(request, block_id):
block_id = int(block_id)
blocks = Block.objects.get(id=block_id)
page_no = int(request.GET.get('page_no','1'))
all_articles = Article.objects.filter(block=blocks,status=0).order_by('-id')
page_articles,pagination_data = paginate_queryset(all_articles, page_no)
return render(request, 'article_list.html', {
'blocks':blocks,
'articles':page_articles,
'pagination_data': pagination_data})
- 从网页上获取当前所属版块id(block_id=int(block_id))
- 根据版块id获取Block数据表中数据(blocks=Block.objects.get(id=block_id)
- 获取文章:满足状态正常(status=0)且属于当前版块(block=blocks)的文章(all_artilces=Arcitle.objects.filter(block=blocks,status=0).order_by(‘-id’))
- 将文章进行分页(分页的实现一节)
- 返回模板,代入版块数据,文章分页及文章数据
8.2.3 编写文章列表template
8.2.3.1 文章列表导航功能的模板
<ol class="breadcrumb">
<li><a href="/">主页</a></li>
<li class="active">{
{ blocks.name }}</li>
</ol>
9.2.3.2 “创建文章”按钮的制作
<a href="/article/create/{
{ blocks.id }}" type="button" class="btn btn-primary">发表文章</a>
8.2.3.3 文章列表的显示
<table class="table table-bordered">
<thead>
<tr>
<th>标题</th>
<th>作者</th>
<th>创建时间</th>
<th>最后更新时间</th>
</tr>
</thead>
<tbody>
{% for article in articles %}
<tr>
<td><a href="/article/articledetail/{
{ article.id }}">{
{ article.title }}</a></td>
<td>{
{ article.content }}</td>
<td>{
{ article.create_timestamp|date:'Y-m-d P' }}</td>
<td>{
{ article.last_update_timestamp|date:'Y-m-d P' }}</td>
</tr>
{% endfor %}
</tbody>
</table>
- 使用for语句,显示所有文章;
- 在文章标题设置连接,当点击文章标题,可以进入文章详情页面;
- 时间的格式化处理,将数据库中的时间以特定格式显示出来(|date:’Y-m-d P’);
8.2.3.4 分页功能的引入
{% include 'component/paginator.html' %}
详细讲解见“分页的实现”一节
8.3 文章列表页面的显示效果
9. 分页的实现
9.1 分页的本质
获取所有文章,将所有文章按照指定数量进行分隔,当页面调取哪一块数据,分页器返回相应数据。
9.2 django提供的分页工具
Django分页工具:django.core.paginator.Paginator
from django.core.paginator import Paginator
all_articles = Articles.objects.all().filter(status=0).order_by("-id")
p = Paginator(all_articles,ARTICLE_COUNT_1PAGE)
page = p.page(page_no)
artilces_objs = page.object_list
9.3 分页功能的页面分解
分页总共涉及到7个变量,详见下表:
10.4 分页功能代码编写
from django.core.paginator import Paginator
def paginate_queryset(objs, page_no, cnt_per_page=5, half_show_length=5):
p = Paginator(objs, cnt_per_page) #分页功能的实例化
if page_no > p.num_pages: #判断页数是否超过最大页数
page_no = p.num_pages
if page_no <= 0: #判断页数是否小于最小页数
page_no = 1
page_links = [i for i in range(page_no - half_show_length, page_no + half_show_length + 1)
if i > 0 and i <= p.num_pages]
page = p.page(page_no)
previous_link = page_links[0] - 1
next_link = page_links[-1] + 1
pagination_data = {
'has_previous': previous_link>0, #有前页在views中做计算
'has_next': next_link <= p.num_pages, #有后页在views中做计算
'previous_link': previous_link,
'next_link': next_link,
'page_cnt': p.num_pages,
'current_no': page_no,
'page_links': page_links}
return (page.object_list, pagination_data)
1) 不仅在文章列表用到分页功能,后续评论功能也会用到分页,因此将分页功能提取可复用的代码,因此新建paginator.py文件。
2) 导入django分页器from django.core.paginator import Paginator
3) 定义分页函数,参数包含objs(文章的列表数据),page_no(当前页面),count_per_page(每页的文章数量),half_show_length(页面上显示的页码范围);
4) 在10.3中讲到分页页面总共有7个变量,这7个变量都可以通过2个变量(count_per_page,half_show_length)来进行计算
5) 程序返回值为当前页的所有数据(列表格式),打包的页面数据(是否有前一页(has_previous),是否有后一页(has_next),前一页(previous_link),后一页(next_link),页数总计(page_cnt),当前页(current_no),页数列表(page_links))
9.5 分页的模板
<nav aria-label="Page navigation">
<ul class="pagination">
{% if pagination_data.has_previous %} {# 判断是否有前一页 #}
<li ><a aria-hidden="true" href="?page_no=1">首页</a></li> {# 首页按钮 #}
<li > {# 前一页标志及链接 #}
<a aria-hidden="true" href="?page_no={
{ pagination_data.previous_link }}" aria-label="Previous">
<span aria-hidden="true">«</span></a>
</li>
{% endif %}
{% for page in pagination_data.page_links %}
{% ifequal page pagination_data.current_no %} {# 判断页面与当前页面是否一致 #}
<li class="active"><a href="?page_no={
{ page }}">{
{ page }}</a></li>
{% else %}
<li><a href="?page_no={
{ page }}">{
{ page }}</a></li>
{% endifequal %}
{% endfor %}
{% if pagination_data.has_next %} {# 判断是否有后一页 #}
<li> {# 后一页标志及链接 #}
<a aria-hidden="true" href="?page_no={
{ pagination_data.next_link }}" aria-label="Next">
<span aria-hidden="true">»</span></a>
</li>
<li><a aria-hidden="true" href="?page_no={
{ pagination_data.page_cnt }}">尾页</a></li> {# 尾页按钮 #}
{% endif %}
</ul>
</nav>
分页模板主要分为三部分,第一是是否有前一页的判断及显示前一页,第二是显示页面范围并active当前页,第三是是否有后一页的判断。
分页的模板可以去bootstrap网站寻找,如下:
9.6 分页功能的应用
分页功能在文章列表页面得到了应用,下面是实际代码。
9.6.1 分页功能的引入
from utils.paginator import paginate_queryset
9.6.2 功能的实现
def article_list(request, block_id):
block_id = int(block_id)
blocks = Block.objects.get(id=block_id)
page_no = int(request.GET.get('page_no','1'))
all_articles = Article.objects.filter(block=blocks,status=0).order_by('-id')
page_articles,pagination_data = paginate_queryset(all_articles, page_no)
return render(request, 'article_list.html', {
'blocks':blocks,
'articles':page_articles,
'pagination_data': pagination_data})
要点:先从template中获取当前页面(page_no)及从models中获取所有文章(all_articles),然后将这两个数据传递至分页函数paginate_queryset中(每页显示文章数量count_per_page及页面上显示的页码范围half_show_length都已设定默认值(count_per_page=5,half_show_length=5)),由于函数返回了两个变量,一个是每页显示的文章(page.queryset),另外一个是分页相关数据(pagination_data),因此设置两个变量进行接收,将这两个变量直接传回至template中
9.6.3 功能的页面
<table class="table table-bordered">
<thead>
<tr>
<th>标题</th>
<th>作者</th>
<th>创建时间</th>
<th>最后更新时间</th>
</tr>
</thead>
<tbody>
{% for article in articles %}
<tr>
<td><a href="/article/articledetail/{
{ article.id }}">{
{ article.title }}</a></td>
<td>{
{ article.content }}</td>
<td>{
{ article.create_timestamp|date:'Y-m-d P' }}</td>
<td>{
{ article.last_update_timestamp|date:'Y-m-d P' }}</td>
</tr>
{% endfor %}
</tbody>
</table>
{% include 'component/paginator.html' %}
利用for函数遍历所有文章,利用table样式进行显示;
引入paginator.html