Django---model基础(单表)

时间:2023-02-04 18:43:49

ORM

一、映射关系:

          表名<--------------->类名
          字段<-------------->属性
          表记录<----------->类实例对象

创建表(建立表模型)

二、单表

class Book(models.Model):
nid = models.AutoField(primary_key=True)
title = models.CharField(max_length=32)
authors = models.CharField(max_length=32)
publishDate = models.DateField()
price = models.DecimalField(max_digits=5, decimal_places=2)

1.通过logging可以查看翻译成的sql语句

LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'handlers': {
'console':{
'level':'DEBUG',
'class':'logging.StreamHandler',
},
},
'loggers': {
'django.db.backends': {
'handlers': ['console'],
'propagate': True,
'level':'DEBUG',
},
}
}
 1、models.AutoField  自增列= int(11)
  如果没有的话,默认会生成一个名称为 id 的列,如果要显示的自定义一个自增列,必须将给列设置为主键 primary_key=True。
2、models.CharField  字符串字段
  必须 max_length 参数
3、models.BooleanField  布尔类型=tinyint(1)
  不能为空,Blank=True
4、models.ComaSeparatedIntegerField  用逗号分割的数字=varchar
  继承CharField,所以必须 max_lenght 参数
5、models.DateField  日期类型 date
  对于参数,auto_now =True则每次更新都会更新这个时间;auto_now_add 则只是第一次创建添加,之后的更新不再改变。
6、models.DateTimeField  日期类型 datetime
  同DateField的参数
7、models.Decimal  十进制小数类型= decimal
  必须指定整数位max_digits和小数位decimal_places
8、models.EmailField  字符串类型(正则表达式邮箱)=varchar
  对字符串进行正则表达式
9、models.FloatField  浮点类型= double
10、models.IntegerField  整形
11、models.BigIntegerField  长整形
  integer_field_ranges ={
    'SmallIntegerField':(-32768,32767),
     'IntegerField':(-2147483648,2147483647),
    'BigIntegerField':(-9223372036854775808,9223372036854775807),
    'PositiveSmallIntegerField':(0,32767),
    'PositiveIntegerField':(0,2147483647),
  }
12、models.IPAddressField  字符串类型(ip4正则表达式)
13、models.GenericIPAddressField  字符串类型(ip4和ip6是可选的)
  参数protocol可以是:both、ipv4、ipv6
  验证时,会根据设置报错
14、models.NullBooleanField  允许为空的布尔类型
15、models.PositiveIntegerFiel  正Integer
16、models.PositiveSmallIntegerField  正smallInteger
17、models.SlugField  减号、下划线、字母、数字
18、models.SmallIntegerField  数字
  数据库中的字段有:tinyint、smallint、int、bigint
19、models.TextField  字符串=longtext
20、models.TimeField  时间 HH:MM[:ss[.uuuuuu]]
21、models.URLField  字符串,地址正则表达式
22、models.BinaryField  二进制
23、models.ImageField图片
24、models.FilePathField文件

添加表记录

三、

1.添加表记录(save和create)

方式一:book_obj=models.Book(title=title)
              book_obj.save() #将数据保存到数据库

方式二:book_obj=models.Book.objects.create(title=title)

2.查询

1.all       查询所有结果            用法:models.表名.objects.all()      结果是QuerySet集合    [model对象]
2.filter 查询所给筛选匹配的对象 用法:models.表名.objects.filter() 结果是:QuerySet集合 如:ret=models.表名.objects.filter(auther='mqj',price=123)
3.get 查询所给筛选匹配的对象,返回值只有一个,如果筛选的对象超过一个或没有就会报错 用法:models.表名.objects.get() 结果是:model对象 如:ret=models.表名.objects.get(auther="yuan")
4.exclude 包含筛选条件你匹配的对象 用法:ret=models.表名.objects.exclude
(author="yuan")
5.values 方法 返回的是列表中一个一个的可迭代字典 返回的是列表中一个一个的可迭代字典 用法:ret=models.表名.objects.filter(author="yuan").value("title","price")
6.values_list 方法 返回的是列表中一个一个的元组序列 用法:ret=models.表名.objects.filter(author="yuan").value_list("title","price")
7.reverse():对查询的结果反向排序
8.order_by():对查询的结果排序
9.ddistinct(): 返回的结果中剔除重复记录
10.count(): 返回数据库匹配查询数量 用法:ret=models.Book.objects.filter(author="yuan").count()
11.first(): 返回第一条记录 用法:ret = models.Book.objects.all().first()
12.last(): 返回最后一条记录 用法:ret = models.Book.objects.all().last()
13.exists(): 返回True或False 用法:ret=models.Book.objects.all().existst()

3、双下划线之单表查询:

models.Tb1.objects.filter(id__lt=10, id__gt=1)   # 获取id大于1 且 小于10的值

models.Tb1.objects.filter(id__in=[11,22,33]) # 获取id等于11、22、33的数据

models.Tb1.objects.filter(name__contains="ven")

models.Tb1.objects.filter(name__icontains="ven")

models.Tb1.obiects.filter(id__range=[1,2])   #范围bettwen and

startswith,istartswith,endswith,iendswith

4.修改

修改方式1:save(效率低)
如:   book_obj=models.Book.objects.filter(nid=id)[0]
book_obj.title="金平"
book_obj.save()
修改方式2:
        title=request.POST.get("title")
authors=request.POST.get("authors")
pubDate=request.POST.get("pubDate")
price=request.POST.get("price")
models.Book.objects.filter(nid=id).update(title=title,authors=authors,publishDate=pubDate,price=price)

5.删除:

     delect

了不起的双下划线:
models.表名.objects.filter(id__gt=10)
models.表名.objects.filter(title__startswith="py")
models.Tb1.objects.filter(id__range=[1, 2])
models.Tb1.objects.filter(id__in=[11, 22, 33])

 四、表关联操作

实例:我们来假定下面这些概念,字段和关系

作者模型:一个作者有姓名和年龄。

作者详细模型:把作者的详情放到详情表,包含生日,手机号,家庭住址等信息。作者详情模型和作者模型之间是一对一的关系(one-to-one)

出版商模型:出版商有名称,所在城市以及email。

书籍模型: 书籍有书名和出版日期,一本书可能会有多个作者,一个作者也可以写多本书,所以作者和书籍的关系就是多对多的关联关系(many-to-many);一本书只应该由一个出版商出版,所以出版商和书籍是一对多关联关系(one-to-many)。

class Book(models.Model):
nid = models.AutoField(primary_key=True)
title = models.CharField(max_length=32)
publishDate = models.DateField()
price = models.DecimalField(max_digits=5, decimal_places=2)
publish = models.ForeignKey("Publish", related_name="bookList")
authorlist = models.ManyToManyField("Author", related_name="bookList")
def __str__(self):
return self.title
class Publish(models.Model):
name = models.CharField(max_length=32)
addr = models.CharField(max_length=32)
def __str__(self):
return self.name
class Author(models.Model):
name = models.CharField(max_length=32)
age = models.IntegerField()
def __str__(self):
return self.name
class AuthorDetail(models.Model):
tel=models.IntegerField()
addr=models.CharField(max_length=32)
author=models.OneToOneField("Author",related_name="authorList")

 表关系:

      1.一对多

      2.一对一

      3.多对多

添加记录:
一对多:
创建一对多:
publish=models.ForeignKey("Publish",related_name="bookList")
添加记录方式1:
models.Book.objects.create(publish_id=1)
添加记录方式2:
pubObj=models.Publish.objects.filter(name="人民出版社")[0]
models.Book.objects.create(publish=pubObj) # 关联的出版社对象 多对多:
创建多对多关系:
authorlist=models.ManyToManyField("Author",related_name="bookList")
多对多添加记录:
book_obj=models.Book.objects.create(title="追风筝的人", price=100, publishDate="2017-12-12", publish_id=2)
alex_obj=models.Author.objects.filter(name="alex")[0]
egon_obj=models.Author.objects.filter(name="egon")[0] book_obj.authorlist.add(alex_obj,egon_obj)
查询记录:
正向查询:
一对多:
linux_obj=models.Book.objects.filter(title="linux").first()
print(linux_obj.publish.name) # 与这本书对象关联的出版社对象的名字
多对多:
linux_obj=models.Book.objects.filter(title="linux").first()
print(linux_obj.authorlist.all()) # 与这本书关联的所有作者对象集合
反向查询:
#一对多的反向查询:
eg:人民出版社出版过的书籍的名字
publish_obj=models.Publish.objects.filter(name="人民出版社")[0]
print(publish_obj.bookList.all()) # 与该年出版社关联的所有书籍对象的集合
#多对多的反向查询:
查询yuan出版过的所有书籍的名字和价格:
author_yuan=models.Author.objects.get(name="yuan")
print(author_yuan.bookList.all()) # 与该作者关联的所有书籍书籍对象的集合

 2.基于对象的查询

基于对象关联查询:    

    if 一对多查询(Book--Publish):
正向查询,按字段:
book_obj.publish : 与这本书关联的出版社对象 book_obj.publish.addr: 与这本书关联的出版社的地址
反向查询,按表名_set
publish_obj.book_set: 与这个出版社关联的书籍对象集合 publish_obj.book_set.all() :[obj1,obj2,....] if 一对一查询(Author---AuthorDetail):
正向查询,按字段:
author_obj.ad : 与这个作者关联的作者详细信息对象 反向查询:按表名:
author_detail_obj.author : 与这个作者详细对象关联的作者对象 if 多对多(Book----Author): 正向查询,按字段: book_obj.authorList.all(): 与这本书关联的所有这作者对象的集合 [obj1,obj2,....] 反向查询,按表名_set:
author_obj.book_set.all() : 与这个作者关联的所有书籍对象的集合

3.双下划线的跨表查询 

查询python这本书出版社的地址
# 方式一:
# book_obj=models.Book.objects.filter(title="python").first()
# print(book_obj.publish.name) # 方式二(双下划线):
# book_obj=models.Book.objects.filter(title="python").values("publish__addr")
# print(book_obj) # 方式三(双下划线):
# book_obj=models.Publish.objects.filter(bookList__title="python").values("addr")
# print(book_obj) 查询老男孩出版社出版过的所有书籍的名字与价格
# 方式一:
# book_obj=models.Publish.objects.filter(name="老男孩出版社").first()
# print(book_obj.bookList.all().values("title","price")) # 方式二:(双下划线)
# book_obj=models.Publish.objects.filter(name="老男孩出版社").values("bookList__title","bookList__price")
# print(book_obj) # 方式三(双下划线):
# book_obj=models.Book.objects.filter(publish__name="老男孩出版社").values("title","price")
# print(book_obj) # egon出版过的所有书籍名称以及出版社名称
# book_obj=models.Author.objects.filter(name="egon").values("bookList__title","bookList__authorlist__name")
# print("book_obj",book_obj) 查询egon出过的所有书籍的名字(多对多)
book_obj=models.Author.objects.filter(name="egon").values("bookList__title")
print(book_obj) book_obj=models.Book.objects.filter(authorlist__name="egon").values("title")
print(book_obj) 手机号以151开头的作者出版过的所有书籍名称以及出版社名称 # book_obj=models.AuthorDetail.objects.filter(tel__startswith="151").first()
# print(book_obj.author.bookList.all().values("title","publish__name")) # 方法2
# models.Book.objects.filter(authorlist__author_detail__tel__startswith="151").values("title", "publish__name")
if 一对多查询(Book--Publish):
正向查询,按字段:
# 查询linux这本书的出版社的名字:
models.Book.objects.all().filter(title="linux").values("publish__name")
反向查询:按表名:
# 查询人民出版社出版过的所有书籍的名字
models.Publish.objects.filter(name="人民出版社出版").values("book__title") if 一对一查询(Author---AuthorDetail):
正向查询,按字段:
models.Author.objects.filter(name="egon).values("ad__tel")
反向查询:按表名:
models.AuthorDetail.objects.filter(tel="").values("author__name") if 多对多(Book----Author):
正向查询,按字段:
models.Book.objects.filter(title="python").values("authorList__name") [{},{},{},{}] 正向查询,按表名:
models.Author.objects.filter(name="alex").values("book__price") 注意: publish=models.ForeignKey("Publish",related_name="bookList")
authorlist=models.ManyToManyField("Author",related_name="bookList")
ad=models.models.OneToOneField("AuthorDetail",related_name="authorInfo") 反向查询的时候都用:related_name

 4.查询

一对多的查询
# 查询linux这本书的出版社的地址? #linux_obj=models.Book.objects.filter(title="linux").first()
#
# print(linux_obj.title)
# print(linux_obj.price)
# print(linux_obj.publishDate)
#
# print(linux_obj.publish.name) # 与这本书对象关联的出版社对象
#print(linux_obj.publish.addr) # 与这本书对象关联的出版社对象 # 人民出版社出版过的书籍的名字
# publish_obj=models.Publish.objects.filter(name="人民出版社")[0]
# print(publish_obj.bookList.all()) # 与这个出版社对象关联的所有书籍对象 多对多的查询 # 查询追风筝的人的所有作者的姓名和年龄 # book_obj=models.Book.objects.filter(title="追风筝的人")[0]
# print("=====",book_obj.authorlist.all() ) # 与这本书关联的所有作者对象,集合对象
# authorlist=book_obj.authorlist.all()
# print(authorlist.values("name","age")) # 查询yuan出版过的所有书籍的名字和价格 #author_yuan=models.Author.objects.get(name="yuan") #print(author_yuan.book_set.all()) # 与这个作者关联的所有书籍对象
#print(author_yuan.bookList.all().values("title","price")) 一对一关系查询 正向查询 #查询手机号为456的作者的姓名 # ad=models.AuthorDetail.objects.filter(tel="456").first()
# print(ad.author.name) #detail_obj=models.AuthorDetail.objects.filter(tel="456").first()
# print(detail_obj.author.name)# 与tel="456"的Author2Detail关联的作者对象
#
反向查询
# 查询景丽洋的手机号
# author_obj=models.AuthorA.objects.filter(name="景丽洋").first()
# print(author_obj.author2detail.tel) # 789
# print(author_obj.abc.tel) # 789

5.添加

一对多的添加
# 方式1
#models.Book.objects.create(title="python",price=100,publishDate="2017-12-12",publish_id=1) # 方式2
# pubObj=models.Publish.objects.filter(name="人民出版社")[0]
# models.Book.objects.create(title="python2",price=120,publishDate="2017-10-12",publish=pubObj) # 关联的出版社对象 多对多的添加
#book_obj=models.Book.objects.create(title="红楼梦", price=100, publishDate="2017-12-12", publish_id=2) # alex_obj=models.Author.objects.filter(name="alex")[0]
# egon_obj=models.Author.objects.filter(name="egon")[0]
# egon_obj=models.Author.objects.filter(name="yuan")[0]
# print("======",book_obj.authorlist) # []
# authorList=models.Author.objects.all()
绑定多对多的关系
# #book_obj.authorlist.add(alex_obj,egon_obj) # [alex_obj,egon_obj]
# book_obj.authorlist.add(*authorList) # [alex_obj,egon_obj] 解除多对多的关系 # book_obj=models.Book.objects.filter(title="红楼梦").first()
# authorList=models.Author.objects.filter(id__lt=3)
# print(book_obj.authorlist.remove(*authorList)) 清除关系方法
# book_obj = models.Book.objects.filter(title="红楼梦").first()
# book_obj.authorlist.clear()

五、聚合函数

from django.db.models import Avg,Sum,Count,Max,Min

聚合函数:aggregate
# 查询所有图书的价格和 ret=models.Book.objects.all().aggregate(priceSum=Sum("price"))
ret=models.Book.objects.all().aggregate(priceAvg=Avg("price"),priceSum=Sum("price"))
print(ret) # {'price__sum': Decimal('166.00')} 分组函数 annote函数 # 查询每一本书的作者个数 book_list=models.Book.objects.all().annotate(c=Count("authorlist__name"))
for book_obj in book_list:
print(book_obj.c) # 查询每一个出版社出版过的最便宜的书籍
ret=models.Book.objects.all().annotate(Min("price"))
print(ret)
统计不止一个作者的图书:
             queryResult=Book.objects
          .annotate(num_authors=Count('authors'))
          .filter(num_authors__gt=1)
查询各个作者出的书的总价格:
# 按author表的所有字段 group by
queryResult=Author.objects

              .annotate(SumPrice=Sum("book__price"))
              .values_list("name","SumPrice")
print(queryResult) #按authors__name group by
queryResult2=Book.objects.values("authors__name")

              .annotate(SumPrice=Sum("price"))
              .values_list("authors__name","SumPrice")
print(queryResult2)

分组查询:
querySet().annotate() --- 返回的是querySet #统计每一个出版社中最便宜的书籍的价格 sql:
select Min(price) from book group by publish_id; ORM: models.Book.objects.values("publish__name").annotate(Min("price"))

六、F查询与Q查询

F查询

1.查询评论数大于收藏数的书籍:

 from django.db.models import F
Book.objects.filter(commnetNum__lt=F('keepNum'))

2. 查询评论数大于收藏数2倍的书籍

 Book.objects.filter(commnetNum__lt=F('keepNum')*2)

3.修改操作也可以使用F函数,比如将每一本书的价格提高30元:

Book.objects.all().update(price=F("price")+30) 

Q查询

filter() 等方法中的关键字参数查询都是一起进行“AND” 的。 如果你需要执行更复杂的查询(例如OR 语句),你可以使用Q

 from django.db.models import Q

Q(title__startswith='Py')
bookList=Book.objects.filter(Q(authors__name="yuan")|Q(authors__name="egon"))

你可以组合& 和|  操作符以及使用括号进行分组来编写任意复杂的Q 对象。同时,Q 对象可以使用~ 操作符取反,这允许组合正常的查询和取反(NOT) 查询:

bookList=Book.objects.filter(Q(authors__name="yuan") & ~Q(publishDate__year=2017)).values_list("title")

查询函数可以混合使用Q 对象和关键字参数。所有提供给查询函数的参数(关键字参数或Q 对象)都将"AND”在一起。但是,如果出现Q 对象,它必须位于所有关键字参数的前面。例如:

bookList=Book.objects.filter(Q(publishDate__year=2016) | Q(publishDate__year=2017),
title__icontains="python"
)

补充:

有关Django中的命令:

下载Django:pip3 install Django
创建一个djang project:django-admin.py startptoject 项目名称;
在目录下创建应用:python manage.py startapp blog;
启动Django项目:python manage.py runserver 端口; python manage.py syncdb
注意:Django 1.7.1 及以上的版本需要用以下命令
python manage.py makemigrations
python manage.py migrate
'''
python manage.py createsuperuser # 按照提示输入用户名和对应的密码就好了邮箱可以留空,用户名和密码必填 # 修改 用户密码可以用:
python manage.py changepassword username '''
注意:
       对象可以调用自己的属性