一、Djiango
1.什么是Django
Djiango是一个全能型web框架,如果把互联网比作电网,那么服务器程序(Nginx、Apache等)就是发电厂,用来制造数据。而应用程序相当于每家每户的电器,web框架则相当于每个电器的工作原理。
web框架也有许多种,除了djiango,还有wbe.py、Flask、Tronado等。
二、设计模式
设计模式有两种,一种是MTV,另一种是MVC
MTV:
-M:Models:模型——负责业务数据对象和数据库对象
-T: Template:模板:负责把页面展示给用户(html)
-V:View:视图——模型与模板的桥梁
MVC:
-M:Models:模型——负责业务数据对象和数据库对象
-V:View:视图——与用户交互的界面
-C:Control:控制器——接收用户的输入,调用模型和视图完成用户请求,模型和视图的桥梁
三、环境搭建与项目创建
1.创建虚拟环境
mkvirtualenv -p/usr/bin/python3 djangoApp #djangoApp是环境名,可随意
rmvirtualenv 环境名 #删除该环境
2.安装django框架
pip install django==2.1.7
3.创建文件夹
在已创建的虚拟环境下创建一个文件夹,用来存放项目,之后进入到该文件夹下创建项目
django-admin startproject CRM #CRM是项目名,可随意
4.输入命令
之后进入CRM文件夹,在与manage.py文件同级的情况下输入
python manage.py runserver 0.0.0.0:8000或者0:8000
ps -ef|grep 8000 #Linux系统下查找进程
5.运行服务
服务即可运行,此时在浏览器输入127.0.0.1:8000会出现以下画面

即表示服务启动成功
四、pycharm远程连接
1.创建项目文件夹
在本地(物理机)创建一个新的空项目(文件夹)
2.配置pycharm远程解释器






配置完成
3.路径映射



路径映射完成
4.设置自动同步


自动同步设置完成

五、pycharm启动项目
1.确认服务端关闭
2.配置


django project root一栏填写本地的django项目的路径
settings一栏与manage script一栏必须为相对路径
配置完成
3.创建应用
在对应环境的项目文件夹下输入命令
python manage.py startapp project #project为项目名,可随意
即可创建
六、URL配置
1.简单的视图映射
通过URLconf模块来实现URL路径到视图函数的映射,一个完整的映射应该在urls.py中有路径(path),在视图中有函数


当以上两步完成后,在pycharm远程打开服务端,在浏览器中输入127.0.0.1:8000/index/后就会出现下图

即为一个简单的响应。
2.路径转换器
路径转换器会通过**<>**来捕获url中的参数,语法为< 转换器名:参数名 >,可以对传入参数进行控制,还可传入多个参数



常用转换器有以下几种
str:匹配除了"/"以外所有非空字符串 #如果不加入转换器则默认为srt
urls:
path('str/<str:s1>/', views.str)
views:
def str(request, s1):
return HttpResponse('{}' .format(s1))



int:匹配除"/"以外所有的整数
urls:
path('int/<int:s1>/', views.int)
views:
def int(request, s1):
return HttpResponse('{}' .format(s1))



slug:匹配字母、数字以及横杠、下划线组成的字符串
uuid:匹配格式化的uuid
3.re_path
所谓re_path,就是使用正则表达式进行路径匹配,所以括号内的参数则遵循正则表达式的写法,能够更细致的对path中的参数进行控制。
urls:
re_path(r'test4/(?P<year>\d+)/(?P<month>\d+)/(?P<day>\d+)/', views.test4)
views:
def test4(request, year, month, day):
return HttpResponse('{}年{}月{}日'.format(year, month, day))



4.额外参数Kwargs
在使用kwargs的时候要注意传参的值是字典,所以kwargs={“xx”: “xx”}
urls:
path('test2/', views.test2, kwargs={'name': '小明'})
views:
def test2(request, name):
return HttpResponse('{}同学' .format(name))



5.重定向
重定向,也就是跳转,通过redirect来实现页面的跳转
要使用重定向首先要导入redirect模块

urls:
path('test5/', views.test5)
views:
def test5(request):
return redirect('http://www.bilibili.com')



此时在浏览器中输入urls中配置的地址,如上图,就会跳转到视图函数中设置的地址。
6.多app的路由管理(include模块)
通过导入include模块实现多app路由管理
根目录下的urls文件如下:

app下的urls文件如下:

app下的视图文件如下:

最后在浏览器输入127.0.0.1:8000/app名/视图名/

7.url命名
url命名可以在改变urls.py中的路径名称时而不用修改视图函数,是十分方便的一种办法。
创建路由配置,第一个是原始路径,第二个是url命名后的路径

创建视图函数

此时输入127.0.0.1:8000/test/ 后则会转跳转到127.0.0.1:8000/index/project,并且无论原index路径如何修改都能通过test来跳转到index

七、模板系统
1、文件放置
可将HTML文件写入模板文件中,有两种方式可使用
根目录放置
-
在项目根目录(与manage.py同级)创建一个templates文件夹,所有模板文件集中放入这个文件夹下,在该文件夹下继续创建与app相应的同名文件夹,并在这个文件夹内放入模板(HTML)文件,以便管理
-
在settings.py中找到有一项TEMPLATES的列表

在’DIRS’后输入
os.path.join(BASE_DIR, 'templates')
即配置完成
app内放置
- 放入各个app目录下名为templates文件夹内
首先在app文件夹下创建名为templates的文件夹

在settings.py找到INSTALLED_APPS,添加对应的app

即配置完成
视图,路径配置(根目录下)
首先在对应文件夹下创建一个html文件

其次导入get_templatesm模块和编写视图函数

路由配置参考
此时在浏览器输入127.0.0.1:8000/teacher/test1/

以上是代码底层所做的操作,在实际应用中,视图函数的编写直接使用
根目录下存放时的路径
return render(request, 'teacher/test.html')

视图,路径配置(app下)
在templates下创建html文件

编写视图函数

配置url

访问

通常将模板存放在根目录下
如果需要重复使用同一个app则可选择将模板存放在各app下
2、模板变量
使用context定义一个变量

在前端页面使用

语法为 {{ 变量名 }} (上图的变量名为now)

3、模板过滤器
可直接在模板文件中对变量进行再处理
语法为 {{ 变量名|过滤器名 }} 或{{ 变量名|过滤器名:参数 }}
以下为常用过滤器

18、upper:全部字母大写
注意
1参数前的冒号前后都不能空格,否则报错
2一个变量可使用多次过滤器
4、静态文件导入
静态文件(CSS, JS, IMG)与模板一样,也有两种方式导入:根目录或者app下
首先创建一个名为static文件夹,然后再创建相应app的文件夹便于管理

之后在settings.py文件中找到STATIC_URL,在下一行写入
STATICFILES_DIRS = [os.path.join(BASE_DIR, 'static')]

配置完成
5、模板标签
语法:在模板文件顶端{% load %}
这样可在静态文件前缀改变的情况下而不用改变link标签内的前缀
常用标签

有些标签需要开始和结束标签,比如for标签
{% for %}
{% endfor %}
这样写才算是一个完整的标签,否则会报错
继承与引用
引用(include),在一个模板中引用另一个模板,可使模板复用,减少代码的冗余
语法:
{% include '文件路径' %}
继承需要用到(extends)与(block)这两个标签
先使用extends继承其他模板

这段代码必须放在第一行
再使用block把内容加入到继承的模板中
{% block %}
{% endblock %}



总结
只要在被继承的文件(base.html)中使用block标签后,再回到继承的文件里使用与之对应的block标签即可在页面相同的位置填入想要的内容
每个继承的文件相互独立,互不影响,所以不需要回到被继承文件(base.html)中修改或者增加标签名
如果所设计的页面的块比较多,那么可以选择多使用block标签使页面布局与理想布局一样
6、自定义模板过滤器
可放在app下或者根目录
首先要去settings下INSTALLED_APP中配置(配置了模板的可以跳过)

在哪个app下创建就配置哪个app的名字
创建一个py文件,名字随意,但最好见名思意

定义一个自定义过滤器函数
def to_sex(value, flag='zh'):
change = {
'zh': ('女', '男'),
'en': ('Female', 'Male'),
}
return change[flag][value]
注册自定义过滤器
from django import template #需要导入template模块
register = template.Library() # 变量名必须是register
def to_sex(value, flag='zh'):
change = {
'zh': ('女', '男'),
'en': ('Female', 'Male'),
}
return change[flag][value]
register.filter("sex", to_sex)
register.filter(to_sex) # 如果name参数不指定的话,就会用函数名作为过滤器名
7、自定义模板标签
在app下templatetags的文件夹中创建一个文件夹

定义一个简单标签
案例:
显示当前时间
from datetime import datetime
def current_time():
now = datetime.now().strftime(format_str)
ruturn now
注册
from datetime import datetime
from django.template import Library # 导入Library模块
register = Library() # 注册
def current_time():
now = datetime.now().strftime(format_str)
ruturn now
register.simple_tag(current_time, name='ct') #name为可选参数,如果写入,标签名就为name后面定义的名字,如果不写入,标签名则为函数名
在模板文件中导入{% load customer_tags %}后就可以使用{% ct %}
并且可以在标签后传入参数{% ct ‘%Y年%m月%d日 %H时:%M分:%S秒’%}
定义一个包含标签
一个模板通过渲染另一个模板来展示数据。
模板1(html)
<ul>
{% for item in ls %} #变量ls是从show_list_as_ul这个标签中传来的
<li>{{ item }}</li>
{% endfor %}
</ul>
通过渲染模板1来返回值(customer_tags)
@register.inclusion_tag('show_list_as_ul.html')
def show_list_as_ul(value): #从前端模板接收变量
return {'ls': value}
在需要的模板内使用模板1(html)
{% show_list_as_ul sts.course%}
在上面这几个函数中 sts.course会传递到value最后传递到ls,实现灵活使用
八、数据库的连接配置
数据库的接口

配置MySQL数据库
- 打开虚拟机,在对应的环境(djangoApp)下输入 pip install pymysql
- 进入数据库(mysql -uroot -pqwe123)
- 创建一个新的库(create database CRM)
- 创建一个新的用户
# 创建一个用户名为rex密码为rex的数据库用户,并将CRM下所有表的操作权限授予给该用户
grant all privileges on CRM.* to 'rex'@'%' identified by 'rex'
- 在数据库接口修改默认接口


- 导入API (pymysql)
在根目录下__ init __.py中导入


记得关闭服务,否则会有红线提示,但不影响使用
九、模型基础
1、ORM
ORM(对象关系映射 Object Relational Mapping),使用面向对象的方法来操作数据库,来达到不使用原生sql语句的情况下也能操作数据库
在ORM下,每一个类都是数据库中的一张表,类属性是数据库中的字段,数据就是类的实例,
2、创建模型
在settings文件内检查app是否已注册

在app文件下models.py下创建class

3、模型激活
要使在models.py下的数据生效,就必须得激活这个类,也就是迁移,一个完整的迁移步骤一共有三步:
- 创建模型
如上图
- 生成迁移
使用manage.py生成迁移
python manage.py makemigrations student
#student为app名,加上app名后则会指定app迁移,如不加则全部迁移
- 使迁移生效
python manage.py migrate student
##student为app名,加上app名后则会指定app生效,如不加则全部生效
4、数据操作
为了使命令行清晰美观,我们会使用ipython来继续接下来的操作
在项目环境下输入
pip install ipython
之后在与manage.py同级时输入
python manage.py shell
- 增
from students.models import Student #导入模型
### 第一种增加方式
s = Student(name='Hikari', age="18", sex='0', qq='112334', phone='13000000000')
s.save()
### 第二种增加方式
s1 = Student()
s1.name = 'Homura'
s1.save()
#如果用此方法增加,需要注意表格字段是否允许为空,如不允许为空,则需要为所有不允许为空的字段添加数据,否则保存时会报错
### 第三种方式
Student.objects.create(name='Hana')
#此方式不需要save(),可直接写入数据库
### 第四种方式
Student.objects.get_or_create(name='Tora', age=15)
#此方式同样不需要save,并且可以赋值给其他变量,返回值的第二项如果为True,则代表创建数据,如果为False,则代表此数据已经存在于该表内
- 查
# 查询全部数据
Student,objects.all() #需要给一个变量接收数据
# 查询单条数据
Student,objects.get(pk=1) #pk为主键,pk=1的意思是主键序号等于1的数据,因为主键不一定都为id,所以为了防止错误,使用pk
get方法只能返回一个对象,如果同一字段下有一个以上的值相同,则报错
# 条件查询
Student.objects.filter(age=18) #单条件查询
Student.objects.filter(age=18, sex=0) #多条件查询
如果导入Q模块后可使用or查询
from django.db.models import Q
Student.objects.filter(Q(age=18),Q(sex=0)|Q(age=20)) #意为查询年龄为18或者12并且性别为女的数据
- 改
# 修改单条数据
s = Student.objects.get(pk=2)
s.age = 18
s.save() # 修改主键为2,字段为age的数据修改
# 修改多条数据
Student.objects.filter(age=18).update(phone='13000000000')
# 将所有年龄为18的数据的电话号码都修改成13000000000
- 删
# 删除单条
s = Student.object.get(pk=1)
s.delete()
# 删除多条
Student.objects.filter(age=18).deleter() #删除年龄为18的数据
Student.objects.all().deleter() # 删除所有数据
objects是django模型类的默认管理器,绝大部分方法都是通过objects来实现
5、常用模型命令
查询
除了get;all;filter之外,还有一些比较常见的查询方法
Student.objects.first()/last() #first/last,查询(第一/最后)条数据
Student.objects.exclude(参数) #exclude,查询除了该参数之外的数据
Student.objects.values('指定字段') #value,指定字段查询,如name,age等
Student.objects.only('指定字段') #only,通过字段查询该字段下所有数据,并返回对象
该方法可以将结果赋值给一个变量:
res = Student.objects.only('name')
并且通过下标可以获取该数据下所有字段的值



Student.objects.defer('指定字段') #defer,查询指定字段外的所有数据,并返回对象(与only相反)
排序
Student.objects.order_by('指定字段') #根据指定字段进行升序排序
Student.objects.order_by('-指定字段') #根据指定字段进行降序排序
条件查询
exact
exact:准确匹配
WHERE 'students_student','name' = nia
iexact:不区分大小写匹配
WHERE 'students_student','name' LIKE nia
eg:
Student.objects.filter(name__exact=nia)
contains
contains:包含条件匹配
WHERE 'students_student','name' LIKE BINARY %k%
eg:
Student.objects.filter(name__contains=’k‘) #意为名字中含有字母k的都能匹配

icontains:不区分大小写匹配

in
Student.objects.filter(s_num__in=['001', '003', '005']) #意为s_num中的001,003,005都能匹配

range
范围查询
Student.objects.filter(age__range=(1,18)) #查询age中符合1~18的所有数据

运算符
#gt 大于 #gte 小于 #lt 小于 #lte 小于等于
eg:
res1 = Student.objects.filter(pk__gt=3) #查询主键大于3的所有数据

6、表关系

OneToOne

OneToMany

ManyToMany

表关系的设置规则:符合现实中的操作
具体解释一下什么是符合现实,举个例子:学校里有很多班级,班级里有很多学生
问: 通过班级找对应的学生
通过学生找他对应的班级
哪个比较方便?
当然是通过学生找班级方便
首先如果通过班级找学生,首先要找到班级,然后从班级里许多个学生中找到唯一一个你需要的学生,这么做要花费两个步骤,而通过学生找班级,只要找到一个学生,询问他的班级就可以知道该学生的班级,这么做只要花费一步。
回滚
python manage.py migrate students 0001
回滚后删除最后一次迁移文件
7、表关联对象操作
本节操作都基于以下表

-
OneToMany(正向/反向操作)
正向:模型内有外键字段,通过这个模型对外键进行操作
class Student(models.Model):
.....
grade = models.ForeignKey('Grade', on_delete=models.SET_NULL, null=True)
Student这个模型类通过grade这个实例去操作Grade类就叫做正向操作
表进行关联之后会自动创建一个字段
在这个表中新的字段表示的是该学生所在的班级

增
s1 = Student.objects.get(name='Hikari')
s1.grade_id=1
s1.save()
查
查询该学生所在班级
Student.objects.get(name='Hikari').grade.name

删
删除并不是把这条数据删除,而是切断这条数据与grade表的关联
Student.objects.get(name='Suzaku')
s1.grade=None
s1.save()
此时再查询学生‘Suzaku’的班级信息则会报错
如想再次增加该学生信息重复上面的增加操作即可

反向:一个模型被另一个模型的外键关联,通过被关联的模型对关联它的模型进行操作
反向操作的前提是先需要通过正向操作取到值后,再通过student_set管理器来操作,如:
Student.objects.get(name='Suzaku').grade.student_set.filter(name='Kos').update(s_num='019')

增:
Student.objects.get(name='Suzaku').grade.student_set.create(....)
Student.objects.get(name='Suzaku').grade.student_set.add(....) #add方法可以一次增加多条数据
改
Student.objects.get(name='Suzaku').grade.student_set.set()
删
s2 = Student.objects.get(name='Kos')
Student.objects.get(pk='14').grade.student_set.set([s2])
意思是将pk=14的数据全部取出来,然后将其所对应的grade表的值所关联的主表值全部清空,然后再放入s2
说人话
比如,pk=14的学生'Hanabi'在3班,上面这段代码通过找到这个学生,然后再找到3班,把原来三班的人全部清空,重新放入s2(也就是学生'Kos')
总结:1.反向操作的管理器和正向操作是一样的,只不过名字不同,正向能用的功能反向一样能用
2.需要先通过主表获取到外键的值后才能使用反向操作
3.管理器的名字是主表名(小写)_set
比如我的主表名字是AAA,那么默认管理器的名字就是aaa_set
-
ManyToMany(正向/反向操作)
多对多的表关系操作首先要让中间表与其他的表进行关联
增 c1 = Course.objects.create(name='Java', teacher='UT')
s1 = Student.objects.last()
e = Enroll()
e.course = c1
e.student = s1
e.save()
这样就创建了一个课程数据c1,并且把学生与c1关联起来了
查
正向
from students.models import Student,StudentDetail,Course,Grade,Enroll
v1 = Student.objects.last()
v1.courses.all()
<QuerySet [<Course: Course object (8)>]>
- **OneToOne**
增
#正向
方法1:创建的同时绑定数据,不需要指定student_detail表的student_id字段
d2 = StudentDetail(college=‘山东蓝翔’)
s2 = Student.objects.filter(pk=17) #注意,这时候取出来的值是一个列表
d2.student=s2[0]
d2.save()
方法2:先创建college字段,需要指定student_detail表的student_id字段(不指定则会报错),再获取学生数据进行绑定
s1 = Student.objects.filter(pk=3) #注意,这时候取出来的值是一个列表
d1 = StudentDetail(college=‘新东方烹饪学校’, student_id=‘0’)
d1.student=s1[0] # s1=<QuerySet [<Student: Rekusu>]>,所以要用下标取值
使用studen建立联系,如下图
d1.save()
#反向:与正向类似
d = StudentDetail(college=‘北大青鸟’,student_id=‘0’)
s = Student.objects.filter(pk=9)[0]
s.studentdetail = d
d.save()

查
#正向
StudentDetail.objects.values(‘college’,‘student__name’,‘student__age’)[0][‘student__name’]
‘Kos’
#反向:与正向类似
Student.objects.values(‘studentdetail__college’)
**跨表查询**
以跨模型的相关字段名,加上双下划线隔开,直到需要的结果为止
#查询男生报名的课程
Course.objects.filter(students__sex=1)
<QuerySet [<Course: Java>]>
#查询报名了Java课程的学员
Student.objects.filter(courses__name=‘Java’)
<QuerySet [<Student: Kos>]>
#查询报名了python课程并在django框架班第11期的学员
Student.objects.filter(courses__name=‘python’,grade__num=11)
<QuerySet [<Student: Hikari>, <Student: Homura>]>
#查询学员报名课程所在的班级有哪些
Grade.objects.filter(student__courses__name=‘python’)
<QuerySet [<Grade: django框架班>, <Grade: django框架班>]>
总结:区分正向反向的标准看外键字段
多对多关系绑定通过中间表,从除中间表外的两个表中各取出一个数据进行关联(详细查看ManyToMany第一条)
#### 十、请求与响应
django框架的请求与响应的流程:
输入网址,请求页面(GET请求),通过路径找到对应的视图函数,并创建一个HttpRequest对象,该对象包含了关于请求的源数据,之后经过渲染处理后,通过视图返回一个HttpResponse对象
**HttpRequest对象**
1.GET请求:只是从服务器获取数据,不会更改数据库的状态和数据,可在路径中看到参数
2.POST请求:携带数据发送至服务器,一般会更改服务器数据,不能再路径中看到参数
3.虽然GET请求会在URL中看到参数,但并不能保证POST请求比GET请求安全,需要看加密方式
**文件上传存储路径**
1.在项目根目录下static文件夹中创建一个文件夹media(名字随意)

2.在settins中进行配置
MEDIA_ROOT = os.path.join(BASE_DIR, ‘static/media’)

视图函数

导入模块,后续会用到
编写视图函数
def index(request):
if request.method == ‘POST’:
files = request.FILES.getlist(‘file’) #获取多个文件
day_dir = datetime.now().strftime('%Y%m%d') #创建文件夹时的命名
dir_path = os.path.join(MEDIA_ROOT, day_dir) #拼接创建文件夹的路径
if not os.path.exists(dir_path): #判断文件夹是否重名
os.mkdir(dir_path) #创建文件夹
for file in files: #遍历获取多个文件
filename = os.path.join(dir_path, file.name)
with open(filename, 'wb')as f:
for line in file.chunks():
f.write(line) #写入文件
return render(request, 'teacher/Upload.html')
**HttpResponse对象**
HttpResponse对象下的方法,除了有之前用到过的contant,redirect,还有jsonResponse
JsonResponse
构造json数据
def test_json(request):
sex = request.GET.get(‘sex’)
sex = int(sex)
res = Student.objects.values(‘name’, ‘age’, ‘sex’)
res = list(res)
data = {‘result’: res}
return JsonResponse(data)
**Cookie**
1570538676100](assets/1570538676100.png)
2.在settins中进行配置
MEDIA_ROOT = os.path.join(BASE_DIR, ‘static/media’)

视图函数

导入模块,后续会用到
编写视图函数
def index(request):
if request.method == ‘POST’:
files = request.FILES.getlist(‘file’) #获取多个文件
day_dir = datetime.now().strftime('%Y%m%d') #创建文件夹时的命名
dir_path = os.path.join(MEDIA_ROOT, day_dir) #拼接创建文件夹的路径
if not os.path.exists(dir_path): #判断文件夹是否重名
os.mkdir(dir_path) #创建文件夹
for file in files: #遍历获取多个文件
filename = os.path.join(dir_path, file.name)
with open(filename, 'wb')as f:
for line in file.chunks():
f.write(line) #写入文件
return render(request, 'teacher/Upload.html')
**HttpResponse对象**
HttpResponse对象下的方法,除了有之前用到过的contant,redirect,还有jsonResponse
JsonResponse
构造json数据
def test_json(request):
sex = request.GET.get(‘sex’)
sex = int(sex)
res = Student.objects.values(‘name’, ‘age’, ‘sex’)
res = list(res)
data = {‘result’: res}
return JsonResponse(data)
**Cookie**
客户端在访问服务器时(发送请求),服务器在http协议中加上请求求,通过响应,传到客户端,并保存在客户端,当客户端再次访问时,会自动带上cookie去访问,这样服务器就可以识别客户端
本文详细介绍了Django框架的基础知识,包括其定义、设计模式(MTV与MVC)、环境搭建、PyCharm远程连接配置、项目启动、URL配置、模板系统、数据库连接配置以及模型基础。内容涵盖从创建项目到实现视图映射、模板变量、模板过滤器、静态文件导入、数据库操作等,适合Django初学者入门学习。
7132

被折叠的 条评论
为什么被折叠?



