常规数据库操作:
基础命令
show databases;
查看当前有哪些数据库
select database();
查看当前数据库的名字
use mysql;
切换数据库为mysql
show tables;
查看当前数据库中有哪些表
select * from user\G;
查看user表中所有的数据
创建数据库
语法:create database 数据库名字;
数据的新增
字符类型必须加单引号,日期类型也是
数字类型数据直接使用
列的数据类型和值得数据类型必须一致
d1.向表中所有列新增数据
语法:insert into 表 values (值1,值2...);
CREATE TABLE emp(
ename CHAR(10),
age INT,
birth DATE
);
INSERT INTO emp VALUES('neimaer',20,'2000-09-08');
d2.向表中指定列新增数据
语法:insert into 表(列1,列2...) values(值1,值2...);
向emp表中新增数据,员工名字为outman,age为18
insert into emp(ename,age) values('outman',18);
d3.补充
新增多条数据
INSERT INTO emp(ename) VALUES('a'),('b'),('c');
e.数据的修改(更新)
字符类型必须加单引号,日期类型也是
数字类型数据直接使用
列的数据类型和值得数据类型必须一致
语法:update 表 set 列=值 [where 条件];
修改满足条件的数据
修改emp表中名字为outman的年龄修改为88
update emp set age=88 where ename='outman';
修改整个列的数据
如果不加where条件,默认修改的是整个列的值
修改emp表中所有年龄为0
update emp set age=0;
f.数据的删除
f1.delete和truncate区别
delete DML(数据库操作语言) 可以删除指定数据 删除数据可以找回
truncate DDL(数据库定义语言) 只能删除所有数据 删除数据无法找回
f2.delete
语法:delete from 表 [where 条件];
删除emp表中名字为outman的所有数据
delete from emp where ename='outman';
删除emp表中所有数据
delete from emp;
f3.truncate
语法:truncate table 表名;
删除emp表中所有数据
truncate table emp;
g.表结构的删除
语法:drop table 表名;
删除emp表结构
drop table emp;
补充:
删除表结构中的某个列:alter table 表 drop column 列名
ALTER TABLE txl DROP COLUMN tel;
修改表结构中的某个列:change
alter table 表 modify 列 数据类型 约束
ALTER TABLE txl MODIFY NAME INT;
表结构中新增一列
alter table 表 add 列 数据类型
ALTER TABLE txl ADD tel CHAR(20);
数据的查询
h1.分类
简单查询
多表查询
子查询
分组查询
h2.简单查询
查询时候可以查询指定行,指定列,指定行的列
语法:select 列 from 表 [where 条件];
查询演员表中名字是NICK的所有信息
SELECT * FROM actor WHERE first_name='NICK';
查询演员表中所有人的姓氏和名字
select last_name,first_name from actor;
查询演员表中所有名字是NICK的人的姓氏
select last_name from actor where first_name='NICK';
h3.where条件
1>比较
>
<
=
>=
<=
!=
<> 不等于
查询演员表中名字不是NICK的所有数据
select * from actor where first_name !='NICK';
查询演员表中演员id小于20的所有信息
select * from actor where actor_id<20;
2>逻辑
and 同时满足条件
or 满足一个条件即可
not 不满足条件
查询演员表中名字是NICK的并且演员id小于20的所有信息
select * from actor where first_name='NICK' and actor_id<20;
查询演员表中名字是NICK或者SMITH的所有信息
select * from actor where first_name='NICK' or first_name='SMITH';
3>空置(null)
空没有任何数据类型,没有任何值,不能用于比较和运算
查询时候使用is null或者is not null
查询演员表中名字为空的所有信息
select * from actor where first_name is null;
4>in
在...里面(或的关系)
查询演员表中名字是NICK或者SMITH的所有信息
select * from actor where first_name in ('NICK','SMITH');
5>模糊查询
通常是和字符类型一起使用,当信息不完整时候使用
like
_ 一个字符
% 任意个字符
查询演员表中名字是N开头的所有信息
select * from actor where first_name like 'N%';
查询演员表中名字是K结尾的所有信息
select * from actor where first_name like '%K';
查询演员表中名字是4个字符的所有信息
select * from actor where first_name like '____';
SELECT * FROM actor WHERE first_name LIKE '%C%';
6>区间查询
between ... and ...包括两个端点
查询演员表中演员id范围在20和30之间的所有信息
select * from actor where actor_id >= 20 and actor_id<=30;
select * from actor where actor_id between 20 and 30;
语法:
create table 表(
列1 数据类型 [constraint 约束名] primary key,
列2 数据类型 unique,
列3 数据类型 not null,
列4 数据类型 check(列4的条件),
列5 数据类型 references 被参考表(被参考列)
);
create table test(
id int primary key,
name char(10) unique,
age int not null,
sex char(10) check(sex='male' or sex='famale')
);
1.笛卡尔积(集)
两张表不做任何关联所产生的数据
select * from city;
select * from country;
select * from city,country;
笛卡尔积会使数据量成倍增加,产生很多无效数据,为了避免此类型情况,使用内联、左联、右联查询
左联:
语法: select 列 from 表1 left join 表2 on 表1.列=表2.列;
左联出来的结果:内联查询结果+左表中有,右表中没有,右表中对应位置为空(左表中所有数据都有)
右联:
语法:select 列 from 表1 right join 表2 on 表1.列=表2.列;(右表中所有数据都有)
SELECT * FROM a LEFT JOIN b ON a.id=b.it;
SELECT * FROM a RIGHT JOIN b ON a.id=b.it;
2.内联查询
关联列判断方法
a.列名相同
b.作用相同
c.主外键关系
语法:
select 列 from 表1 ,表2 where 表1.列=表2.列;
select 列 from 表1 inner join 表2 on 表1.列=表2.列;
查询city名称为Acua的国家名称
a.分析列
城市名称
国家名称
b.分析表
城市名称 city
国家名称 country
c.关联
select * from city,country
where city.country_id=country.country_id;
d.过滤
select country from city,country
where city.country_id=country.country_id
and city='Acua';
查询city名称为Acua的国家名称,country_id
c.关联
select * from city c,country c1
where c.country_id=c1.country_id;
d.过滤
select c1.country,c.country_id from city c,country c1
where c.country_id=c1.country_id
and c.city='Acua';
分组查询
1.分组
按照某种属性进行分类
2.分组函数(聚合)
max 最大
min 最小
avg 平均
sum 求和
count 计数
分组函数通常是和分组一起使用,也可以单独使用
查询付款表中最高付款金额,最低付款金额,平均付款金额
select max(amount),min(amount),avg(amount) from payment;
3.分组查询
语法:select 列 from 表
[where 条件]
group by 分组条件
[having 分组后过滤条件]
分组条件判断
每后面跟的就是分组条件
select后面from前面的列如果要显示必须是分组条件
查询每个国家有多少个城市?要求显示国家名字和城市数量
a.分析列
国家名字
城市名字
b.分析表
国家 country
城市 city
c.关联
select * from city c,country co
where c.country_id=co.country_id;
d.过滤
select co.country,count(c.city) from city c,country co
where c.country_id=co.country_id
group by co.country;
4.分组后过滤
先分组后过滤
where 分组前过滤 不能直接跟分组函数
having 分组后过滤 后面可以直接跟分组函数
查询哪些国家的城市超过20个?
select co.country,count(c.city) from city c,country co
where c.country_id=co.country_id
group by co.country
having count(c.city)>20;
查询客户表中每种名字有多少人?
select u.name,count(u.name)
from kehu k, user u
where kehu.name = user.name
group by u.name
查询每个城市有多少个地址?
===============================================================
SQL:结构化查询语言
DDL:数据库定义语句 create alter drop truncate
DML:数据库操作语句 insert delete update
DCL:数据库控制语句 grant revoke
DQL:数据库查询语句 select
子查询(嵌套)
一条SQL语句的执行依赖于另外一条SQL语句的执行结果
查询国家名称是China的城市有哪些?
select city from city where country_id=(select country_id from country where country='china')
a.列
国家
城市
b.表
国家 country
城市 city
c.关联的列
country_id
d.拆分需求
d1.查询国家表中国家名称是China的country_id
select country_id from country where country='China';
d2.查询城市表中country_id为上面查询出来结果的城市名称
select city from city where country_id=(select country_id from country where country='China');
1.排序
语法:
select 列 from 表
where 条件
group by 分组条件
having 分组后过滤条件
order by 排序条件;
a.顺序
从小到大
order by 列
order by 列 asc
查询actor表中所有数据,按照actor_id从小到大进行排列
select * from actor order by actor_id;
b.逆序
从大到小
order by 列 desc
查询actor表中所有数据,按照actor_id从大到小进行排列
select * from actor order by actor_id desc;
补充:双排序,多排序
SELECT * FROM city ORDER BY country_id,city_id DESC;
2.limit
limit 分页查询
查询actor 表中前3条数据
SELECT * FROM actor LIMIT 3
查询actor表中第4到第8条数据
SELECT * FROM actor LIMIT 3,5
学会排序,灵活运用很关键,可顺序取前十,倒序取倒十
笔试题
1.insert into student values('小明','005');
2.update exam set score=85 where code=(select code from student where name='李四') and subject='语文';
3.select subject,avg(score) from exam group by subject
4.select s.name,s.code,a.score from student s right join exam a
on s.code=a.code order by s.code,a.subject;
5.
a>查询每个科目最高分
select max(score),subject from exam group by subject;
b>查询每门成绩最高的学生id
select a.code from exam a,(select max(score) s1,subject from exam group by subject) b
where a.subject=b.suject
and a.score=b.s1
c>select s.name,s.code,a.suject,a.score from student s,exam a
where s.code=a.code
and s.code in (
select a.code from exam a,(select max(score) s1,subject from exam group by subject) b
where a.subject=b.suject
and a.score=b.s1
)
********************************************************************************************************
1.mongodb
a.基础
数据分为2部分:软件、数据
数据库是由集合组成
集合是由文档组成
mysql mongodb
数据库 数据库
表 集合
数据 文档
b.mongodb的服务
mongod mongodb的主服务
mongo mongodb的客户端服务
27107 mongodb的端口
b1.服务的检查
win+r--cmd--tasklist | find "mongod"
b2.端口的检查
win+r--cmd--netstat -an | find "27017"
c.mongodb的登陆
c1.登陆命令
mongo
登陆本地数据库
mongo 127.0.0.1
登陆ip为127.0.0.1的数据库
mongo 127.0.0.1:27017/admin
登陆ip为127.0.0.1端口为27107的admin数据库
c2.登陆方式
1>进入到命令所在位置
2>设置环境变量
d.mongodb的基础命令
show databases
show dbs
查看当前有哪些数据库
db
查看当前数据库的名字
use local
数据库切换为local
show tables
show collections
查看当前数据库有哪些集合
db.startup_log.find()
查看startup_log集合中所有文档
e.CURD(增删改查)
e1.文档新增
db.xiyouji.insert({name:'5kong',age:18})
e2.文档查询
db.xiyouji.find({age:18})
e3.文档修改
db.xiyouji.update({age:18},{$set:{name:'tangsir'}})
e4.文档删除
db.xiyouji.remove({name:'8jie'})
f.文档新增
f1.新增普通文档
db.xiyouji.insert({name:'tai2'})
f2.新增文档指定_id
db.xiyouji.insert({_id:0,name:'kingkong'})
f3.新增内嵌文档
db.xiyouji.insert({name:'skong',jingli:{kill:500,hit:1}})
f4.新增多个文档
db.xiyouji.insert([{name:'tieshan'},{name:'niumo'}])
g.文档的查询
g1.查询所有文档
db.xiyouji.find()
g2.查询指定文档
db.xiyouji.find({age:{$exists:1}})
g3.查询指定文档的指定属性
db.xiyouji.find({name:"5kong"},{_id:0,name:1})
g4.查询表达式
1>比较
> >
>e >=
< <
<e <=
&ne !=
db.xiyouji.find({age:{>e:20}})
db.xiyouji.find({age:{&ne:20}})
2 > 关系
&and 同时满足
db.xiyouji.find({&and:[{age:{<e:20}},{name:'yudi'}]},{_id:0})
&or 满足一个即可
db.xiyouji.find({&or:[{age:{<e:20}},{name:'yudi'}]})
3 > 存在性
$exists 属性存在与否
db.xiyouji.find({age:{$exists:1}})
h.文档的更新
h1.替换全部文档
db.xiyouji.update({name:'tangsir'}, {age:666})
h2.修改指定文档($set)
db.xiyouji.update({name:'tangsir'}, {$set:{age:100}})
h3.删除属性($unset)
db.xiyouji.update({name:'tangsir'}, {$unset:{age:100}})
h4.增长列
db.xiyouji.update({name:'tangsir'}, {$inc:{age:100}})(age + 100)
i.文档的删除
i1.删除指定文档
db.xiyouji.remove({age:{$exists:1}})
i2.删除所有文档
db.xiyouji.remove()
**************************************************************************************************************
redis详解:http://www.cnblogs.com/yuhangwang/p/5817930.html
第二链接:https://blog.csdn.net/liqingtx/article/details/60330555
/*************************************************************************************************************
网站参考:https://www.cnblogs.com/slfenng/p/7880734.html
python——Django(ORM连表操作)https://www.cnblogs.com/Eva-J/p/5373414.html
python——Django(ORM连表操作)进阶 https://www.cnblogs.com/happy-king/p/8338404.html
用 ./manage.py shell 打开交互式环境,在其中为模型添加一条记录,时间使用当前时间,
当前时间通过django.utils.timezone.now() 来获取
from app1.models import Log
from django.utils import timezone
log = Log(time=timezone.now())
log.save()
Django模型的部分API使用范例
# 创建新记录
>>> a = Author(name='Alice', age=18)
>>> a.save()
>>> a = Author.object.create(name='Alice', age=18)
创建新记录的常见方法:
1. a = Author(name='Alice', age=18)
a.save()
2. a = Author()
a.name = 'Alice'
a.age = 18
a.save()
3. a = Author.objects.create(name='Alice', age=18)
# 删除记录
>>> e.delete()
(1, {'weblog.Entry': 1})
>>> Entry.objects.filter(pub_date__year=2005).delete()
(5, {'webapp.Entry': 5})
# 修改记录
>>> a = Author.objects.get(name='Alice', age=18)
>>> a.age += 1
>>> a.save()
>>> Entry.objects.filter(pub_date__year=2007).update(headline='Everything is the same')
# Change every Entry so that it belongs to this Blog.
>>> b = Blog.objects.get(pk=1)
>>> Entry.objects.all().update(blog=b)
# 查询记录
通过模型的Manager可以获得一个QuerySet,通过QuerySet可以查询数据库记录,每一个模型都有一个Manager,它的名字默认是objects。
>>> Entry.objects.all() # 获取模型的所有记录
>>> Entry.objects.filter(pub_date__year=2006) # 抽取符合条件的记录
>>> Entry.objects.exclude(pub_date__year=2006) # 排除符合条件的记录
串接过滤条件
>>> Entry.objects.filter(
... headline__startswith='What'
... ).exclude(
... pub_date__gte=datetime.date.today()
... ).filter(
... pub_date__gte=datetime.date(2005, 1, 30)
... )
QuerySet 的特点
1. 每一个QuerySet都是独一的,互相之间是独立的,以下q1, q2是两个独立的QuerySet
q1 = Entry.objects.filter(headline__startswith="What")
q2 = q1.exclude(pub_date__gte=datetime.date.today())
2. QuerySet是惰性的,意思是到“最后一刻”才会操作数据库,下面四条语句,到print语句时才真正操作数据库
q = Entry.objects.filter(headline__startswith="What")
q = q.filter(pub_date__lte=datetime.date.today())
q = q.exclude(body_text__icontains="food")
print(q)
获取一条记录,使用get方法,get方法支持和filter一样的表达式:
>>> one_entry = Entry.objects.get(pk=1)
如果没有匹配的记录,或者有超过一条的记录,get方法会抛出异常。
限制结果集大小
>>> Entry.objects.all()[:5] # 返回QuerySet,不操作数据库
>>> Entry.objects.all()[5:10] # 返回QuerySet,不操作数据库
>>> Entry.objects.all()[:10:2] # 用了step, 操作数据库,返回list
对结果排序
Entry.objects.filter(pub_date__year=2005).order_by('-pub_date', 'headline')
此语句先按pub_date反序排,然后按照headline顺序排。
按字段做过滤
在字段名和操作符之间用两个下划线分隔:
Book.objects.filter(name__contains='Python')
操作符的详细用法请参考
https://docs.djangoproject.com/en/1.11/ref/models/querysets/#field-lookups
<1> all(): 查询所有结果
<2> filter(**kwargs): 它包含了与所给筛选条件相匹配的对象
<3> get(**kwargs): 返回与所给筛选条件相匹配的对象,返回结果有且只有一个,
如果符合筛选条件的对象超过一个或者没有都会抛出错误。
<5> exclude(**kwargs): 它包含了与所给筛选条件不匹配的对象
<4> values(*field): 返回一个ValueQuerySet——一个特殊的QuerySet,运行后得到的并不是一系列
model的实例化对象,而是一个可迭代的字典序列
# This list contains a Blog object.
>>> Blog.objects.filter(name__startswith='Beatles')
<QuerySet [<Blog: Beatles Blog>]>
# This list contains a dictionary.
>>> Blog.objects.filter(name__startswith='Beatles').values()
<QuerySet [{'id': 1, 'name': 'Beatles Blog', 'tagline': 'All the latest Beatles news.'}]>
>>> Blog.objects.values('id', 'name')
<QuerySet [{'id': 1, 'name': 'Beatles Blog'}]>
<9> values_list(*field, flat=False):
它与values()非常相似,它返回的是一个元组序列,values返回的是一个字典序列
>>> Entry.objects.values_list('id').order_by('id')
<QuerySet[(1,), (2,), (3,), ...]>
>>> Entry.objects.values_list('id', flat=True).order_by('id')
<QuerySet [1, 2, 3, ...]>
<6> order_by(*field): 对查询结果排序
Entry.objects.filter(pub_date__year=2005).order_by('-pub_date', 'headline')
上面的结果将按pub_date降序排序,然后按 headline升序排序。前面的负号"-pub_date"表示 降序。升序是隐含的。
要随机订购,请使用"?",如下:
Entry.objects.order_by('?')
<7> reverse(): 对查询结果反向排序
要检索查询集中的“最后”五个项,您可以执行以下操作:
my_queryset.reverse()[:5]
上面的例子将首先返回最后一项,然后是倒数第二项,依此类推。
请注意,reverse()通常只应在具有QuerySet 已定义排序的情况下调用(例如,在查询定义默认排序的模型时或使用时order_by())。
如果没有为给定定义这样的排序QuerySet,则调用reverse()它没有实际效果(在调用之前排序是未定义的reverse(),
并且之后将保持未定义)。
<8> distinct(): 从返回结果中剔除重复纪录
Entry.objects.order_by('pub_date').distinct('pub_date')
<10> count(): 返回数据库中匹配查询(QuerySet)的对象数量。
Entry.objects.filter(headline__contains='Lennon').count()
<11> first(): 返回第一条记录
<12> last(): 返回最后一条记录
<13> exists(): 如果QuerySet包含数据,就返回True,否则返回False
entry = Entry.objects.get(pk=123)
if some_queryset.filter(pk=entry.pk).exists():
print("Entry contained in queryset")
<14> aggregate(): 返回通过计算的聚合值(平均值,总和等)的字典QuerySet
>>> from django.db.models import Count, Avg, Max, Min, Sum
>>> q = Blog.objects.aggregate(Count('entry'))
{'entry__count': 16}
<17> annotate(): 为调用的QuerySet中每一个对象都生成一个独立的统计值(统计方法用聚合函数)。
(1) 练习:统计每一本书的作者个数
bookList=Book.objects.annotate(authorsNum=Count('authors'))
for book_obj in bookList:
print(book_obj.title,book_obj.authorsNum)
练习:统计每一个出版社的最便宜的书
方式一:
publishList=Publish.objects.annotate(MinPrice=Min("book__price"))
for publish_obj in publishList:
print(publish_obj.name,publish_obj.MinPrice)
annotate的返回值是querySet,如果不想遍历对象,可以用上valuelist:
queryResult= Publish.objects.annotate(MinPrice=Min("book__price")).values_list("name","MinPrice")
print(queryResult)
方式二:
queryResult=Book.objects.values("publish__name").annotate(MinPrice=Min('price'))
<15> update(** kwargs): 对指定的字段执行SQL更新查询,并返回匹配的行数(如果某些行已具有新值,则可能不等于更新的行数
要关闭2010年发布的所有博客条目的注释,您可以执行以下操作:
>>> Entry.objects.filter(pub_date__year=2010).update(comments_on=False)
<16> delete(): 对其中的所有行执行SQL删除查询
例如,要删除特定博客中的所有条目:
>>> b = Blog.objects.get(pk=1)
# Delete all the entries belonging to this Blog.
>>> Entry.objects.filter(blog=b).delete()
(4, {'weblog.Entry': 2, 'weblog.Entry_authors': 2})
可用的操作符:
1. exact 精确匹配: polls.get_object(id__exact=14).
2. iexact 忽略大小写的精确匹配: polls.objects.filter(slug__iexact="foo") 匹配 foo, FOO, fOo, 等等.
3. contains 大小写敏感的内容包含测试: polls.objects.filter(question__contains="spam")
返回question 中包含 "spam" 的所有民意测验.
(仅PostgreSQL 和 MySQL支持. SQLite 的LIKE 语句不支持大小写敏感特性. 对Sqlite 来说, contains 等于 icontains.)
4. icontains 大小写不敏感的内容包含测试:
5. in 在给定的列表中。
Entry.objects.filter(id__in=[1, 3, 4])
您还可以使用查询集动态评估值列表,而不是提供文字值列表:
inner_qs = Blog.objects.filter(name__contains='Cheddar')
entries = Entry.objects.filter(blog__in=inner_qs)
== SELECT ... WHERE blog.id IN (SELECT id FROM ... WHERE NAME LIKE '%Cheddar%')
6. gt > Entry.objects.filter(id__gt=4)
7. gte >=
8. lt <
9. lte <=
10. startswith 区分大小写的开头 Entry.objects.filter(headline__startswith='Lennon')
11. istartswith 不区分大小写的开头
12. endswith 区分大小写的结尾
13. iendswith 不区分大小写的结尾
14. range 范围测试(包括在内)
import datetime
start_date = datetime.date(2005, 1, 1)
end_date = datetime.date(2005, 3, 31)
Entry.objects.filter(pub_date__range=(start_date, end_date))
15. date 将字符串转化为日期类型
Entry.objects.filter(pub_date__date=datetime.date(2005, 1, 1))
16. year Entry.objects.filter(pub_date__year=2005)
17. month
18. day
19. week
Entry.objects.filter(pub_date__week=52)
Entry.objects.filter(pub_date__week__gte=32, pub_date__week__lte=38)
20. week_day 对于日期和日期时间字段,“星期几”匹配。
Entry.objects.filter(pub_date__week_day=2)
21. time
22. hour
23. minute
24. second
25. isnull
26. regex 区分大小写的正则表达式匹配。
Entry.objects.get(title__regex=r'^(An?|The) +')
27. iregex 不区分大小写的正则表达式匹配。
28. search 布尔全文搜索,利用全文索引。
Entry.objects.filter(headline__search="+Django -jazz Python")
Q()对象
from django.db.models import Q
Book.objects.filter(Q(pages__gte=10)|Q(price__lt=100))
Q对象的更多用法 (Query)
and: Q(pk=1) & Q(pk=2)
or: Q(pk=1) | Q(pk=2)
not: ~Q(pk=1)
from django.db.models import Q
condition = Q(pk__lt=100) & Q(pk__gt=50)
M.objects.filter(condition)
F()对象
以下操作:
reporter = Reporters.objects.get(name='Tintin')
reporter.stories_filed += 1
reporter.save()
可以换成:
from django.db.models import F
reporter = Reporters.objects.get(name='Tintin')
reporter.stories_filed = F('stories_filed') + 1
reporter.save()
通过 F() 可以引用数据表中的字段,这样,该字段的值不会从数据库读入Python中,Python也无从知晓该字段的值,加一的操作完全在数据库内容执行,效果等同于:
update reporter set stories_filed = stories_filed + 1;
用这种方式更新的记录,需要重载该记录,才能看到新的值:
reporter = Reporters.objects.get(pk=reporter.pk)
# 或者这样:
# reporter.refresh_from_db()
F() 可以用在QuerySet对象的update方法上,见避免了get()和save()操作:
reporter = Reporters.objects.filter(name='Tintin')
reporter.update(stories_filed=F('stories_filed') + 1)
F() 可以提升性能:
1. 让数据库做计算操作,而不是让python来做
2. 减少某些操作的查询次数
Django 提供了三种模型之间的关系,分别是:
1. 多对一(一对多),通过ForeignKey 实现
2. 多对多,通过ManyToManyField 实现
3. 一对一,通过OneToOneField 实现
这三种关系本质上都是通过外键 (foreign key) 来实现的。
创建多对一关系
以父子关系为例,一个父亲可以有多个孩子,一个孩子只能有一个父亲,父亲是“一”,孩子是“多”。
class Father(models.Model):
name = models.CharField(max_length=128)
class Child(models.Model):
name = models.CharField(max_length=128)
father = models.ForeignKey(Father)
通过多对一关系获取关联的记录
f1 = Father.objects.create(name="Abraham")
f2 = Father.objects.create(name="Isaac")
c1 = Child.objects.create(name="Isaac", father=f1)
c2 = Child.objects.create(name="Ishmael", father=f1)
c3 = Child.objects.create(name="Esau", father=f2)
c4 = Child.objects.create(name="Israel", father=f2)
通过Father 记录获取关联的Child 记录:
In [14]: f1.child_set.all()
Out[14]: <QuerySet [<Child: Child object>, <Child: Child object>]>
通过Child 记录获取关联的Father 记录:
In [15]: c1.father
Out[15]: <Father: Father object>
使用关联记录作为查询条件:
In [19]: Father.objects.get(child=c1)
Out[19]: <Father: Father object>
In [20]: Father.objects.get(child=c1.pk)
Out[20]: <Father: Father object>
In [21]: Father.objects.filter(child__in=[c1,c2])
Out[21]: <QuerySet [<Father: Father object>, <Father: Father object>]>
In [22]: Father.objects.filter(child__name='Israel')
Out[22]: <QuerySet [<Father: Father object>]>
In [23]: Child.objects.filter(father__name='Abraham')
Out[23]: <QuerySet [<Child: Child object>, <Child: Child object>]>
多对一关系中删除操作的影响
1. 默认情况下,删除“一”中的记录,“多”中的相关记录会被删除。删除“多”中的记录不影响“一”中的记录。
2. 如果需要改变关联删除这种行为,可以在定义ForeignKey 的时候传递一个 on_delete=models.DO_NOTHING 的参数。
on_delete=models.DO_NOTHING 这种设定,视后台的数据库的不同,行为也会不一样。以mysql为例,
就算手动给mysql的数据表添加了 ON DELETE NO ACTION后,依然不能删除“一”中的记录;不过,如果
使用on_delete=models.SET_NULL,然后在mysql数据表上设置外键属性 ON DELETE SET NULL后,就
可以正常删除“一”中的记录,“多”中的记录的外键会被自动设置为null(就是pyhton的None)。
多对多关系
创建多对多关系
以文章和标签为例,一篇文章可以使用多个标签,一个标签可以给多篇文章使用,是多对多的关系。
class Tag(models.Model):
desc = models.CharField(max_length=128)
class Article(models.Model):
title = models.CharField(max_length=128)
tag = models.ManyToManyField(Tag)
通过多对多关系获取关联的记录
In [22]: t1 = Tag.objects.create(desc='Linux')
In [23]: t2 = Tag.objects.create(desc='Python')
In [24]: a1 = Article.objects.create(title='Python on Linux is good')
In [25]: a2 = Article.objects.create(title='Python on Linux is powerful')
In [26]: a1.tag.add(t1, t2)
In [27]: a2.tag.add(t1, t2)
通过Tag 记录获取关联的Article 记录:
In [28]: t1.article_set.all()
Out[28]: <QuerySet [<Article: Article object>, <Article: Article object>]>
通过Article 记录获取关联的Tag 记录:
In [29]: a1.tag.all()
Out[29]: <QuerySet [<Tag: Tag object>, <Tag: Tag object>]>
使用关联记录作为查询条件:
In [30]: Tag.objects.filter(article__in=[a1, a2]) <-- 有重复
Out[30]: <QuerySet [<Tag: Tag obje ct>, <Tag: Tag object>, <Tag: Tag object>, <Tag: Tag object>]>
In [31]: Tag.objects.filter(article__in=[a1, a2]).distinct() <-- 去重
Out[31]: <QuerySet [<Tag: Tag object>, <Tag: Tag object>]>
In [32]: Article.objects.filter(tag__in=[t1.pk, t2]).distinct()
Out[32]: <QuerySet [<Article: Article object>, <Article: Article object>]>
In [33]: Article.objects.filter(tag__desc__startswith='L').distinct()
Out[33]: <QuerySet [<Article: Article object>, <Article: Article object>]>
多对多关系中删除操作的影响
删除多对多关系中任何一边的记录,不会连带删除另外一边的记录。
一对一关系
创建一对一关系
以非对称加密系统中的公钥和私钥为例。实践中,一个公钥唯一匹配一个私钥,一个私钥唯一匹配一个公钥,是一对一的关系。
class Private(models.Model):
keyid = models.CharField(max_length=128)
class Public(models.Model):
keyid = models.CharField(max_length=128)
private = models.OneToOneField('Private', null=True)
通过一对一关系获取关联的记录
In [2]: pri1 = Private.objects.create(keyid='a')
In [3]: pri2 = Private.objects.create(keyid='b')
In [4]: pub1 = Public.objects.create(keyid='c', pravite=pri1)
In [5]: pub2 = Public.objects.create(keyid='d', pravite=pri2)
通过Private 记录获取关联的Public 记录:
In [32]: pri1.public
Out[32]: <Public: Public object>
通过Public 记录获取关联的Private 记录:
In [33]: pub1.private
Out[33]: <Private: Private object>
使用关联记录作为查询条件:
In [34]: Public.objects.get(private=pri1)
Out[34]: <Public: Public object>
In [35]: Public.objects.filter(private__in=[pri1,pri2])
Out[35]: <QuerySet [<Public: Public object>, <Public: Public object>]>
In [36]: Private.objects.filter(public=pub1.pk)
Out[36]: <QuerySet [<Private: Private object>]>
一对一关系中删除操作的影响
一对一关系本质上是外键关系(和多对一关系一样),只不过一对一关系给外键加上唯一性限制而已。两个模型的定义中,没有OneToOneField 的那个模型可以被称为“被引用”的模型。默认情况下,删除“被引用”的模型的记录,会连带删除对应的“引用”模型的记录,在定义OneToOneField 时加上on_delete=models.DO_NOTHING 可以改变连带删除行为。删除“引用”模型的记录则不会删除“被引用”模型的记录。这和“一对多”关系是一样的。
四、创建指定时区的时间对象,并对时间做时区转换
1. 用pytz.timezone 创建一个Asia/Chongqing 的时区
from datetime import datetime
import pytz
tz = pytz.timezone('Asia/Chongqing') <-- 创建时区
2. 给一个没有时区信息的时间加上刚创建的时区信息
naive_time = datetime.now() <-- 无时区信息
aware_time = tz.localize(naive_time) <-- 加上本地时区信息
# aware_time = datetime.now(tz) <-- 给now加上时区参数,效果与上面两条命令等价
3. 把加上时区信息的时间对象转换成UTC的时间
tz2 = pytz.timezone('UTC') <-- 另外一个时区
tz2.normalize(aware_time) <-- 时区转换
aware_time.astimezone(tz2) <-- 时区转换,与上等价
sqlite命令行操作参考
.help <-- 显示帮助信息
.tables <-- 显示所有表的名字
.schema <-- 显示所有表的结构
.schema tb1 <-- 显示表db1的结构
.header on
.mode column
select * from tb1
定制Django后台,关联编辑
假设Choice通过ForeignKey指向Question,现在需要在编辑Question的时候能够编辑相关联的Choice,
则可以参考以下做法:
# 定义一个Inline的类,类中用model属性指明被关联编辑的模型,这里就是Choice
class ChoiceStackInline(admin.TabularInline):
model = Choice
# 定义一个ModelAdmin类,类中用inlines来使用刚刚定义好的Inline类
class ChoiceAdmin(admin.ModelAdmin):
inlines = [ChoiceStackInline,]
# 注册的时候,把刚刚定义好的ModelAdmin类作为第二个位置参数
admin.site.register(Question, ChoiceAdmin)
mysql、MongoDB、Django-SQL、Redis日常操作
最新推荐文章于 2021-02-01 02:03:16 发布