记录Django学习笔记
https://www.bilibili.com/video/BV1rx411X717
创建工程
1 | django-admin startproject HelloDjango |
创建应用
1 | python manage.py startapp App |
在setting.py中注册应用:
1 | INSTALLED_APPS = [ |
开发者服务器
1 | python manage.py runserver 0.0.0.0:8000 |
允许访问范围
1 | ALLOWED_HOSTS = ["*"] |
语言和时区设置
1 | LANGUAGE_CODE = 'zh-hans' |
迁移
1 | python manage.py migrate |
注册路由
1 | from learn1 import views |
1 | def hello(request): |
html模板
两种
- 在App中进行模板配置
- 只需在App的根目录创建templates文件夹即可
- 如果想让代码自动提示,我们应该标记文件夹为模板文件夹
- 在项目目录中进行模板配置
- 需要在项目目录中创建templates文件夹并标记
- 需要在settings中进行注册
- 在开发中使用第二种
- 模板可以继承,复用
在HelloDjango中新建templates文件夹并设置为模板文件夹(方便代码提示),在其中新建html模板
然后再settings.py中加入templates路径
1 | TEMPLATES = [ |
HTML小技巧:
1 | ul>li*4(tab键) |
1 | <ul> |
分发路由
这样就可以访问ip/learn2/hello了
- 项目如果逻辑过于复杂,可以进行拆分
- 拆分为多个App
- 继续拆分路由器 urls
- 在App中创建自己的urls
- urlpatterns 路由规则列表
- 在根urls中进行子路由的包含
- 子路由使用
- 根路由规则 + 子路由的规则
- 在App中创建自己的urls
1 | from django.urls import path |
在HelloDjango的urls.py中导入learn2中的路由
1 | urlpatterns = [ |
models 使用了ORM技术
- Object Relational Mapping 对象关系映射
- 将业务逻辑进行了一个解耦合
- object.save()
- object.delete()
- 关系型数据库
- DDL
- 通过models定义实现 数据库表的定义
- 数据操作
- 增删改查
- 存储
- save()
- 查询
- 查所有 objects.all()
- 查单个 objects.get(pk=xx)
- 更新
- 基于查询的
- 查好的对象,修改属性,然后save()
- 删除
- 基于查询的
- 调用 delete()
快捷键
- control + p
- 参数提示
- shift + f6 重命名,重构
- .re 快捷生成return
- .if 多用点看看世界的美好
连接mysql驱动
- mysqlclient
- python2,3都能直接使用
- 致命缺点
- 对mysql安装有要求,必须指定位置存在配置文件
- python-mysql
- python2 支持很好
- python3 不支持
- pymysql
- python2,python3都支持
- 它还可以伪装成前面的库
1 | import pymysql |
重新建立 migration 文件
1.首先要保证,目前的migration文件和数据库是同步的,通过执行
1 | python manage.py makemigrations |
如果看到 这样的提示: No changes detected,则可以继续接下来的步骤
2.通过执行
1 | python manage.py showmigrations |
结果,可以看到当前项目,所有的app及对应的已经生效的migration文件如
1 | git_hook |
3.通过执行
1 | python manage.py migrate –fake pay zero |
这里的 pay就是你要重置的app
4.之后再执行 python manage.pu showmigrations
,你会发现 文件前的 [x] 变成了[ ]
现在,你可以删除pay 这个 app下的migrations模块中 除 init.py 之外的所有文件。
5.之后,执行
1 | python manage.py makemigrations |
程序会再次为这个app 生成 0001_initial.py 之类的文件
6.最重要的一步来了, 执行
1 | python manage.py migrate –fake-inital |
–fake-inital 会在数据库中的 migrations表中记录当前这个app 执行到 0001_initial.py ,但是它不会真的执行该文件中的 代码。
这样就做到了,既不对现有的数据库改动,而又可以重置 migraion 文件,妈妈再也不用在 migration模块中看到一推文件了。
重新生成数据库中的某张表
1.删除数据库中的django_migration 表中对应的记录以及你要重新导的表
2.将你要导的那个app中的migrate 文件删除掉
3.重新导入你需要的表
1 | python manage.py makemigration shop(你要导的app) |
这样就完成了。
表关系
-
分类
-
ForeignKey:一对多,将字段定义在多的端中
-
ManyToManyField:多对多,将字段定义在两端
-
OneToOneField:一对一,将字段定义在任意一端中
-
-
用一访问多
- 格式
- 对象.模型类小写_set
- 示例
- grade.students_set
- 格式
-
用一访问一
- 格式
- 对象.模型类小写
- 示例
- grade.students
- 格式
-
访问id
- 格式
- 对象.属性_id
- 示例
- student.sgrade_id
- 格式
模型过滤
- filter():返回符合筛选条件的结果
- exclude():返回不符合筛选条件的结果
- all():返回所有数据
- order_by(‘id’):排序,如果要逆序就加个
-
- values():一条数据就是一个字典,返回一个列表
- 连续使用
- 链式调用
- Person.objects.filter().filter().xxxx.eclude().exclude().yyyy
方法
-
对象方法
- 可以调用对象的属性,也可以调用类的属性
-
类方法
- 不能调用对象属性,只能调用类属性
1
2
3@classmethod
def create(cls, p_name, p_age=100):
return cls(p_name=p_name, p_age=p_age) -
静态方法
- 啥都不能调用,不能获取对象属性,也不能获取类属性
- 只是寄生在我们这个类上而已
获取单个对象
- get
- 查询条件没有匹配的对象,会抛异常,DoesNotExist
- 如果查询条件对应多个对象,会抛异常,MultipleObjectsReturned
- first
- last
- count
- exist
first和last
- 默认情况下可以正常从QuerySet中获取
- 隐藏bug
- 可能会出现 first和last获取到的是相同的对象
- 显式,手动写排序规则(先order_by)
- 可能会出现 first和last获取到的是相同的对象
切片
- 和python中的切片不太一样
- QuerySet[5:15] 获取第五条到第十五条数据
- 相当于SQL中limit和offset
缓存集
- filter
- exclude
- all
- 都不会真正的去查询数据库
- 只有我们在迭代结果集,或者获取单个对象属性的时候,它才会去查询数据库
- 懒查询
- 为了优化我们结构和查询
查询条件
- 属性__运算符=值
- gt 大于
- lt 小于
- gte 大于等于
- lte 小于等于
- in 在某一集合中
- contains 类似于 模糊查询 like
- startswith 以xx开始 本质也是like
- endswith 以 xx 结束 也是like
- exact
- 前面同时添加i , ignore 忽略
- iexact
- icontains
- istartswith
- iendswith
- django中查询条件有时区问题
- 关闭django中自定义的时区
- 在数据库中创建对应的时区表
模型成员
- 显性属性
- 开发者手动书写的属性
- 隐性属性
- 开发者没有书写,ORM自动生成的
- 如果你把隐性属性手动声明了,系统就不会为你产生隐性属性了
从MySql到model
1 | python manage.py inspectdb > backstage/models.py |
sort排序
2)key参数/函数
从python2.4开始,list.sort()和sorted()函数增加了key参数来指定一个函数,此函数将在每个元素比较前被调用。 例如通过key指定的函数来忽略字符串的大小写:
代码如下:
1 | sorted("This is a test string from Andrew".split(), key=str.lower) |
key参数的值为一个函数,此函数只有一个参数且返回一个值用来进行比较。这个技术是快速的因为key指定的函数将准确地对每个元素调用。
更广泛的使用情况是用复杂对象的某些值来对复杂对象的序列排序,例如:
代码如下:
1 | student_tuples = [ |
Paginator分页
1 | from django.core.paginator import Paginator |
pop()间接修改键的key值
pop()一般用作删除列表中元素,但是它的返回值很有趣
1 | pop(key[,default]) |
- key: 要删除的键/值对所对应的键
- default: 可选参数,给定键不在字典中时必须设置,否者会报错(没有默认值),此时返回default值,
Python 字典 pop() 方法删除给定键所对应的键/值对,并返回被删除的值。给定键如果不在字典中,则必须设置一个default值,否则会报错,此时返回的就是default值。
model_to_dict()单个对象转字典
1 | from django.forms import model_to_dict |
取日期区间
1 | import datetime |
django中通过model名字获取model
1 |
|
时间类型
-
default=datetime.now()
model每次初始化,都会自动设置该字段的默认值为初始化时间。
-
default=datetime.now
model每次进行新增或修改操作,都会自动设置该字段的值为操作时间。设置后仍可以使用ORM手动修改该字段。
-
auto_now_add=True
默认值为False,若设置为True,model每次进行新增操作,都会自动设置该字段的值为操作时间。设置为True后无法使用ORM手动修改该字段,哪怕填充了字段的值也会被覆盖。
-
auto_now=True
默认值为False,若设置为True,model每次进行新增或修改操作,都会自动设置该字段的值为操作时间。设置为True后无法使用ORM手动修改该字段,哪怕填充了字段的值也会被覆盖。
-
要注意的点
除非想设置动态默认时间为项目的启动时间,否则default=datetime.now()这种用法是错误的,会得到期望之外的结果。
使用User.objects.update方法时,设置的default=datetime.now和auto_now=True都不会生效,由于设置了auto_now=True的字段不能手动修改,此时只能使用save方法修改数据,这对于多个数据的更新是不友好的。
因此如果设置动态默认时间的字段,应该使用default=datetime.now和auto_now_add=True来实现。
djang获取models字段方法
通过._meta.fields获取
以Student这个model为例
1 | In [59]: Student._meta.fields |
获取字段名:
1 | In [62]: stu = Student._meta.fields |
修改数据库中部分信息
1 | def add_work(request): |
外键不能直接插入
1 | publisher = UserAdmin.objects.get(id=publisherid) |
去重查询
1 | works = MainDataTougaolanmu.objects.all().values('userid_id').distinct() |
解决跨域
在整个项目的setting.py中进行修改
1 | INSTALLED_APPS = [ |
1 | MIDDLEWARE = [ |
1 | # 跨域增加忽略 |