orm对象关系映射
类 数据库的表
对象 表的记录
对象获取属性 记录的某个字段对应的值
优点:能够让一个不会数据库操作的人 也能够简单快捷去使用数据库
缺点:由于封装程度太高 可能会导致程序的执行效率偏低
有时候 结合项目需求 可能需要你手写sql语句
注意事项
1.django的orm不会自动帮你创建库,库需要你自己手动创建
表会自动帮你创建 你只需要书写符合django orm语法的代码即可
去应用下所在的models.py中书写类
from django.db import models
# Create your models here.
class Userinfo(models.Model):
# 设置id字段为userinfo表的主键 id int primary key auto_increment
id = models.AutoField(primary_key=True) # 在django中 你可以不指定主键字段 django orm会自动给你当前表新建一个名为id的主键字段
# 设置username字段 username varchar(64) CharField必须要指定max_length参数
username = models.CharField(max_length=64) # 在django orm中 没有char字段 但是django 暴露给用户 可以自定义char字段
# 设置password字段 password int
password = models.IntegerField()
*****数据库迁移(同步)命令******
python manage.py makemigrations # 不会创建表 仅仅是生成一个记录 将你当前的操作记录到一个小本本上(migrations文件夹)
python manage.py migrate # 将你的orm语句真正的迁移到(同步)到数据库中
只要你在models.py中修改了跟数据库相关的代码 你就必须重新开始执行上面两条命令
基于函数/类的视图
CBV
写视图函数 必须要写一个类 然后继续View
from django.views import View
class MyLogin(View):
def get(self,request):
return render(request,'login.html')
def post(self,request):
return HttpResponse('post请求')
路由配置
CBV源码
FBV
url(r'^index/',views.index)
CBV
url(r'^login/',views.MyLogin.as_view())
# url(r'^login/',views.view)
def as_view(cls,*args,**kwargs):
def view(...):
self = cls(...)
return self.dispatch(...)
return view
def dispatch(...):
# 判断当前请求方式在不在八个默认的请求方式中 get post delete options ...
# 利用反射 获取对象的所对应的属性或者是方法
# 执行对应方法
?
django暴露给用户一个自定义配置的文件
用户配置了就用用户的 用户没有配置就使用默认的 并且配置文件中的变量名必须是大写才有效
from django.conf import settings
settings = LazySettings()
class LazySettings(object):
...
class Settings(object):
# 循环获取默认的配置文件中所有的大写配置
# 利用setattr给对象不停的设置键值对
# 再循环获取暴露给用户的自定义配置文件中所有的大写的配置
# 再利用setattr给对象不停的设置键值对
"""字典的键存在的情况 再设值其实就是替换"""
{{}} 变量相关
{%%} 逻辑相关
模板语法传值
python基本数据类型
如果传递给前端一个函数名 会直接加括号调用 将函数的返回值展示到前端
如果函数有参数 不好意思 django的模板语法 不支持给函数传参
#方法都不能传参
<p>{{ obj }}</p>
<p>{{ obj.get_cls }}</p>
<p>{{ obj.get_func }}</p>
<p>{{ obj.get_self }}</p>
?
? 模板语法获取容器类型的数据 只能采用句点符(.)
? 点索引
? 点键
?
{{ l.1 }}
{{ l.3 }}
{{ d.username }}
{{ d.password }}
{{ d.password.1 }}
过滤器 有点类似于小的方法
会将|左边的值当作第一个参数传入 右边的当作第二个参数传入
|add
|default
|length
|slice
|truncatechars # 截字符 三点也算
|truncatewords # 按空格截 三点不算
|filesizeformat
|safe
<p>{{ n|add:100 }}</p>
<p>{{ n|add:'abc' }}</p>
<p>{{ s|add:'sasahhdasda' }}</p>
<p>{{ l|length }}</p>
<p>{{ d|length }}</p>
{#<p>{{ file_size|filesizeformat }}</p>#}
{#<p>截取10个字符 三个点也算{{ w1|truncatechars:10 }}</p>#}
{#<p>截取10个字符 三个点也算{{ w|truncatechars:10 }}</p>#}
{#<p>安装空格截取单词 三个点不算{{ w1|truncatewords:6 }}</p>#}
{#<p>安装空格截取单词 三个点不算{{ w|truncatewords:6 }}</p>#}
{#<p>安装空格截取单词 三个点不算{{ w2|truncatewords:6 }}</p>#}
{#<p>{{ l|slice:'0:5' }}</p>#}
{#<p>{{ l|slice:'0:5:2' }}</p>#}
{#<p>{{ ctime|date:'Y-m-d' }}</p>#}
{#<p>{{ ctime|date:'Y年/m月' }}</p>#}
{#<p>{{ sss|safe }}</p>#}
{#<p>{{ sss1|safe }}</p>#}
{#<p>{{ res }}</p>#}
?
? {#
{{ xo|default:‘‘ }}#}
? {#有值就拿值 没值就用后面默认的#}
? 前端
? |safe
? 后端
? from django.utils.safestring import mark_safe
?
? res = mark_safe("<h1>111</h1>")
? """前端代码不一定必须要在前端写好 也可以再后端写完 传递给前端页面"""
? 只要思想不滑坡 方法总比困难多
{%%}
if判断 后端语法一模一样
{#{% if xo %}#}
{# <p>xo有值</p>#}
{#{% else %}#}
{# <p>xo没有值</p>#}
{#{% endif %}#}
{#{% if xo %}#}
{# <p>xo有值</p>#}
{#{% elif xo1 %}#}
{# <p>xo1有值</p>#}
{#{% else %}#}
{# <p>去他大爷的</p>#}
{#{% endif %}#}
for循环
内部提供了一个forloop对象
{#{% for foo in l %}#}
{# {% if forloop.first %}#}
{# <p>这是我的第一次</p>#}
{# {% elif forloop.last %}#}
{# <p>这是最后一次了啊</p>#}
{# {% else %}#}
{# <p>嗨起来 大宝贝~</p>#}
{# {% endif %}#}
{#{% endfor %}#}
?
? {#{% for foo in xo %}#}
? {#
{{ forloop.counter }}:{{ foo }}
#}你给我的对象是个空的没法进行for循环
#}{{ yyy.user_list.2.username.1 }}
#}{#{% with yyy.user_list.2.username.1 as dsb %}#}
{# <p>{{ dsb }}</p>#}
{# <p>{{ yyy.user_list.2.username.1 }}</p>#}
{#{% endwith %}#}
keys,values,items
{#{% for foo in d.items %}#}
{# <p>{{ foo }}</p>#}
{#{% endfor %}#}
{##}
{#{% for foo in d.keys %}#}
{# <p>{{ foo }}</p>#}
{#{% endfor %}#}
{##}
{#{% for foo in d.values %}#}
{# <p>{{ foo }}</p>#}
{#{% endfor %}#}
1.在应用下新建一个名字必须叫templatetags文件夹
2.在该文件夹下新建一个任何名称的py文件
3.在该py文件中 先固定写两行代码
from django.template import Library
register = Library()
@register.filter(name='过滤器的名字')
def index(a,b):
# 过滤器内部逻辑代码
... # ...等价于pass
@register.simple_tag(name='标签的名字')
def login(a,b,c,*args):
...
很多页面的大部分区域长的都差不多的情况下 你可以考虑使用模板的继承
1,在你想用的那个页面上 通过block事先划定 你将来可能用得到的区域
{% block 名字 %}
模板内容
{% endblock %}
2,子板需要先继承模板 才能用到该模板中 事先划定的区域
{% extends 模板的名字 %}
{% block 名字 %}
子板内容
{% endblock %}
一个模板页面通常应该有三个区域
{% block css %}
{% endblock %}
{% block content %}
{% endblock %}
{% block js %}
{% endblock %}
通常情况下是将页面上的某一块区域当作一个模块
{% include 模块名 %}
"""
如果你向查看orm语句内部真正的sql语句有两种方式
1.如果是queryset对象 可以直接点query查看
2.配置文件中 直接配置
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'handlers': {
'console': {
'level': 'DEBUG',
'class': 'logging.StreamHandler',
},
},
'loggers': {
'django.db.backends': {
'handlers': ['console'],
'propagate': True,
'level': 'DEBUG',
},
}}
"""
只要是queryset对象就可以无限制的点queryset对象的方法
queryset.filter().filter().filter()
import os
if __name__ == "__main__":
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "one_search.settings")
import django
django.setup()
# 你就可以在下面测试django任何的py文件
把上面代码直接复制到tests.py文件中
# 单表操作
# 增删改查
# 增
# models.Book.objects.create(title='西游记',price=123.23,publish_date='2019-10-24')
# from datetime import date# ctime = date.today()
# book_obj = models.Book(title='三国演义',price=666.66,publish_date=ctime)
# book_obj.save()# 改# models.Book.objects.filter(pk=1).update(price=999.66)
# book_obj = models.Book.objects.filter(pk=1).first()
# book_obj.title = '不符合社会主义核心价值观'
# book_obj.save()
# 删除
# models.Book.objects.filter(pk=1).delete()
#
# 1.all() 查询所有 QuerySet
# res = models.Book.objects.all() # 惰性查询
# print(res)
# for i in res:
# print(i.title)
# 2.filter() QuerySet
# res = models.Book.objects.filter(pk=2)
# print(res)
# 3.get() 数据对象本身
# 4.first() 拿第一个
# res = models.Book.objects.all()
# print(res)
# print(res.first())
#5. last() 拿最后一个
# res = models.Book.objects.all()
# print(res)
# print(res.last())
# 6.exclude 除此之外 QuerySet
# res = models.Book.objects.exclude(pk=3).filter(pk=4).filter(pk=1).filter(pk=4)
# # # <QuerySet []>
# # print(res)
# 7.values QuerySet 列表套字典
# res = models.Book.objects.values('title')
# for r in res:
# print(r.get('title'))
# 8.values_list QuerySet 列表套元组
# res = models.Book.objects.values_list('title')
# print(res)
# 9.count() 统计数据的个数
# res = models.Book.objects.count()
# res1 = models.Book.objects.all().count()
# print(res,res1)
# 10.distinct() 去重
"""去重:数据必须是一模一样的情况下才能去重"""
# res = models.Book.objects.all().distinct()
# res1 = models.Book.objects.values('title','price').distinct()
# print(res1)
# 11.order_by()
# res = models.Book.objects.order_by('price') # 默认是升序
# # res1 = models.Book.objects.order_by('-price') # 加负号就是降序
# print(res)
# 12.reverse() 前面必须是先结果排序才可以反转
# res = models.Book.objects.order_by('price').reverse()
# print(res)
# 13.exists() 一点卵用没有
# res = models.Book.objects.filter(pk=1).exists()
# print(res)
# 查询价格大于200的书籍
# res = models.Book.objects.filter(price__gt=200)
# 查询价格小于200的书籍
# res = models.Book.objects.filter(price__lt=200)
# print(res)
# 查询价格大于或者等于200的书籍
# res = models.Book.objects.filter(price__gte=200)
# res1 = models.Book.objects.filter(price__lte=200)
# print(res,res1)
# 价格是200 或者是123.23 或者666.66
# res = models.Book.objects.filter(price__in=[200,123.23,666.66])
# print(res)
# 价格在200 到700之间的书籍
# res = models.Book.objects.filter(price__range=(200,666.66)) # 顾头不顾尾
# print(res)
# 查询书籍名称中包含p的
# res = models.Book.objects.filter(title__contains='p') # 区分大小写
# print(res)
# 忽略大小写
# res = models.Book.objects.filter(title__icontains='p') # 忽略大小写
# print(res)
# 查询书籍名称是以三开头的书籍
# res = models.Book.objects.filter(title__startswith='三')
# res1 = models.Book.objects.filter(title__endswith='P')
# print(res1)
# 查询出版日期是2019年的书籍
# res = models.Book.objects.filter(publish_date__year='2019')
# 查询出版日期是10月的书籍
# res = models.Book.objects.filter(publish_date__month='10')
# 增
# models.Book.objects.create(title='三国演义',price=123.23,publish_id=1) # publish_id直接传出版社主键值
# publish_obj = models.Publish.objects.filter(pk=2).first()
# models.Book.objects.create(title='水浒传',price=123.23,publish=publish_obj) # publish直接传出版社数据对象
# 查
# book_obj = models.Book.objects.filter(pk=1).first()
# print(book_obj.publish) # 获取到当前所对应的出版社对象
# print(book_obj.publish_id) # 获取到的就是表中的实际字段
# 改
# models.Book.objects.filter(pk=1).update(publish_id=3)
# publish_obj = models.Publish.objects.filter(pk=2).first()
# models.Book.objects.filter(pk=1).update(publish=publish_obj)
# 删除
# models.Publish.objects.filter(pk=2).delete()
# 默认也是级联更新 级联删除
# 给主键为3的书籍添加两个作者 1 2
# book_obj = models.Book.objects.filter(pk=3).first()
# # print(book_obj.authors) # 就相当于 已经在书籍和作者的关系表了
# # book_obj.authors.add(1)
# # book_obj.authors.add(2,3)
# author_obj = models.Author.objects.filter(pk=1).first()
# author_obj1 = models.Author.objects.filter(pk=2).first()
# # book_obj.authors.add(author_obj)
# book_obj.authors.add(author_obj,author_obj1)
"""
add() 括号内既可以传数字也可以传数据对象
并且都支持传多个
"""
# 修改关系
# book_obj = models.Book.objects.filter(pk=3).first()
# # book_obj.authors.set([3,])
# # book_obj.authors.set([1,3])
# author_obj = models.Author.objects.filter(pk=1).first()
# author_obj1 = models.Author.objects.filter(pk=2).first()
# book_obj.authors.set((author_obj,))
# book_obj.authors.set((author_obj,author_obj1))
"""
set() 括号内 既可以传数字也传对象
并且也是支持传多个的
但是需要注意 括号内必须是一个可迭代对象
"""
# 删
# book_obj = models.Book.objects.filter(pk=3).first()
# # book_obj.authors.remove(2)
# # book_obj.authors.remove(1,2)
#
# author_obj = models.Author.objects.filter(pk=1).first()
# author_obj1 = models.Author.objects.filter(pk=2).first()
# # book_obj.authors.remove(author_obj)
# book_obj.authors.remove(author_obj,author_obj1)
"""
remove() 括号内 既可以传数字也传对象
并且也是支持传多个的
"""
# 清空
# book_obj = models.Book.objects.filter(pk=3).first()
# book_obj.authors.clear()
"""clear()括号内不需要传任何参数 直接清空当前书籍对象所有的记录"""
"""
1.子查询
2.连表查询
正反向的概念
外键字段在谁那儿 由谁查谁就是正向
谁手里有外键字段 谁就是正向查
没有外键字段的就是反向
书籍对象 查 出版社 外键字段在书籍 正向查询
出版社 查 书籍 外键字段在书籍 反向查询
正向查询按字段
反向查询按表名小写 ...
"""
# 1.查询书籍是python入门的出版社名称
# book_obj = models.Book.objects.filter(title='python入门').first()
# # 正向查询按字段
# print(book_obj.publish.name)
# print(book_obj.publish.addr)
# 2.查询书籍主键是6的作者姓名
# book_obj = models.Book.objects.filter(pk=6).first()
# # print(book_obj.authors) # app01.Author.None
# print(book_obj.authors.all())
# 3.查询作者是jason的手机号
# author_obj = models.Author.objects.filter(name='jason').first()
# print(author_obj.author_detail.phone)
# print(author_obj.author_detail.addr)
"""
正向查询 按字段
当该字段所对应的数据有多个的时候 需要加.all()
否者点外键字段直接就能够拿到数据对象
"""
# 4.查询出版社是东方出版社出版过的书籍
# publish_obj = models.Publish.objects.filter(name='东方出版社').first()
# # print(publish_obj.book_set) # app01.Book.None
# print(publish_obj.book_set.all())
# 5.查询作者是jason写过的所有的书
# author_obj = models.Author.objects.filter(name='jason').first()
# # print(author_obj.book_set) # app01.Book.None
# print(author_obj.book_set.all())
# 6.查询手机号是110的作者
# author_detail_obj = models.AuthorDetail.objects.filter(phone=110).first()
# print(author_detail_obj.author)
# print(author_detail_obj.author.name)
# print(author_detail_obj.author.age)
"""
反向查询按表名小写
什么时候需要加_set.all()
当查询的结果可以是多个的情况下 需要加_set.all()
什么时候不需要加_set.all()
当查询的结果有且只有一个的情况下 不需要加任何东西 直接表名小写即可
"""
# 7.查询书籍是python入门的作者的手机号
# book_obj = models.Book.objects.filter(title='python入门').first()
# print(book_obj.authors.all())
"""
MySQL
left join
inner join
right join
union
"""
# 1.查询书籍是python入门的出版社名称
# 正向
# res = models.Book.objects.filter(title='python入门').values('publish__name')
# print(res)
# 反向
# res = models.Publish.objects.filter(book__title='python入门').values('name')
# print(res)
# 2.查询作者是jason的手机号码
# 正向
# res1 = models.Author.objects.filter(name='jason').values('author_detail__phone')
# print(res1)
# 反向
# res = models.AuthorDetail.objects.filter(author__name='jason').values('phone','author__age')
# print(res)
# 3.查询手机号是120的作者姓名
# res2 = models.AuthorDetail.objects.filter(phone=120).values('author__name')
# print(res2)
# res = models.Author.objects.filter(author_detail__phone=120).values('name','author_detail__addr')
# print(res)
# 4.查询出版社是东方出版社出版的书籍名称
# res = models.Publish.objects.filter(name='东方出版社').values('book__title','addr')
# print(res)
# 5.查询作者是jason的写过的书的名字和价格
# res = models.Author.objects.filter(name='jason').values('book__title','book__price')
# print(res)
# 7.查询书籍是python入门的作者的手机号
# res = models.Book.objects.filter(title='python入门').values('authors__author_detail__phone')
# print(res)
"""
关键字:aggregate
"""
from django.db.models import Max,Min,Count,Sum,Avg
# 统计所有书平均价格
# res = models.Book.objects.all().aggregate(Avg('price'))
# res1 = models.Book.objects.all().aggregate(Max('price'))
# res2 = models.Book.objects.all().aggregate(Min('price'))
# res3 = models.Book.objects.all().aggregate(Sum('price'))
# res4 = models.Book.objects.all().aggregate(Count('title'))
# res5 = models.Book.objects.all().aggregate(Avg('price'),Max('price'),Min('price'),Sum('price'),Count('title'))
# print(res5)
"""
关键字:annotate
"""
# 1.统计每一本书的作者个数
# res = models.Book.objects.annotate(author_num = Count('authors')).values('author_num')
# print(res)
# 2.统计出每个出版社卖的最便宜的书的价格
# res = models.Publish.objects.annotate(price_min=Min('book__price')).values('price_min')
# print(res)
# 3.统计不止一个作者的图书
"""
1.统计每本书对应的作者个数
2.基于上面的结果 筛选出作者个数大于1 的
"""
#res=models.Book.objects.annotate(author_num=Count('authors')).filter(author_num__gt=1).values('author_num')
# print(res)
# 4.查询各个作者出的书的总价格
# res = models.Author.objects.annotate(sum_price=Sum('book__price')).values('sum_price')
# print(res)
我们之前在查询数据库的时候条件都是我们自己手写的
但是现在出现了条件是从数据库里面获取的
"""
"""
from django.db.models import F,Q
# 1.查询出卖出数大于库存数的书籍
# res = models.Book.objects.filter(maichu__gt=F('kucun'))
# print(res)
# 2.将所有的书的价格 全部提高100块
# models.Book.objects.update(price=F('price') + 100)
# 3.了解 尝试着将所有的书的名字后面都加上 爆款
# Q查询进阶用法 用Q产生对象 然后再使用
# q = Q()
# q.connector = 'or'
# q.children.append(('title__icontains','p'))
# # q.children.append(('kucun',666))
# res = models.Book.objects.filter(q)
# print(res)
"""
字符串的左边 跟你的变量名条件书写一模一样
"""
# 惰性查询
# res = models.Book.objects.all()
# res = models.Book.objects.values('title')
# res = models.Book.objects.only('title')
# for r in res:
# # print(r.title)
# print(r.price)
"""
only会将括号内的字段对应的值 直接封装到返回给你的对象中 点该字段 不需要再走数据库
一旦你点了不是括号内的字段 就会频繁的去走数据库查询
"""
# res = models.Book.objects.defer('title') # defer和only互为反关系
# for r in res:
# print(r.title)
"""
defer会将括号内的字段排除之外将其他字段对应的值 直接封装到返回给你的对象中 点该其他字段 不需要再走数据库
一旦你点了括号内的字段 就会频繁的去走数据库查询
"""
"""
"""
# 1.查询书籍名称是python入门或者价格是544.44的书
# res = models.Book.objects.filter(title='python入门',price=544.44)
# res = models.Book.objects.filter(Q(title='python入门'),Q(price=544.44)) # 逗号就是and
# res = models.Book.objects.filter(Q(title='python入门')|Q(kucun=666)) # 用来Q之后 就能够支持|表示或
# res = models.Book.objects.filter(~Q(title='python入门')|Q(kucun=666)) # esc下面那个键 波浪号 表示非
# print(res)
AutoField(primary_key=True)
CharField(max_length=32) varchar(32)
IntegerField() int
BigIntegerField() long
DateField()
auto_now:每次修改数据的时候 都会更新该字段
auto_now_add:只在创建数据的时候 才会自动将创建时间添加 后续不会再自动修改了
DecimalField()
BooleanField(Field)
- 布尔值类型
该字段在存储数据的时候 你只需要传布尔值即可
对应到数据库中 会变成0/1
TextField(Field)
- 文本类型
存大段文本
EmailField(CharField) varchar(...)
FileField(Field)
- 字符串,路径保存在数据库,文件上传到指定目录
- 参数:
upload_to = "" 上传文件的保存路径
storage = None 存储组件,默认django.core.files.storage.FileSystemStorage
DecimalField(Field)
- 10进制小数
- 参数:
max_digits,小数总长度
decimal_places,小数位长度
# 自定义char类型字段
class MyCharField(models.Field):
def __init__(self,max_length,*args,**kwargs):
self.max_length = max_length
super().__init__(max_length=max_length,*args,**kwargs)
def db_type(self, connection):
return 'char(%s)'%self.max_length
如果你使用的是django2.X版本 你在建数据库表关系的时候
你需要手动指定两个参数
(你要手动告诉django 级联更新 级联删除 是否建外键约束)
on_delete
db_constraint
# res = models.Book.objects.all()
# res = models.Book.objects.values('title')
# res = models.Book.objects.only('title')
# for r in res:
# # print(r.title)
# print(r.price)
"""
only会将括号内的字段对应的值 直接封装到返回给你的对象中 点该字段 不需要再走数据库
一旦你点了不是括号内的字段 就会频繁的去走数据库查询
"""
# res = models.Book.objects.defer('title') # defer和only互为反关系
# for r in res:
# print(r.title)
"""
defer会将括号内的字段排除之外将其他字段对应的值 直接封装到返回给你的对象中 点该其他字段 不需要再走数据库
一旦你点了括号内的字段 就会频繁的去走数据库查询
"""
# select_related
# res = models.Book.objects.select_related('publish')
# res1 = models.Author.objects.select_related('author_detail')
# # res = models.Book.objects.all()
# for r in res1:
# print(r.author_detail)
# print(r.author_detail.phone)
# print(r.author_detail.addr)
"""
select_related 会自动帮你做连表操作 然后将连表之后的数据全部查询出来封装给对象
select_related括号内只能放外键字段
并且多对多字段不能放
如果括号内外键字段所关联的表中还有外键字段 还可以继续连表
select_related(外键字段__外键字段__外键字段...)
"""
# prefetch_related
res = models.Book.objects.prefetch_related('publish')
# print(res)
for r in res:
print(r.publish.name)
"""
prefetch_related 看似连表操作 其实是类似于子查询
prefetch_related括号内只能放外键字段
并且多对多字段不能放
如果括号内外键字段所关联的表中还有外键字段 还可以继续连表
select_related(外键字段__外键字段__外键字段...)
"""
"""
第一个 内部自动连表 消耗的资源就在连表上 但是走数据库的次数较少
第二个 内部不做连表 消耗的资源就在查询次数上 但是给用户的感觉跟连表操作一样
"""
# django中如何开启事务
from django.db import transaction
with transaction.atomic():
# 在该代码块中所写的orm语句 同属于一个事务
# 缩进出来之后自动结束
#事务的特性: ACID
原子性
一致性
隔离性
持久性
Django知识整理三(django中orm简介,FBV与CBV, django settings源码分析,模板层相关知识,模型层相关知识)
原文:https://www.cnblogs.com/asyouwish/p/11762704.html