Django框架05 /orm单表操作
Posted liubing8
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Django框架05 /orm单表操作相关的知识,希望对你有一定的参考价值。
目录
Django框架05 /orm单表操作
昨日内容回顾
模板相关
模板继承(母版继承)
1. 创建一个xx.html页面(作为母版,其他页面来继承它使用)
2. 在母版中定义block块(可以定义多个,整个页面任意位置)
{% block content %} <!-- 预留的钩子,共其他需要继承它的html,自定义自己的内容 -->
{% endblock %}
3 其他页面继承写法
{% extends 'base.html' %} 必须放在页面开头
4 页面中写和母版中名字相同的block块,从而来显示自定义的内容
{% block content %} <!-- 预留的钩子,共其他需要继承它的html,自定义自己的内容 -->
{{ block.super }} #这是显示继承的母版中的content这个快中的内容
这是xx1
{% endblock %}
组件
1 创建html页面,里面写上自己封装的组件内容,xx.html
2 新的html页面使用这个组件
{% include 'xx.html' %}
自定义标签和过滤器
1 在应用下创建一个叫做templatetags的文件夹(名称不能改),在里面创建一个py文件,例如xx.py
2 在xx.py文件中引用django提供的template类,写法
from django import template
register = template.Library() #register变量名称不能改
定义过滤器
@register.filter 参数至多两个
def xx(v1,v2):
return xxx
使用:
{% load xx %}
{{ name|xx:'oo' }}
# 自定义标签 没有参数个数限制
@register.simple_tag
def huxtag(n1,n2): #冯强xx '牛欢喜'
'''
:param n1: 变量的值 管道前面的
:param n2: 传的参数 管道后面的,如果不需要传参,就不要添加这个参数
:return:
'''
return n1+n2
# inclusion_tag 返回html片段的标签
@register.inclusion_tag('result.html')
def res(n1): #n1 : ['aa','bb','cc']
return {'li':n1 }
使用:
{% res a %}
静态文件配置
1 项目目录下创建一个文件夹,例如名为jingtaiwenjianjia,将所有静态文件放到这个文件夹中
2 settings配置文件中进行下面的配置
# 静态文件相关配置
STATIC_URL = '/abc/' #静态文件路径别名
STATICFILES_DIRS = [
os.path.join(BASE_DIR, 'jingtaiwenjianjia'),
]
3 引入<link rel="stylesheet" href="/abc/css/index.css">
url别名和反向解析
写法
url(r'^index2/', views.index,name='index'),
url(r'^index2/(d+)/', views.index,name='index'),
反向解析
后端: from django.urls import reverse
reverse('别名') 例如:reverse('index') -- /index2/
带参数的反向解析:reverse('index',args=(10,11,)) -- /index2/10/
html: {% url '别名' %} -- 例如:{% url 'index' %} -- /index2/
带参数的反向解析:{% url '别名' 参数1 参数2 %} 例如:{% url 'index' 10 %} -- /index2/10/ <a href='/index2/10/'>hhh</a>
url命名空间
路由分发 include
1 在每个app下创建urls.py文件,写上自己app的路径
2 在项目目录下的urls.py文件中做一下路径分发,看下面内容
from django.conf.urls import url,include
from django.contrib import admin
urlpatterns = [
# url(r'^admin/', admin.site.urls),
url(r'^app01/', include('app01.urls')),#app01/home/
url(r'^app02/', include('app02.urls')),
]
命名空间namespace
from django.conf.urls import url,include
from django.contrib import admin
urlpatterns = [
# url(r'^admin/', admin.site.urls),
url(r'^app01/', include('app01.urls',namespace='app01')),#app01/home/
url(r'^app02/', include('app02.urls',namespace='app02')),
]
使用:
后端:reverse('命名空间名称:别名') -- reverse('app01:home')
hmtl:{% url '命名空间名称:别名' %} -- {% url 'app01:home' %}
今日内容
orm单表操作 对象关系映射(object relational mapping)
orm语句 -- sql -- 调用pymysql客户端发送sql -- mysql服务端接收到指令并执行
1.orm介绍
django 连接mysql
1 settings配置文件中
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'orm02',
'USER':'root',
'PASSWORD':'123',
'HOST':'127.0.0.1',
'PORT':3306,
}
}
2 项目文件夹下的init文件中写上下面内容,用pymysql替换mysqldb
import pymysql
pymysql.install_as_MySQLdb()
3 models文件中创建一个类
# class UserInfo(models.Model):
# id = models.AutoField(primary_key=True)
# name = models.CharField(max_length=10)
# bday = models.DateField()
# checked = models.BooleanField()
#BooleanField()不能设置空值
4 执行数据库同步指令,添加字段的时候别忘了,该字段不能为空,所有要么给默认值,要么设置它允许为空 null=True
django连操作数据库默认是不能为空的
# python manage.py makemigrations
# python manage.py migrate
5 创建记录(实例一个对象,调用save方法)
from app01 import models
def query(request):
# 创建一条记录,增
new_obj = models.UserInfo(
id=2,
name='二狗',
bday='2019-09-27',
checked=1,
)
new_obj.save() #翻译成sql语句,然后调用pymysql,发送给服务端 insert into app01_userinfo values(2,'二狗','2019-09-27',1)
return HttpResponse('xxx')
2.增:
方式1:
new_obj = models.UserInfo(
id=2,
name='二狗',
bday='2019-09-27',
checked=1,
)
new_obj.save()
方式2:
# ret 是创建的新的记录的model对象(重点)
ret = models.UserInfo.objects.create(
name='大狗',
bday='2019-08-07',
checked=0
)
print(ret) #UserInfo object 大狗
print(ret.name) #UserInfo object
print(ret.bday) #UserInfo object
3.时间问题
models.UserInfo.objects.create(
name='大狗2',
bday=current_date,
# now=current_date, 直接插入时间没有时区问题
checked=0
)
但是如果让这个字段自动来插入时间,就会有时区的问题,auto_now_add创建记录时自动添加当前创建记录时的时间,存在时区问题
now = models.DateTimeField(auto_now_add=True,null=True)
解决方法:
settings配置文件中将USE_TZ的值改为False
# USE_TZ = True
USE_TZ = False # 告诉mysql存储时间时按照当地时间来寸,不要用utc时间
使用pycharm的数据库客户端的时候,时区问题要注意
4.删
简单查询:filter() -- 结果是queryset类型的数据里面是一个个的model对象,类似于列表
models.UserInfo.objects.filter(id=7).delete() #queryset对象调用
models.UserInfo.objects.filter(id=7)[0].delete() #model对象调用
5.改
方式1:update
# models.UserInfo.objects.filter(id=2).update(
# name='peng',
# checked = 0,
#
# )
# 错误示例,model对象不能调用update方法
# models.UserInfo.objects.filter(id=2)[0].update(
# name='peng+2',
# # checked = 0,
# )
方式2
ret = models.UserInfo.objects.filter(id=2)[0]
ret.name = 'peng+2'
ret.checked = 1
ret.save()
更新时的auto_now参数
# 更新记录时,自动更新时间,创建新纪录时也会帮你自动添加创建时的时间,但是在更新时只有使用save方法的方式2的形式更新才能自动更新时间,有缺陷,放弃
now2 = models.DateTimeField(auto_now=True,null=True)
6.批量插入 -- bulk_create
book_list = []
for i in range(10):
bk_obj = models.Book(
name='peng%s'%i,
addr='北京%s'%i
)
book_list.append(bk_obj)
models.Book.objects.bulk_create(book_list) #批量插入,速度快
7.查询api
all()
查询所有结果,结果是queryset类型
ret = models.Books.objects.all()
print(ret)
< QuerySet[ < Books: Books object >, < Books: Books object >, < Books: Books object >] >
filter(**kwargs) -- 条件查询
包含与所给筛选条件相匹配的对象,结果也是queryset类型
查询条件不能匹配到数据时,不会报错,返回一个空的queryset,<QuerySet []>,
如果没有写查询条件会获取所有数据,queryset类型的数据还能够继续调用fitler方法
ret = models.Books.objects.filter(name='linux')
print(ret)
<QuerySet [<Books: Books object>, <Books: Books object>]>
#多条件查询用,隔开--是and的关系
ret = models.Books.objects.filter(name='linux',price=113)
print(ret)
<QuerySet [<Books: Books object>, <Books: Books object>]>
get(**kwargs)
返回与所给筛选条件相匹配的对象,不是queryset类型,是model对象,返回结果有且只有一个,如果符合筛选条件的对象超过一个或者没有都会抛出错误。捕获异常try。 Book.objects.get(id=1)
报错:
1. 查不到数据会报错 :Book matching query does not exist.
2. 超过一个就报错 :returned more than one Book -- it returned 13!
ret = models.Books.objects.get(id=5)
print(ret)
Books object
exclude(**kwargs) -- 排除
排除的意思,它包含了与所给筛选条件不匹配的对象,没有不等于的操作,用这个exclude,返回值是queryset类型
model对象和queryset对象都可以调用
Book.objects.exclude(id=6),返回id不等于6的所有的对象,Book.objects.all().exclude(id=6),在queryset基础上调用
model对象调用:
ret = models.Books.objects.exclude(name='python')
print(ret)
<QuerySet [<Books: Books object>, <Books: Books object>, <Books: Books object>]>
queryset对象调用:
ret = models.Books.objects.all().exclude(name='python')
print(ret)
<QuerySet [<Books: Books object>, <Books: Books object>, <Books: Books object>]>
order_by(*field) -- 排序
queryset类型的数据来调用,对查询结果排序,默认是按照id来升序排列的,返回值还是queryset类型
升序排序:
models.Book.objects.all().order_by('price') #默认是按照price升序排列
降序排序:
models.Book.objects.all().order_by('-price') #按照字段降序排列,就写个负号就行了
多条件排序:
models.Book.objects.all().order_by('price','id')是多条件排序,按照price进行升序,price相同的数据,按照id进行升序
ret = models.Books.objects.all().order_by('price')
print(ret)
<QuerySet [<Books: Books object>, <Books: Books object>, <Books: Books object>, <Books: Books object>, <Books: Books object>, <Books: Books object>]>
reverse() -- 反转
queryset类型的数据来调用,返回值还是queryset类型,对查询结果反向排序,必须是在排序之后才能使用
count() -- 计数、统计返回结果的数量
queryset类型的数据来调用,返回数据库中匹配查询(QuerySet)的对象数量。
first()
queryset类型的数据来调用,得到的都是model对象,返回第一条记录 Book.objects.all()[0] = Book.objects.all().first(),得到的都是model对象,不是queryset
last()
queryset类型的数据来调用,返回最后一条记录
exists() -- 判断返回结果是否有数据
queryset类型的数据来调用,如果QuerySet包含数据,就返回True,否则返回False,效率高
models.Book.objects.all().exists()
#翻译成的sql是SELECT (1) AS `a` FROM `app01_book` LIMIT 1,
就是通过limit 1,取一条来看看是不是有数据
ret = models.Books.objects.all().exists()
print(ret)
True
#exists() 括号内不能放数据
values(*field)
1.queryset类型的数据来调用,返回一个ValueQuerySet——一个特殊的QuerySet,运行后得到的并不是一系列
2.model的实例化对象来调用,而是一个可迭代的字典序列,只要是返回的queryset类型,就可以继续链式调用queryset类型的其他的查找方法,其他方法也是一样的。
#调用values或者values_list的是objects控制器,那么返回所有数据
ret = models.Books.objects.all().values('name')
print(ret)
<QuerySet [{'name': 'python'}, {'name': 'python'}, {'name': 'linux'}, {'name': 'python'}, {'name': 'linux'}, {'name': 'Go'}]>
ret = models.Books.objects.values('name')
print(ret)
<QuerySet [{'name': 'python'}, {'name': 'python'}, {'name': 'linux'}, {'name': 'python'}, {'name': 'linux'}, {'name': 'Go'}]>
#调用values或者values_list的对象是objects控制器,那么返回所有数据
values_list(*field)
它与values()非常相似,它返回的是一个元组序列,values返回的是一个字典序列
ret = models.Books.objects.all().values_list('name')
print(ret)
<QuerySet [('python',), ('python',), ('linux',), ('python',), ('linux',), ('Go',)]>
distinct() -- 去重、配置values和values_list来使用
distinct()括号里不能加去重的条件
values和values_list得到的queryset类型的数据来调用,从返回结果中剔除重复纪录
ret = models.Books.objects.values('name').distinct()
print(ret)
<QuerySet [{'name': 'python'}, {'name': 'linux'}, {'name': 'Go'}]>
错误示例:
ret = models.Books.objects.all().distinct()
print(ret)
<QuerySet [<Books: python>, <Books: python>, <Books: linux>, <Books: python>, <Books: linux>, <Books: Go>]>
注意:
不在values()、values_list()后面使用没有意义,因为要是所有的内容全相同才会去重
8.基于双下划线的模糊查询 -- filter双下划线查询
1.Book.objects.filter(price__in=[100,200,300]) #price值等于这三个里面的任意一个的对象
2.Book.objects.filter(price__gt=100) #大于
3.price__gte=100,大于等于,别写price>100,这种参数不支持
2.Book.objects.filter(price__lt=100) #小于
3.price__lte=100,小于等于,别写price>100,这种参数不支持
5.Book.objects.filter(price__range=[100,200]) #sql的between and,大于等于100,小于等于200
6.Book.objects.filter(title__contains="python") #title值中包含python的
7.Book.objects.filter(title__icontains="python") #不区分大小写
8.Book.objects.filter(title__startswith="py") #以什么开头,
9.Book.objects.filter(title__istartswith="py") #不区分大小写
#日期时间
10.Book.objects.filter(pub_date='2012-9-12')
11.Book.objects.filter(pub_date__year=2012)
12.Book.objects.filter(pub_date__ year_ gt='2018') #大于2018年的、2018数字类型也可以
13.Book.objects.filter(pub_date__year='2019' ,pub_ date__ month='8') #某年某月
14.Book.objects.filter(pub_date__ year='2019' ,pub_date__month='8',pub_date__day='01') #某年某月某日
#找字段数据为空的双下滑线
15.models.Book.objects.filter(publish_date__isnull=True) #这个字段值为空的那些数据
9.总结
总结1
1.新增字段(注意设置可以为空或者设置默认值)
2.UTC时间格式格林尼治时间
3.model对象不能调用update方法
orm1 > settings.py
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'orm1',
'HOST':'127.0.0.1',
'PORT':3306,
'USER':'root',
'PASSWORD':'123'
}
}
# USE_TZ = True
#告诉mysql默认使用当地时间
USE_TZ = False
#不是跨时区的应用,不需要考虑时区问题,就将这个值改为False,mysql是对时区不敏感,django往mysql里面出数据的时候,如果这里的值为True,那么将让mysql强制使用UTC时间,那么我们存储进入的时间,当你查询的时候,你就会发现,时间晚了8小时,也就是说你存时间的时候被改为了UTC时间,本地是东八区,比UTC时间多8小时
orm1 > __init__.py
import pymysql
pymysql.install_as_MySQLdb()
models.py
from django.db import models
# Create your models here.
class Userinfo(models.Model):
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=16)
register_time = models.DateField(null=True)
#auto_now_add=True 修改记录不会改变
update_time = models.DateTimeField(auto_now=True,null=True)
#auto_now=True, 修改记录用方式一/update不会改变、用方式二/ret.save()会更新
checked = models.BooleanField(default=0)
def __str__(self):
return self.name
views.py
from django.shortcuts import render,HttpResponse
# Create your views here.
from app01 import models
from datetime import datetime
# def query(request):
#创建记录
#方式一
# current_time = datetime.now()
# new_obj = models.Userinfo(
# id = 1,
# name = 'peng'
# )
# new_obj.save()
#方式二
# ret =models.Userinfo.objects.create(
# name='wang',
# register_time='2019-8-8',
# update_time='2019-8-10 12:12:12',
# checked=1,
#
# )
# ret = models.Userinfo.objects.filter(name='wang')
# print(ret)
#返回一个
#删除
# ret = models.Userinfo.objects.filter(id=7)[0].delete()
# print(ret)
#将符合条件的第一条记录删除
# ret = models.Userinfo.objects.filter(id=7).delete()
# print(ret)
#将符合条件的所有记录删除
#注意:filter搜索出来的是queryset类型的列表:queryset<[对象1,对象2,对象3]>
#修改
#方式一
# models.Userinfo.objects.filter(id=1).update(
# name='peng',
# checked=1,
# register_time = '2019-1-1',
# update_time = '2020-06-03',
# )
# 方式二
# ret = models.Userinfo.objects.filter(id=1)[0]
# ret.name='zhao'
# ret.save()
# return HttpResponse('完啦')
#注意:model对象不能调用update()方法
总结2
1.带有a标签属性的button按钮
<td>
<a href="" class="btn btn-warning">编辑</a>
<a href="" class="btn btn-danger"> 删除</a>
</td>
2.number类型的input标签
<div class="form-group">
<label for="price"> 价格</label>
<input type="number" class="form-control" id="price" name="price">
</div>
3.date类型的input标签
<div class="form-group">
<label for="publish_ datel">出版8期</label>
<input type="date" class="form-control" id="publish_ date" placeholder="Password">
</div>
4.重定向路径已经取别名后,重定向后面写别名就行
return redirect('showbooks')
5.**在接收到get或者post提交数据后的应用
if request.method == 'POST':
print(request. POST)
# title = request.POST.get( 'title')
# price = request. POST.get( 'price')
# publish_ date = request. POST. get( 'publish_ date')
# publish = request. POST.get( 'publish')
data = request.POST.dict() #将querydict类型转换成dict类型
models.Book.objects.create(
# title=title,
# price=price,
# publish_ date=publish_ date,
# publish=publish
**data
#{'title': ['asdf '],'price':. ['212.'], 'publish date': ['2019-09-12'],. 'publish': ['asdf ']}
return redirect('showbooks')
dic = {"key":1,"key1":34}
**dic --- "key"=1,"key1"=34
6.pk代替id
方式一:别名的反向解析、id字段可以用pk来代替(primary_key)
<td>
<a href="" class=btn btn-warning">编辑</a>
<a href="{% url 'delete_ book' book:pk %}" class="btn btn-dangerl>删除</a>
</td>
方式二:
<a href="/remove_books/{{ i.id }}">
<button type="submit" class="btn btn-danger">
<span class="glyphicon glyphicon-remove" aria-hidden="true"></span>删除
</button>
</a>
以上是关于Django框架05 /orm单表操作的主要内容,如果未能解决你的问题,请参考以下文章