# 在Django中默认使用自带的sqlite数据库
# 如果想使用MySQL,在settings.py文件中添加下面语句,把之前的sqlite配置注掉
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'books', #你的数据库名称
'USER': 'root', #你的数据库用户名
'PASSWORD': '', #你的数据库密码
'HOST': '', #你的数据库主机,留空默认为localhost
'PORT': '3306', #你的数据库端口
}
}
TIME_ZONE = 'Asia/Shanghai' # 使用上海时间
# 这时候创建数据库会报错,因为Django默认使用MySQLdb,这是python2的模块,在python3中使用pymysql
# 要解决这个问题,在项目的__init__.py文件中添加
import pymysql
pymysql.install_as_MySQLdb()
# 创建表=========================================
# models.py
from django.db import models
from django.contrib.auth.models import User # django自带的用户登录验证
#使用时在用户表中添加user字段Foreignkey(User)
#创建一张表,可以不写主键id ,创建表时会自动创建
class Book(models.Model): # 必须继承这个库
name = models.CharField(
null=True # 字段可以为空
max_length=25, # 必填
db_column = 'user', # 数据库列名name->user
db_index = True, # 创建索引
unique = True, # 加速查找,限制列值唯一
primary = True, # 加速查找,限制列值唯一且非空
#admin属性
verbose_name='user',
blank=True, # 在admin中字段是否可以为空
editable=True , # 在admin中是否可编辑
help_text= '帮助信息',
choices # 下拉框选项
# gf = models.IntegerField(choices=[(0,"v1"),(1,"v2"),],default=1)
error_messages
validators #自定义错误验证
)
price = models.IntegerField()
pub_date = models.DateField()
class Meta:
uninque_together("字段一","字段二") # 联合唯一
abstract = True # abstract:抽象的 使定义的这个modle不生成表,只用来供其他model类继承
想要创建表就在命令行输入下面两条命令
python manage.py makemigrations
python manage.py migrate
#添加表记录
#方法一---------------------------------------------------
#一个实例对象就是一条表记录,先创建一个对象,再保存
b = Book(name = "python",price=45,........)
b.save()
#方法二---------------------------------------------
Book.objects.create(name = "python",price=45,........)
#修改表记录
# 方式一------------------------------------------
Book.objects.filter().update() # <class 'django.db.models.query.QuerySet'>
# 方式二-------------------------------------------
b.Book.objects.get() # <class 'app01.models.Book'>
b.prince = 80
b.save()
# 删除表记录
Book.objects.filter().delete()
# 查询表记录
1. all() # 取出全部,支持切片
2. first() # 取出第一个
3. last() # 取出最后一个
4. get() #一定会取出那一条记录的对象,其他的是取出一组对象,哪怕只有一个
5. values values_list #通过filter筛选出来的多条记录,可以通过调用这两个方法,获取其中的某个字段,前者是字典,后者是元组
6. exclude() # 取出除筛选条件之外的记录
7. distinct() # values取字段的时候可能会取到重复字段,用该方法可以去重
# 万能的双下划线-------------------------------
__gt: #字段名下的数据小于,prince__gt = 10,prince大于10的记录 ,__gte大于等于
__contains # 字段中包含, name__contains = "p" ,包含"p", __icontains不区分大小写
# 多表操作(一对多)
#添加外键,比如把书绑定到出版社
/*
class ForeignKey(to,on_delete,**options) 。
第一个参数是引用的是哪个模型,第二个参数是在使用外键引用的模型数据被删除了,这个字段该如何处理,
比如有 CASCADE 、 SET_NULL 等
*/
- 一对一
- 一张表其实就是一对一
-两张表的一对一要添加约束唯一性
-一对多
# class Userinfo(models.Model):
# username = models.CharField(
# max_length=32,
# )
# p_k = models.ForeignKey(
# to="Part", # 关联的表
# to_field="id", # 关联的字段,默认关联ID
# on_delete=models.CASCADE, #与之关联的数据全部删除
#- models.DO_NOTHING,引发错误IntegrityError
#- models.PROTECT, 引发错误ProtectedError
#- models.SET_NULL,删除关联数据,与之关联的值设置为null(前提FK字段需要设置为可空)
#- models.SET_DEFAULT,删除关联数据,与之关联的值设置为默认值(前提FK字段需要设置默认值)
#- models.SET,删除关联数据,
#a. 与之关联的值设置为指定值,设置:models.SET(值)
#b. 与之关联的值设置为可执行对象的返回值,设置:models.SET(可执行对象)
# )
# class Part(models.Model):
# name = models.CharField(
# max_length=32,
# )
-多对多
-多对多的第三张表有两种创建方式
a. 添加ManyToMany字段
mk = models.ManyToManyField(
to="Tag",
related_name=None, # 反向操作时,使用的字段名,用于代替 【表名_set】 如: obj.表名_set.all()
related_query_name=None, # 反向操作时,使用的连接前缀,用于替换【表名】 如: models.UserGroup.objects.filter(表名__字段名=1).values('表名__字段名')
limit_choices_to=None, # 在Admin或ModelForm中显示关联数据时,提供的条件:
db_table=None, # 创建第三张表时的表名
db_constraint=True,
through=None, # 指定关系表,即不自动创建,而使用手动创建的第三张表,但有些方法无法使用如add
through_fields=None,
)
b.手动创建第三张表
class Utotag(models.Model):
u = models.ForeignKey(to="User",on_delete=models.CASCADE)
t = models.ForeignKey(to="Tag",on_delete=models.CASCADE)
class Meta: # 约束多对多关系,使对应的多不能重复
verbose_name = u'图片'
verbose_name_plural = u'图片'
unique_together = [
("u","t"), #Please correct the error below.
]
- 自关联
# 自关联
"""
一个网站的用户在一张表中
用户之间的互相关注,是一种自关联
"""
class User_list(models.Model):
user = models.CharField(max_length=32)
uTOu = models.ManyToManyField(to="User_list",related_name="sss")
# 建议所有的多表关系都使用related_name
- 会自动创建另一张表 其中的字段名 : id from_user_list_id to_user_list_id
-select_related("外键字段")
from app01 import models
b_obj_list = models.B.objects.all().select_related("fk")
for row in b_obj_list:
print(row.name)
print(row.fk.name)
# for循环进行跨表查询时每次查询都会到数据库中执行查询,效率低
#models.B.objects.all().select_related("fk"),这样关联表也会被一次取出,提升了性能
# 在Book类中添加这样一个字段,public = models.ForeignKey("被关联的出版社表",on_delete=models.CASCADE)
#django会自动在字段名后添加 _id ,默认关联到 id 上
# 添加记录
#方式一------------------------------------------
Book.objects.create(name = "GO",prince=70,pub_date='2019-08-07',public_id=1)
#方式二-------------------------------------------
# 先获取要绑定的对象
public_object=Public.objects.filter(name='人民出版社')[0] # 这是一个对象集合所以取索引0
# 之后把对象赋给外键(不加_id)
Book.objects.create(name='python',prince=50,pub_date='2017-02-1',public=public_object)
# 查询记录
# 方式一 正向查询:根据外键找关联,先取到model,然后model.外键就取到了这个model关联的对象
book_model = Book.objects.get(name="python")
print(book_model.public.name)
print(book_model.public.city)
# 方式二 反向查询:从被关联的表反向找关联表,格式:被关联表model.关联表_set.all().values() || _set.all().values_list()
OneToOne无法反向查询
pub_set = Public.objects.get(id=1)
book_msg = pub_set.book_set.all().values("name","price")
print(book_msg)
#-- 小写类名_set是一种默认形式,可以修改在外键参数添加related_name=""
cs = models.ForeignKey(Classes,on_delete=models.CASCADE,related_name="sss")
# 正向查找和反向查找
# ---找到学员对应班级,正向查找
date = models.Students.objects.all().values("student_name","cs__class_name")
# values是一个queryset字典,而values_list是元组,并且values在get和filter中不能使用
for i in date:
print(i["student_name"],i["cs__class_name"])
# ---找到班级对应的学员,反向查找
reverse_date = models.Classes.objects.get(id=2).students_set.all().values("student_name")
print(reverse_date)
return HttpResponse("成功")
# 以上两种方式都是通过对象
# 方式三:伟大的双下划线__ (可以在values中和filter中使用)
# 多表操作(多对多)
#两张表之间的多对多需要第三张表做桥梁
# 第一种方法是手动添加第三张表,两个外键分别关联两张表
# 在其中一张表中添加字段 字段名 = models.ManyToManyField("另一张表名")
# 之后Django会自动创建第三张表
# 向第三张表中添加记录
# 取到要关联的两个对象,使用add方法添加
author_obj = Author.objects.get(name="alex")
book_obj = Book.objects.get(id=2)
book_obj.author.add(author_obj) # .remove(),可以解除关联,也就是删除第三张表中book_obj对应的数据
# 还可以直接传参数id号 book_obj.author.add(ID号([1,2,3]或者 2))
# 删除数据
book_obj.author.remove(book_obj) #可以解除关联,也就是删除第三张表中book_obj对应的数据
book_obj.author.clear() #清空该对象的关联
# 重置关联
book_obj.author.set([1,2,3]) # 相当于清空关联,重新设置
# 查询数据
# 查找alex出过的书
ret = Book.objects.filter(author__name="alex").values("name","price")
# 查找GO这本书的作者
ret1 = Book.objects.filter(name = "GO").values("author__name")
print(ret1)
# 查询一班的老师
obj4=models.Classes.objects.filter(class_name="一班").first()
obj5=models.Classes.objects.get(class_name="一班")
print(obj4.ct.all().values("teacher_name"))
# obj=models.Classes.objects.all().values("class_name","ct__teacher_name")
# for i in obj:
# print(i)
# 聚合和分组
# 聚合
# 首先导入模块 from django.db.models import Avg Sum Min Max Count
# 求所有书的价格
# ret = Book.objects.aggregate(Sum("price"))
# print(ret)
# 分组
# 求每个出版社出的书的价格
ret = Public.objects.values("name").annotate(Sum("book__price"))
print(ret)
# 求每个作者出的书的价格
ret2=Author.objects.values("name").annotate(Sum("book__price"))
print(ret2)
#F查询和Q查询
# filter中的筛选条件可以用逗号隔开写多条,但是这些条件之间是且的关系,怎么表示或和非呢?
# 修改一条记录,SQL语句可以直接使用算术运算符,但ORM中不行,怎么办呢
# F查询和Q查询
# 给每本书的价格加10
Book.objects.all().update(price=F("price")+10)
# 查询除了python以外的所有书
ret = Book.objects.filter(~Q(name="python"))
for i in ret:
print(i.name)
# 查询价格是50或者60的书
ret = Book.objects.filter(Q(price=50)|Q(price=60))
for i in ret:
print(i.name)
###########注意在筛选条件中F、Q和键值对可以并存,但F、Q要在键值对前面
"""
from django.db.models import Q
query_obj=Q()
query_obj.connector='or'
query_obj.children.append(('qq__contains',query))
query_obj.children.append(('name__contains',query))
"""
# QuerySet :查询集合的一些特点
1.查询语句不会被立即执行,只有使用查询结果时才被执行
2.查询的结果会放在缓存中,中间无论怎么修改,再次使用查询结果都是缓存中的,除非再次调用查询语句
3.查询集合会全部放在内存中,当如果这个数据特别大,那么内存就会有极大的负担,所以可以吧查询集合做成一个生成器
用的时候一条一条的取 ,给集合调用.iterator()方法