Django

1.安装Django

要想使用Django,就必须安装

1
pip intall django

2.创建项目

终端法

1.打开终端

2.进入想放项目的目录

3.执行命令创建项目

1
"F:\python\Scripts\django-admin.exe" startproject firstDjango

pycharm创建

特殊说明:

终端创建的项目是标准的

pycharm,在标准的基础上加了一些东西

​ 创建了一个templates目录(删除)

​ settings.py里面新加了一句话 删掉

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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',
],
},
},
]

‘DIRS’: []这句改成这样

默认项目的文件介绍

manage.py 用于项目的管理,启动项目,创建app,数据管理

然后包含一个与项目同名的文件夹

该文件夹里面包含

_init_.py

settings.py 配置文件 [经常修改]

urls.py url和函数的对应关系 [我们经常修改]

asgi.py [接收网路请求] 异步

wsgi.py [接受网络请求] 同步

APP

大项目中有很多小功能,这个APP就是这些小功能

例如

1
2
3
4
5
项目
app 用户管理【表结构,函数,html模板,css】
app 订单管理
app 后台管理
...

使用manage.py创建APP

1
python manage.py startapp app01

APP中包含的文件

1
2
3
4
5
6
7
8
9
10
11
├─app01
│ │ admin.py [固定,不用动]django 默认提供admin后台管理
│ │ apps.py [固定,不用动]app启动类
│ │ models.py [重要] 对数据库进行操作
│ │ tests.py [固定,不用动]单元测试
│ │ views.py [重要],视图函数都写在这
│ │ __init__.py
│ │
│ └─migrations 【固定,不用动】数据库变更记录
│ __init__.py

快速上手

运行程序要确保app已经注册

注册流程:

打开设置文件seeting.py,里面有一个

1
2
3
4
5
6
7
8
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
]

然后打开apps.py文件。里面有一个

1
2
3
class App01Config(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'app01'

看到名字是app01,然后再setting那个列表里面加一个

1
'app01.apps.App01Config'

编写URL和视图函数对应关系,再urls.py中编写

1
2
3
4
5
6
7
from app01 import views
urlpatterns = [
#path('admin/', admin.site.urls),
# 第一个参数代表网站后面的参数 www,xxx.com/index/ 第二个参数表示访问网站就去执行某个函数
#函数都在views中放着
path('index/', views.index),
]

编写视图函数 编写views.py

1
2
3
4
5
from django.shortcuts import render,HttpResponse

# Create your views here.
def index(request):
return HttpResponse("Hello, world. You're at the polls index.")

启动django项目

方式一

1
python manage.py runserver

方式二

使用pycharm启动

再写页面

之后再写页面只需要urls.py那个列表里新加一行,然后在view.py再定义对应的函数即可

templates

上述创建的视图函数返回的只是一行普通的文字,那可否返回一份HTML呢,可以

再视图函数中将返回值改为 return render(request,”xxxx.html”)

这样django就回去templates目录下寻找填写的第二个参数的那个html,这个目录手动在app01下创建,这个寻找的顺序是会根据app的创建顺序逐一寻找

静态文件

在开发过程中,一般将:

图片、css、js等

放在app目录下的static目录下,这个目录名字不可改

这个static目录下要有如下几个目录:

css

img

js

plugins

引入静态文件的方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
{% load static %}

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<link rel="stylesheet" href="{% static 'plugins/bootstrap-3.4.1/css/bootstrap.css' %}">
</head>
<body>
<h1>用户列表</h1>

<script src="{% static 'js/jquery-3.7.1.min.js' %}"></script>
<script src="{% static 'plugins/bootstrap-3.4.1/js/bootstrap.js' %}"></script>
</body>
</html>

模板语法

本质上:在HTML中写一些占位符,由数据对这些占位符进行替换和处理

1
2
3
4
5
6
7
8
9
10
11
def tpl(request):
name = "汉朝"
roles = ["管理员","ceo","保安"]
user_info = {"name":"jack","salary":10000,"role":"CTO"}
data_list = [
{"name": "jack", "salary": 10000, "role": "CTO"},
{"name": "jack", "salary": 10000, "role": "CTO"},
{"name": "jack", "salary": 10000, "role": "CTO"}
]

return render(request,'tpl.html',{"n1":name,"n2":roles,"n3":user_info,"n4":data_list})
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
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>模板语法的学习</h1>
<div>{{ n1 }}</div>
<div>{{ n2 }}</div>
<h1>取下标的操作</h1>
<div>{{ n2.0 }}</div>
<div>{{ n2.1 }}</div>
<h1>循环取值</h1>
<div>
//遍历列表
{% for item in n2 %}
<span>{{ item }}</span>
{% endfor %}
</div>
<hr>
{{ n3 }}
{{ n3.name }}
{{ n3.salary }}
{{ n3.role }}
<ul>
//只遍历字典的键 当然也可以只遍历字典的值
{% for item in n3.keys %}
<li>{{ item }}</li>
{% endfor %}
</ul>
<ul>
//循环遍历字典
{% for k,v in n3.items %}
<li>{{ k }} = {{ v }}</li>
{% endfor %}
</ul>
<hr>
//列表里嵌套字典
{{ n4.0 }}
{{ n4.0.name }}
<hr>
//条件判断语句
{% if n1 == "汉朝" %}
<h1>里里里里</h1>
{% elif n1 == "xxx" %}
<h1>daksjdlajdl</h1>
{% else %}
<h1>asdadkaskd</h1>
{% endif %}
</body>
</html>

请求和响应

views.py文件

request参数是一个对象,封装了用户发送过来的所有请求相关的数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
from django.shortcuts import redirect
def someting(request):
print(request.method)#打印get 获取请求方式GET/POST

#在URL上传递值 /somethint/?n1=123&n2=999
print(request.GET)#打印{"n1":['123'],"n2":['999']}

#在请求体中提交数据
print(request.POST)#打印{}

#响应
return HttpResponse("返回内容");
#还可以返回render

#读取HTML的内容+渲染(替换) -》字符串,返回给用户浏览器
return render(request,'something.html',{"title":"来了"})#效果为,返回一个title被改为来了的页面

#还可以返回redirect 需要导入redirect
#让浏览器重定向到其他页面
return redirect("www.baidu.com")#参数是一个网址

练习:登录页面

1
2
3
4
5
6
7
8
9
10
11
12
13
def login(request):
if request.method == "GET":
return render(request,'login.html')
else:
#print(request.POST)
#在这里可以进行校验
username = request.POST.get('user')
password = request.POST.get('pwd')
if username =='root' and password =='123':
return redirect('https://www.baidu.com/')
else:
#可以通过模板渲染来实现登陆失败的提示
return render(request,'login.html',{"error_msg":"用户名密码错误"})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form method="post" action="/login/">
{% csrf_token %}
<input type="text" name="user" placeholder="请输入账号"/>
<input type="password" name="pwd" placeholder="请输入密码"/>
<input type="submit" value="登录"/><span style="color:red">{{ error_msg }}</span>
</form>
</body>
</html>

数据库操作

Django开发操作数据库更简单,内部提供了ORM框架

ROM

ROM可以帮助我们做两件事:

创建、修改、删除数据库中的表(不用写sql语句)==无法创建数据库==

操作表中数据(不用写sql语句)

所以使用过程中需要

1.自己创建数据库

启动mysql服务

自带工具创建数据库

2.django连接数据库

在seeting.py中进行配置

1
2
3
4
5
6
7
8
9
10
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'pydb2',
'USER': 'root',
'PASSWORD': 'zs123456',
'HOST': '127.0.0.1',
'PORT': '3306',
}
}

django操作表

创建表

删除表

修改表

创建表

在models.py文件中

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

# Create your models here.
class UserInfo(models.Model):
user = models.CharField(max_length=32)
password = models.CharField(max_length=64)
age = models.IntegerField()

如果需要让django执行创建表的操作需要在终端执行两个命令
要保证执行这个命令的时候工作目录下有manage.py文件
并且app要以及注册

1
python manage.py makemigrations
1
python mamage.py migrate

如果要删除一列,只需要注释掉哪一行,然后在执行一次这两个命令就可以了

例如

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

# Create your models here.
class UserInfo(models.Model):
user = models.CharField(max_length=32)
password = models.CharField(max_length=64)
#age = models.IntegerField()

然后在执行一次这两个指令,表中该列就删掉了

如果要加一列有一些问题,因为

假设原来的表是这样样子

id name pass age

1 s 123 18

1 a 123 19

如果要加一列的话,那么前面这些数据也就都会多一列

id name pass age size

1 s 123 18

1 a 123 19

那以前这些数据空着一列肯定不行所以表如果之前就存在的话,要加一列就要提供一个默认值

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

# Create your models here.
class UserInfo(models.Model):
user = models.CharField(max_length=32)
password = models.CharField(max_length=64)
#age = models.IntegerField()
size = models.IntegerField(default = 1)

如果没有设置默认值,那么直接新增的话Django会让手动输入一个值

此外还可以允许为空

1
data = models.IntegerField(null=True, blank=True)

操作表中的数据

插入数据
1
2
3
4
5
6
7
8
9
10
from app01.models import  UserInfo#先要把对象导进来
#然后
def orm(request):
# 插入数据
UserInfo.objects.create(user='小胡', password='123', age=19)
UserInfo.objects.create(user='小张', password='123', age=20)
UserInfo.objects.create(user='小刘', password='123', age=21)


return HttpResponse("成功")
删除数据
1
2
3
#删除数据
UserInfo.objects.filter(id=3).delete() #带条件的删除
UserInfo.objects.all().delete() #删除所有数据
查询数据
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#获取数据
#data_list = [对象,对象,对象] data_list是一个QuerySet类型
#列表里的每一个对象就是一行数据
data_list = UserInfo.objects.all()
for obj in data_list:
print(obj.id,obj.user,obj.password,obj.age)

#条件查询
data_list2 = UserInfo.objects.filter(id=1)
for obj in data_list2:
print(obj.id, obj.user, obj.password, obj.age)

#获取列表第一行数据
row_obj = UserInfo.objects.filter(id=4).first()
print(row_obj.user)
更新数据
1
2
3
4
5
6
# 更新数据
#更新所有行
UserInfo.objects.all().update(age=100)
#更新符合条件的行
UserInfo.objects.filter(user='小胡').update(age=200)

练习:用户管理

显示所有用户的数据

1
2
3
4
5
6
7
#views.py
def info_list(request):

data_list = UserInfo.objects.all()

return render(request, 'info_list.html',{"data_list": data_list})

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
{# info_list #}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>用户列表</h1>
<a href="/info/add/">添加</a>
<div>
<table border="1">
<thead>
<tr>
<th>用户名</th>
<th>密码</th>
<th>年龄</th>
<th>操作</th>
</tr>

</thead>

<tbody>
{% for obj in data_list %}
<tr>
<td>{{ obj.user }}</td>
<td>{{ obj.password }}</td>
<td>{{ obj.age }}</td>
<td><a href="/info/delete/?nid={{ obj.id }}">删除</a></td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</body>
</html>

添加用户

1
2
3
4
5
6
7
8
9
10
11
def add_info(request):
if request.method == 'GET':
return render(request,'add_info.html')

user = request.POST.get('user')
password = request.POST.get('password')
age = request.POST.get('age')

UserInfo.objects.create(user=user,password=password, age=age)

return redirect('/info/list/')#要跳转到自己的其他页面,不需要加域名 只需要把后面的部分加上就行了
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
{# add_info.html  #}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form method="post">
{# 这里不写action默认值就是本页面#}
{% csrf_token %}
<input type="text" name="user" placeholder="请输入用户名">
<input type="text" name="password" placeholder="请输入密码">
<input type="text" name="age" placeholder="请输入年龄">
<input type="submit" value="提交">

</form>
</body>
</html>

删除用户

1
2
3
4
5
def delete_info(request):
nid = request.GET.get('nid')
UserInfo.objects.filter(id=nid).delete()

return redirect('/info/list/')
1
<td><a href="/info/delete/?nid={{ obj.id }}">删除</a></td>

重头写一个django项目

1.创建django项目

2.创建对应的表结构

1
2
3
4
#models.py
class Department(models.Model):
"""部门表"""
title = models.CharField(verbose_name='部门名称',max_length=100)

这里的verbose_name就是给该列加一个注释

3.设计表结构

e9d126e8d30ed0a2843b555b0d57638c.png

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
#models.py
from django.db import models

# Create your models here.
class Department(models.Model):
"""部门表"""
title = models.CharField(verbose_name='部门名称',max_length=32)


class UserInfo(models.Model):
"""员工表"""
name = models.CharField(verbose_name="姓名",max_length=32)
password = models.CharField(verbose_name="密码",max_length=32)
age = models.CharField(verbose_name="年龄")
account = models.DecimalField(verbose_name="账户余额",max_digits=10,decimal_places=2,default=0)
create_time = models.DateTimeField(verbose_name="入职时间")

#无约束,也就是部门ID可以随便存
#depart = models.BigIntegerField(verbose_name="部门ID")

#有约束
# to 与哪张表关联
# to_field 表中的哪一列关联
#2.django自动
# 写的列叫depart
# 但是django生成的列生叫depart_id
#3.部门表被删除
#3.1级联删除
#depart = models.ForeignKey(to="Department",to_field="id",on_delete=models.CASCADE)
#3.2置空 部门被删除的时候这一列置空
depart = models.ForeignKey(to="Department",to_field="id",null=True,blank=True,on_delete=models.SET_NULL)
#在django中做的约束
gender_choices = (
(1,"男"),
(2,"女"),
)
#这样性别就只能在填上面元组中有的内容了
gender = models.SmallIntegerField(verbose_name="性别",choices=gender_choices)

模板的继承

如果网页中有导航条,那么子页面可能都有这个导航条,如果每个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
42
43
44
45
46
47
48
49
50
51
{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<link rel="stylesheet" href="{% static 'plugins/bootstrap-3.4.1/css/bootstrap.css' %}">
{% block css%}{% endblock%}
</head>
<body>
<nav class="navbar navbar-default">
<div class="container">
<!-- Brand and toggle get grouped for better mobile display -->
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse"
data-target="#bs-example-navbar-collapse-1" aria-expanded="false">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="#">用户管理平台</a>
</div>

<!-- Collect the nav links, forms, and other content for toggling -->
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
<ul class="nav navbar-nav">
<li class="active"><a href="#">部门管理 <span class="sr-only">(current)</span></a></li>
</ul>
<ul class="nav navbar-nav navbar-right">
<li><a href="#">登录</a></li>
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true"
aria-expanded="false">胡越 <span class="caret"></span></a>
<ul class="dropdown-menu">
<li><a href="#">个人信息</a></li>
<li><a href="#">账户余额</a></li>
</ul>
</li>
</ul>
</div>
</div>
</nav>
<div>
{% block content %}{% endblock %}
</div>
{% block js %}{% endblock %}
<script src="{% static 'js/jquery-3.7.1.min.js' %}"></script>
<script src="{% static 'plugins/bootstrap-3.4.1/js/bootstrap.js' %}"></script>
</body>
</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
{% extends "layout.html" %}

{% block css%}{% endblock%}

{% block content %}
<div class="container">
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title"> 新增用户 </h3>
</div>
<div class="panel-body">
<form method="post">
{% csrf_token %}
<div class="form-group">
<label for="exampleInputEmail1">部门名称</label>
<input type="text" class="form-control" placeholder="名称" name="title">
</div>

<button type="submit" class="btn btn-success">保存</button>
</form>
</div>
</div>

</div>
{% endblock %}

{% block js %}{% endblock %}

查询结果的一些特殊情况

查询用户信息,其中包含字段姓名,密码,年龄,账户余额,入职时间,性别,部门这些字段,其中比较特殊的字段为入职时间,性别,和部门

首先是入职时间:特殊之处在于数据库存储的时间格式和日常见到的数据格式是不同的,所以需要格式转换

在pdjango的python语法中的转换方式为(obj为查询出来的行对象)

1
obj.create_time.strftime("%Y-%m-%d")

在html中的模板语法为

1
<td>{{ item.create_time|date:"Y-m-d" }}</td>

然后是性别:特殊之处在于,在数据库中存储的是数字1或2,在构建数据库的时候提供了这样一个元组

1
2
3
4
gender_choices = (
(1,"男"),
(2,"女"),
)

所以直接查询出来的结果也是1或2,问题是如何把1或2和男与女对应起来,django提供了这样的方法

1
2
obj.gender #获取数据库的原始数据
obj.get_gender_display() #获取结果就是1对应的男 2对应的女

在HTML的模板语法为

1
<td>{{ item.get_gender_display }}</td>

区别在于不需要加小括号

最后一个特殊的是部门,因为部门在数据库中存的是部门id,而这个部门id和另外一张部门表关联

1
depart = models.ForeignKey(to="Department",to_field="id",null=True,blank=True,on_delete=models.SET_NULL)

所以直接查询获取的数据是部门id,如何把部门id转换为对应的部门名称,django也提供了方法

1
obj.depart.title

在HTML中为

1
<td>{{ item.depart.title }}</td>

modelform插件

可以将input的过程简略很多,像原来的写法,就是增加部门的写法需要在html里面这样写

1
2
3
4
5
6
7
8
9
<form method="post">
{% csrf_token %}
<div class="form-group">
<label for="exampleInputEmail1">部门名称</label>
<input type="text" class="form-control" placeholder="名称" name="title">
</div>

<button type="submit" class="btn btn-success">保存</button>
</form>

因为部门表只需要提交一个部门名称,而用户表就不一样了,需要提交的数据太多了,所以还是这样一个一个写太过于冗余,所以就引入了modelForm插件,这样将这些过程简略,下面是modelForm的使用示例

首先需要在view.py中新增加一个类

1
2
3
from django import forms

class UserModelForm(forms.ModelForm):

然后在这个类的内部使用modelFrom插件,可以将需要添加input输入框的字段这样添加

1
2
3
4
class Meta:
model = models.UserInfo
fields = ['name','password','age','account','create_time','gender','depart']

然后再对应的user_add类中添加

1
2
form =UserModelForm
return render(request,'user_add.html',{"form":form})

然后再对应的user_add.html页面中添加模板函数

1
2
3
4
5
6
7
8
9
10
11
12
13
<form method="post">
{% csrf_token %}
{% for item in form %}
<div class="form-group">

<label for="exampleInputEmail1">{{ item.label }}</label>
{{ item }}


</div>
{% endfor %}
<button type="submit" class="btn btn-success">保存</button>
</form>

就可以将’name’,’password’,’age’,’account’,’create_time’,’gender’,’depart’这么一大堆的需要添加input输入框的html语法简化为上面这几句

但是这样写会有一些问题,就是modelForm默认提供的input标签是没有样式的,所以如果要增加样式可以将之前的UserModelForm类写成这样

1
2
3
4
5
6
7
8
9
10
11
class UserModelForm(forms.ModelForm):
class Meta:
model = models.UserInfo
fields = ['name','password','age','account','create_time','gender','depart']

def __init__(self, *args, **kwargs):
super().__init__(*args,kwargs)
for name,field in self.fields.items():
#print(name,field);
#找到所有的插件,添加样式form-control样式
field.widget.attrs = {"class":"form-control", "placeholder": field.label, "name": name}

就是新增加了下面那个构造函数