Django学习笔记

Django学习笔记

  最近在学习一些WEB相关知识,这篇博文用于记录一些知识点,基于Django2.2来编写。

初始化

新建虚拟环境

  安装virtualenv:

1
pip install virtualenv

  virtualenv使用:

1
2
3
4
5
6
# 创建
virtualenv <虚拟环境名称>
# 启动
activate
# 退出
deactiavte

一键导出/安装扩展

  命令提示符下:

1
2
pip freeze > requirements.txt
pip install -r requirements.txt

基础知识

新建项目

  CMD下输入:django-admin startproject <项目名>

初始化数据库

  CMD下输入:python manage.py migrate

启动本地项目

  CMD下输入:python manage.py runserver

创建管理员

  CMD下输入:python manage.py createsuperuser

创建应用

  CMD下输入:python manage.py startapp <应用名>

  在app目录下定义models.py,例如:

1
2
3
class Article(models.Model):
title = models.CharField(max_length=30)
content = models.TextField()

  保存后在项目目录下,settings.py注册该应用:

  CMD下执行:

basic
1
2
python manage.py makemigrations
python manage.py migrate

  在应用目录下,编辑admin.py:

1
2
from .models import Article
admin.site.register(Article)

绑定url

  在项目目录下,编辑urls.py,参考注释:

1
2
Add an import:  from my_app import views
Add a URL to urlpatterns: path('', views.home, name='home')

注意事项

  公用全局设置可放在settings中,统一管理

1
2
from django.conf import settings
settings.XXX

进阶知识

定制admin后台

  在应用目录下,models.py中的类中,增加__str__方法,例如:

1
2
3
4
5
6
7
8
9
from django.db import models

# Create your models here.
class Article(models.Model):
title = models.CharField(max_length=30)
content = models.TextField()

def __str__(self):
return "<Article: %s>" % self.title

  项目目录下的admin.py:

1
2
3
4
5
6
7
8
9
10
11
from django.contrib import admin
from .models import Article

# Register your models here.
@admin.register(Article)
class ArticleAdmin(admin.ModelAdmin):
list_display = ('id','title','content')
ordering = ('id',)
# 倒序:('-id',)

# admin.site.register(Article, ArticleAdmin)

修改模型

  模型修改后要重新执行

1
2
python manage.py makemigrations
python manage.py migrate

增加其他参数

  修改models.py,增加如下内容:

1
2
3
4
5
6
7
from django.utils import timezone

class Article(models.Model):
......
created_time = models.DateTimeField(auto_now_add=True)
last_updated_time = models.DateTimeField(auto_now=True)
author = models.ForeignKey(User, on_delete=models.DO_NOTHING,default=1)

  相应的应于admin中的list_display增加字段。

  给类增加默认排序,在父类中增加子类,形如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
from django.db import models
from django.contrib.auth.models import User

class BlogType(models.Model):
type_name = models.CharField(max_length=15)

def __str__(self):
return self.type_name

class Blog(models.Model):
title = models.CharField(max_length=50)
blog_type = models.ForeignKey(BlogType,on_delete=models.DO_NOTHING)
content = models.TextField()
author = models.ForeignKey(User, on_delete=models.DO_NOTHING)
created_time = models.DateTimeField(auto_now_add=True)
last_updated_time = models.DateTimeField(auto_now=True)

def __str__(self):
return "<Blog: %s>" % self.title

class Meta:
ordering = ['-created_time']

使用Shell命令

  命令提示符下输入:

1
python manage.py shell

管理博文

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
>>>from blog.models import Blog
>>>from blog.models import BlogType
>>>from django.contrib.auth.models import User
# 常用
>>>Blog.objects.all()
>>>BlogType.objects.all()
>>>User.objects.all()
# 实例化
>>>blog = Blog()
>>>blog.title = 'shell下第1篇'
>>>blog.content = 'xxxxxxxxxxxxxxx'
>>>blog_type = BlogType.objects.all()[0]
>>>blog.blog_type = blog_type
>>>user = User.objects.all()[0]
>>>blog.author = user
# 保存
>>>blog.save()
#批量添加
>>>for i in range(1,31):
... blog = Blog()
... blog.title = "for %s" % i
... blog.content = 'xxxx:%s' % i
... blog.blog_type = blog_type
... blog.author = user
... blog.save()

网页搭建

使用模版

  应用目录下创建文件夹templates,然后创建html文件,编辑view.py,类似以下编辑:

1
2
3
4
5
6
7
8
9
10
11
from django.shortcuts import render
from article.models import Article

def article_detail(request, article_id):
try:
article = Article.objects.get(id=article_id)
context = {}
context['article_obj'] = article
return render(request, "article_detail.html", context)
except Article.DoesNotExist:
raise Http404('不存在')

  也可以使用render_to_response方法:

1
2
3
from django.shortcuts import render_to_response
......
return render_to_response("article_detail.html", context)

  还有get_object_or_404方法:

1
2
3
4
5
6
7
8
from django.shortcuts import render_to_response,get_object_or_404
from article.models import Article

def article_detail(request, article_id):
article = get_object_or_404(Article, pk=article_id)
context = {}
context['article_obj'] = article
return render_to_response("article_detail.html", context)

  html文件类似:

1
2
3
4
5
6
7
8
9
<html>
<head>
<body>
<h2>{{ article_obj.title }}</h2>
<hr>
<p>{{ article_obj.content }}</p>
</body>
</head>
</html>

创建目录

  创建目录html页面,在urls里绑定,使用循环来遍历文章id,使用pk而不是id是更保险的写法。

1
2
3
4
5
6
7
8
9
<html>
<head>
<body>
{% for article in articles %}
<a href="/article/{{ article.pk }}">{{ article.title }}</a>
{% endfor %}
</body>
</head>
</html>

  超链接部分也可以用这种写法:

1
<a href="{% url 'article_detail' article.pk %}">{{ article.title }}</a>

url合并

  如果有很多应用,按之前的写法,url会太臃肿,因此可以在应用下新建urls.py:

1
2
3
4
5
6
7
from django.urls import path
from . import views

urlpatterns = [
path('<int:article_id>', views.article_detail, name='article_detail'),
path('', views.article_list, name='article_list'),
]

  相应的,项目下url可改为:

1
2
3
4
5
6
7
8
9
from django.contrib import admin
from django.urls import include,path
from . import views

urlpatterns = [
path('admin/', admin.site.urls),
path('',views.index),
path('article/',include('article.urls')),
]

使用html模版

  为了减少重复html代码的使用,可以使用block块来标记可替代内容,首先在项目根目录下创建templates文件夹,创建base.html并写入以下内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<!-- {% block <别名>%}{% endblock %} -->
<!DOCTYPE html>
<html lang="zh-cn">
<head>
<meta charset="UTF-8">
<title>{% block title %}{% endblock %}</title>
</head>
<body>
<div>
<a href="{% url 'home' %}"><h3>个人博客网站</h3></a>
</div>
<hr>
{% block content %}{% endblock %}
</body>
</html>

  与之相应地,可以在其他的html文件中,省略这些内容,只需要用extends引用,再到block块中填充即可,例如blog_list.html:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<!-- {% extends 'base.html' %} -->
<!-- {% block <别名>%}{% endblock %} -->
{% extends 'base.html' %}

{# 页面标题 #}
{% block title %}
我的网站
{% endblock %}

{# 页面内容 #}
{% block content %}
{% for blog in blogs %}
<a href="{% url 'blog_detail' blog.pk%}">
<h3>{{ blog.title }}</h3>
</a>
<p>{{ blog.content|truncatechars:30 }}</p>
{% empty %}
<p>-- 暂无博客,敬请期待 --</p>
{% endfor %}
<p>一共有{{ blogs|length}}篇文章</p>
{% endblock %}

  然后在项目文件夹中的setting.py中编辑TEMPLATES的DIRS列表,加入os.path.join(BASE_DIR, 'templates')

使用css

  在项目目录下新建static文件夹,写入base.css文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
* {
margin: 0;
padding: 0;
}
div.nav {
background-color: #eee;
border-bottom: 1px solid #ccc;
padding: 10px 5px
}
div.nav a{
text-decoration: none;
color:black;
padding: 5px 10px;
}
div.nav a.logo {
display: inline-block;
font-size: 120%;
}

  然后在项目文件夹中的setting.py中加入:

1
2
3
STATICFILES_DIRS = [
os.path.join(BASE_DIR, 'static'),
]

  引用方法:

1
2
3
4
5
6
7
<!-- head中写入 -->
<link rel="stylesheet" href="/static/base.css">

<!-- 也可以用django自带方法,在html顶部写入 -->
{% load staticfiles %}
<!-- 再到head中写入 -->
<link rel="stylesheet" href="{% static 'base.css'%}">

使用css框架Bootstrap

基础

  访问官网,下载新版Bootstrap,保留以下文件,放在项目static的新建的Bootstrap文件夹中:

1
2
3
4
5
6
7
css
bootstrap.min.css
bootstrap.min.css.map
font
all
js
bootstrap.min.js

  参考文档,如果需要导入,可按如下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
{% load staticfiles %}
<!DOCTYPE html>
<html lang="zh-cn">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>{% block title %}{% endblock %}</title>
<link rel="stylesheet" href="{% static 'base.css' %}">
<link rel="stylesheet" href="{% static 'bootstrap-3.3.7/css/bootstrap.min.css' %}">
<script type="text/javascript" src="{% static 'jquery-1.12.4.min.js' %}"></script>
<script type="text/javascript" src="{% static 'bootstrap-3.3.7/js/bootstrap.min.js' %}"></script>
{% block header_extends %}
<!-- 此处可以被其他html文件继承,用于加载css文件 -->
{% endblock %}
</head>
<body>
</body>
</html>

栅格系统

  类前缀从超小到大分别为.col-xs-、.col-sm-、.col-md-、.col-lg-,也可以使用类如.visible-xs-block、.hidden-xs来显示或者隐藏,使用 例如.col-md-offset- 1类可以将列向右侧偏移。

1
2
3
4
<div class="row">
<div class="col-md-8">.col-md-8</div>
<div class="col-md-4">.col-md-4</div>
</div>

分页

基础

  shell中可以大致了解分页器的功能:

1
2
3
4
5
6
7
8
9
10
11
>>>from django.core.paginator import Paginator
>>>from blog.models import Blog
>>>blogs = Blog.objects.all()
>>>paginator = Paginator(blogs, 10)
# 常用
>>>paginator.count
>>>paginator.num_pages
>>>paginator.page_range
# 赋值
>>>page1 = paginator.page(1)
>>>page1.object_list

  修改views.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
def blog_list(request):
blogs_all_list = Blog.objects.all()
paginator = Paginator(blogs_all_list, settings.EACH_PAGE_BLOGS_NUMBER) # 每10篇为1页
page_num = request.GET.get("page", 1) # 获取url页码参数(GET请求)
page_of_blogs = paginator.get_page(page_num)
current_page_num = page_of_blogs.number #获取当前页码
# 获取当前页码前后各两位的范围
# page_range = list(range(max(current_page_num - 2, 1), current_page_num)) + \
# list(range(current_page_num, min(current_page_num + 2, paginator.num_pages) + 1))
page_range = [x for x in range(current_page_num-2, current_page_num+3) if (x>0 and x<paginator.num_pages + 1)]
# 加上首页和尾页以及省略页码标记
if page_range[0] - 1 >= 2:
page_range.insert(0,'...')
if paginator.num_pages - page_range[-1] >= 2:
page_range.append('...')
if page_range[0] != 1:
page_range.insert(0,1)
if page_range[-1] != paginator.num_pages:
page_range.append(paginator.num_pages)
context = {}
context['blogs'] = page_of_blogs.object_list
context['page_of_blogs'] = page_of_blogs
context['page_range'] = page_range
context['blog_types'] = BlogType.objects.all()
# context['blogs_count'] = Blog.objects.all().count()
return render_to_response('blog/blog_list.html',context)

def blogs_with_type(request, blog_type_pk):
blog_type = get_object_or_404(BlogType, pk=blog_type_pk)
blogs_all_list = Blog.objects.filter(blog_type=blog_type)
paginator = Paginator(blogs_all_list, settings.EACH_PAGE_BLOGS_NUMBER) # 每10篇为1页
page_num = request.GET.get("page", 1) # 获取url页码参数(GET请求)
page_of_blogs = paginator.get_page(page_num)
current_page_num = page_of_blogs.number #获取当前页码
# 获取当前页码前后各两位的范围
# page_range = list(range(max(current_page_num - 2, 1), current_page_num)) + \
# list(range(current_page_num, min(current_page_num + 2, paginator.num_pages) + 1))
page_range = [x for x in range(current_page_num-2, current_page_num+3) if (x>0 and x<paginator.num_pages + 1)]
# 加上首页和尾页以及省略页码标记
if page_range[0] - 1 >= 2:
page_range.insert(0,'...')
if paginator.num_pages - page_range[-1] >= 2:
page_range.append('...')
if page_range[0] != 1:
page_range.insert(0,1)
if page_range[-1] != paginator.num_pages:
page_range.append(paginator.num_pages)
context = {}
context['blog_type'] = blog_type
context['blogs'] = page_of_blogs.object_list
context['page_of_blogs'] = page_of_blogs
context['page_range'] = page_range
context['blog_types'] = BlogType.objects.all()
# context['blogs_count'] = Blog.objects.all().count()
return render_to_response('blog/blogs_with_type.html',context)

  修改blog_list.html:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
<div class="paginator">
<ul class="pagination">
<!-- 上一页 -->
<li>
{% if page_of_blogs.has_previous %}
<a href="?page={{ page_of_blogs.previous_page_number }}" aria-label="Previous">
<span aria-hidden="true">&laquo;</span>
</a>
{% else %}
<span aria-hidden="true">&laquo;</span>
{% endif %}
</li>
<!-- 全部页码 -->
{% for page_num in page_range %}
{% if page_num == page_of_blogs.number %}
<li class='active'><span>{{ page_num }}</span></li>
<!-- <li class='active'><a href="?page={{ page_num }}">{{ page_num }}</a></li> -->
{% else %}
{% if page_num == '...' %}
<li><span>{{ page_num }}</span></li>
{% else %}
<li><a href="?page={{ page_num }}">{{ page_num }}</a></li>
{% endif %}
{% endif %}
{% endfor %}
<!-- 下一页 -->
<li>
{% if page_of_blogs.has_next %}
<a href="?page={{ page_of_blogs.next_page_number }}" aria-label="Next">
<span aria-hidden="true">&raquo;</span>
</a>
{% else %}
<span aria-hidden="true">&raquo;</span>
{% endif %}
</li>
</ul>
<p>
共有{{ page_of_blogs.paginator.count}}篇博客,
当前第{{ page_of_blogs.number }}页,共{{ page_of_blogs.paginator.num_pages }}页
</p>
</div>

上一页/下一页

  编辑views.py,其中__gt表示大于,同理lt为小于:

1
2
3
4
5
6
7
def blog_detail(request,blog_pk):
context = {}
blog = get_object_or_404(Blog, pk=blog_pk)
context['next_blog'] = Blog.objects.filter(created_time__gt=blog.created_time).last()
context['previous_blog'] = Blog.objects.filter(created_time__lt=blog.created_time).first()
context['blog'] = blog
return render_to_response('blog/blog_detail.html',context)

评论