Django(四):model
一、创建model
django.db.models是django自带的创建数据库的ORM。
在models.py中以继承models.Model创建表后,需要在setttngs中确保添加了当前应用,并执行
python3 manage.py makemigrations app[应用名称]
python3 manage.py migrate app[应用名称]
来生成迁移文件并提交到数据库执行建表操作。
一、创建单张表
# models.py
from django.db import models
class Person(models.Model):
name = models.CharField(max_length=)
age = models.CharField(max_length=)
from app02.models import Person
p1 = Person(name="Jan", age=20) # 声明一个实例,也就是一条记录
p1.save() # 必须保存
p2 = Person()
p2.name = "Li"
p2.age = 18 # 可以声明一个实例,也可以修改一个字段,同样需要提交
p2.save()
二、创建一对一表
当一张既有的表需要扩充字段时,为了保持原有的表字段和结构不变,可以创建另一张表存储扩充的字段;第二张表的主键和第一张表的主键一一对应。
# models.py
from django.db import models class Place(models.Model):
name = models.CharField(max_length=50)
address = models.CharField(max_length=80) class Restaurant(models.Model):
place = models.OneToOneField(Place,on_delete=models.CASCADE,primary_key=True)
serves_hot_dogs = models.BooleanField(default=False)
serves_pizza = models.BooleanField(default=False)
>>> p1 = Place(name='Demon Dogs', address='944 W. Fullerton')
>>> p1.save()
>>> p2 = Place(name='Ace Hardware', address='1013 N. Ashland')
>>> p2.save()
>>> r1 = Restaurant(place=p1, serves_hot_dogs=True, serves_pizza=False) # 插入记录时,如果需要同时插入扩充的字段,就在后面继续添加扩充表
>>> r1.save()
>>> p1.restaurant
>>> r2.place
>>> hasattr(p2, 'restaurant') # 可以用hasattr检查是否已插入扩充字段
三、创建多对一表
# models.py
from django.db import models class Reporter(models.Model):
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=30)
email = models.EmailField()
class Article(models.Model):
headline = models.CharField(max_length=100)
pub_date = models.DateField()
reporter = models.ForeignKey(Reporter, on_delete=models.CASCADE)
>>> r1 = Reporter(first_name='John', last_name='Smith',
email='john@example.com')
>>> r1.save() # 一定要save,否则下面的Article外键无法绑定需要的reporter字段
>>> r2 = Reporter(first_name='Paul', last_name='Jones', email='paul@example.com')
>>> r2.save()
>>> from datetime import date
>>> a1 = Article(id=None, headline="This is a test", pub_date=date(, , ), reporter=r1) # 正向添加-添加记录时需要指定reporter
>>> a1.save()
>>> a2 = Article.objects.create(headline="Paul's story", pub_date=date(2006, 1, 17), reporter=r2) # 正向添加-用管理器的方式添加,不需要save()
>>> r2.article_set.create(headline="John's second story", pub_date=date(2005, 7, 29)) # 反向添加-注意r2.article_set的方式
>>> r3 = Reporter(first_name="Jan", last_name="--", email="jan@example.com")
>>> r3.save()
>>> r3.article_set.add(a2) # 反向添加一个对象
>>> r3.artilce_set.remove(a2) # 反向删除
add()和remove()是django默认的用于处理一对多或者多对多的增删操作。对于ForeignKey,只有“一”的那张表可以使用add和remove来一次性添加一个或者多个“多”的记录。对于ManyToManyField,两张表都可以使用add和remove添加或者删除一个或者多个记录。
四、创建多对多表
# models.py
from django.db import models class Publication(models.Model):
title = models.CharField(max_length=30)
def __str__(self):
return self.title
class Meta:
ordering = ('title',) class Article(models.Model):
headline = models.CharField(max_length=100)
publications = models.ManyToManyField(Publication)
def __str__(self):
return self.headline
class Meta:
ordering = ('headline',)
>>> p1 = Publication(title='The Python Journal')
>>> p1.save()
>>> p2 = Publication(title='Science News')
>>> p2.save()
>>> p3 = Publication(title='Science Weekly')
>>> p3.save()
>>> a1 = Article(headline='Django lets you build Web apps easily')
>>> a1.save()
>>> a1.publications.add(p1,p2,p3) # 直接用add添加一个或多个记录
>>> a2 = Article(headline='NASA uses Python')
>>> a2.save()
>>> new_publication = a2.publications.create(title='Highlights for Children') # 或者直接用管理器(models.objects.create)创建一条记录并添加进去
>>> p2.article_set.all() # 可以通过article_set访问
>>> a4 = Article(headline='NASA finds intelligent life on Earth') # 反向添加记录:可以先写好记录,再添加给另一张表
>>> a4.save()
>>> p2.article_set.add(a4)
>>> new_article = p2.article_set.create(headline='Oxygen-free diet works wonders') # 或者也用管理器的方式添加
二、Field和字段
名称 | 解释 |
AutoField | 一个根据实际ID自动增长的IntegerField,通常不指定;如果不指定,一个主键字段将自动添加到模型中 |
BooleanField | true/false 字段,此字段的默认表单控制是CheckboxInput |
NullBooleanField | 支持null、true、false三种值 |
CharField(max_length=字符长度) | 字符串,默认的表单样式是 TextInput |
TextField | 大文本字段,一般超过4000使用,默认的表单控件是Textarea |
IntegerField | 整数 |
DecimalField(max_digits=None, decimal_places=None) | 使用python的Decimal实例表示的十进制浮点数;DecimalField.max_digits=位数总数,DecimalField.decimal_places=小数点后的数字位数 |
FloatField | 用Python的float实例来表示的浮点数 |
DateField[auto_now=False, auto_now_add=False]) |
使用Python的datetime.date实例表示的日期; 参数DateField.auto_now:每次保存对象时,自动设置该字段为当前时间,用于"最后一次修改"的时间戳,它总是使用当前日期,默认为false; 参数DateField.auto_now_add:当对象第一次被创建时自动设置当前时间,用于创建的时间戳,它总是使用当前日期,默认为false 该字段默认对应的表单控件是一个TextInput. 在管理员站点添加了一个JavaScript写的日历控件,和一个“Today"的快捷按钮,包含了一个额外的invalid_date错误消息键 auto_now_add, auto_now, and default 这些设置是相互排斥的,他们之间的任何组合将会发生错误的结果 |
TimeField | 使用Python的datetime.time实例表示的时间,参数同DateField |
DateTimeField | 使用Python的datetime.datetime实例表示的日期和时间,参数同DateField |
FileField | 一个上传文件的字段 |
ImageField | 继承了FileField的所有属性和方法,但对上传的对象进行校验,确保它是个有效的image |
通过字段选项,可以实现对字段的约束;在字段对象时通过关键字参数指定。
名称 | 解释 |
null | 如果为True,Django 将空值以NULL 存储到数据库中,默认值是 False |
blank | 如果为True,则该字段允许为空白,默认值是 False;对比:null是数据库范畴的概念,blank是表单验证证范畴的 |
db_column | 字段的名称,如果未指定,则使用属性的名称 |
db_index | 若值为 True, 则在表中会为此字段创建索引 |
default | 默认值 |
primary_key:若为 True | 则该字段会成为模型的主键字段 |
unique | 如果为 True, 这个字段在表中必须有唯一值;唯一索引 |
auto_now | 创建时生成创建时间 |
auto_now_add | 更新时自动更新当前时间 |
choices | admin: 默认元组列表,user_type=[(1, "普通用户"), (2, "VIP用户"), (3, "超级用户")];modesl.IntegerField(choices=user_type);在admin中会自动显示这几个分类,但是对表无影响,可以是任意整数 |
verbose_name | admin: 别名,支持中文 |
editable | admin: 是否可以被编辑 |
error_message | admin: 自定义错误信息 |
help_text | admin: 帮助信息 |
三、自定义管理器
objects是Manager类型的对象,用于与数据库进行交互。当定义模型类时没有指定管理器,则Django会为模型类提供一个名为objects的管理器,当为模型类指定管理器后,django不再为模型类生成名为objects的默认管理器。
管理器是Django的模型进行数据库的查询操作的接口,Django应用的每个模型都拥有至少一个管理器。
自定义管理器类主要用于两种情况:向管理器类中添加额外的方法,或者修改管理器返回的原始查询集:重写get_queryset()方法。
from django.db import models class BookInfoManager(models.Model):
"""
可以重写Model中的方法
"""
def get_queryset(self):
return super(BookInfo, self.get_queryset().filter(isdelete=False)) # 创建BookInfo
def create(self, name, pub_date):
b = BookInfo()
b.name = name
b.headline = pub_date
b.isdelete = False
return b class BookInfo(models.Model):
name = models.CharField(max_length=20)
headline = models.CharField(default="this's a python book")
isdelete = models.BooleanField(default=False)
# 自定义管理器被定义时,继承了默认管理器
manager = BookInfoManager() # BookInfo.manager.create(name="Jan")
四、数据库操作
1、多对一操作
1.批量添加
# models.py
from django.db import models class Province(models.Model):
name = models.CharField(max_length=32) class City(models.Model):
name = models.CharField(max_length=32)
pro = models.ForeignKey("Province", to_field="id", on_delete=models.CASCADE)
# app01/insert_records.py import os, django
# 添加django的环境配置
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "app.settings")
django.setup() from app01.models import Province, City city_dict = {"东莞": 2, "深圳": 2, "惠州": 2, "河源": 2, "泰安": 3, "青岛": 3, "济南": 3, "张家口": 1,"邢台": 1}
province_dict = {"河北": 1, "山东": 3, "广东": 2,}
province_records_dict = {id: Province(id=id, name=name) for name, id in province_dict.items()}
print(province_records_dict)
# 先创建Province
Province.objects.bulk_create(province_records_dict.values())
# 再创建City
city_records_list = [City(pro=province_records_dict[id], name=name) for name, id in city_dict.items()]
print(city_records_list)
City.objects.bulk_create(city_records_list)
print("ok")
2.正向查询与反向查询
# 1.all - 查找全city表中的全部记录,返回所有的querySet
City.objects.all()
# 正向查询:指定获取的字段,外表需要用外键+双下划线的形式访问外键表中的字段;如果有两个表中的字段,相当于对两个表同时进行操作
City.objects.all().values("id", "name", "pro__id", "pro_name")
# 反向查询:默认会将外键表的模型类小写当做id,相当于city__id,它同样支持表名+双下划线+字段的形式查询
Province.objects.all().values("id", "name", "city", "city__name", "city__id")
# 2.filter - 过滤器
# 正向过滤: 根据某个外键表或者外表中的字段对外表记录进行过滤查询
City.objects.all().filter(pro__name="河北") # 过滤字段
# 反向过滤: 根据某个外键表或者外表中的字段对外键表进行过滤查询
Province.objects.all().filter(name="河北")[0].city_set.all()
3、多对多操作
1.批量添加
# models.py
from django.db import models class Book(models.Model):
name = models.CharField(max_length=32) class Author(models.Model):
name = models.CharField(max_length=32)
book = models.ManyToManyField(Book, related_name="book")
import os, django
# 添加django的环境配置
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "app.settings")
django.setup() from app01.models import * Book.objects.all().delete()
Author.objects.all().delete() book_dict = {1: "Python", 2: "Go", 3: "Linux", 4: "PHP"}
author_dict = {1: "Jan", 2: "Li", 3: "wise"}
together_dict = {
"Jan": ["Python", "Go"],
"Li": ["Linux", "Go"],
"wise": ["PHP", "Go", "Python"]
}
# 根据以上信息创建ManyToMany
# 先创建两个表的记录
book_records_list = {name: Book(id=id, name=name) for id, name in book_dict.items()}
Book.objects.bulk_create(book_records_list.values())
author_records_list = {name: Author(id=id, name=name) for id, name in author_dict.items()}
Author.objects.bulk_create(author_records_list.values())
# 再根据关系写入数据库
for key, vlist in together_dict.items():
# 获取书名对应的querySet
for i in vlist:
author_records_list[key].book.add(book_records_list[i])
2、正向查询与反向查询
# 正向查找
Author.objects.get(id=1).book.all()
# 反向查找
Book.objects.get(id=1).book.all() # 这里写.book.all()是因为在Author模型类中声明了related_name,默认的话是author_set.all()
Book.objects.get(id=1).book.all().values("id", "name", "book__name")
# 遍历
for item in Author.objects.values("id", "name", "book"):
print(item["id"], item["name"], item["book"])
3、基本查询
1.返回querySet集合的方法
名称 | 解释 |
filter | 过滤器 |
exclude |
排除满足条件的对象 |
order_by | 查询结果排序 |
annotate | 分组函数,在分组后的数据集上进行操作 |
distinct | 去重 |
values | 将querySet以字典形式返回到一个查询集里 |
raw | 处理一个原始的sql语句 |
aggregate | 聚合函数,在每个记录上进行操作 |
2.返回单个对象
名称 | 函数 |
get() | 返回单个满足条件的对象 |
first() | 返回第一个对象 |
last() | 返回最后一个对象 |
exists() | 判断查询集中是否有数据,如果有则返回True |
count() | 返回当前查询的总条数 |
select_related() | 返回当前querySet的前一条和后一条数据 |
3.字段查询
实现where子名,作为方法filter()、exclude()、get()的参数。语法:属性名称__比较运算符=值。
1.exact:表示判等,大小写敏感;如果没有写“ 比较运算符”,表示判等filter(isDelete=False)
2.contains:是否包含,大小写敏感
exclude(btitle__contains='传')
3.startswith、endswith:以value开头或结尾,大小写敏感
exclude(btitle__endswith='传')
4.isnull、isnotnull:是否为null
filter(btitle__isnull=False)
5.在前面加个i表示不区分大小写,如iexact、icontains、istarswith、iendswith
6.in:是否包含在范围内
filter(pk__in=[1, 2, 3, 4, 5])
7.gt、gte、lt、lte:大于、大于等于、小于、小于等于
filter(id__gt=3)
8.对year、month、day、week_day、hour、minute、second:对日期间类型的属性进行运算
filter(bpub_date__year=1980)
filter(bpub_date__gt=date(1980, 12, 31))
9.查询的快捷方式:pk,pk表示primary key,默认的主键是id
filter(pk__lt=6)
4、跨表查询
多对一或者多对多都可以使用模型类+双下划线+字段名的形式进行跨表操作。
Author.objects.filter(book__name="Go")
Book.objects.filter(book__name="Jan")
5、聚合函数
使用aggregate()函数返回聚合函数的值,函数包括(Avg,Count,Max,Min,Sum)。
from django.db.models import Max
maxDate = list.aggregate(Max('bpub_date'))
6、其它相关
# 1. Cast,用于做类型转换
# v = models.UserInfo.objects.annotate(c=Cast('pwd', FloatField())) # 2. Coalesce,从前向后,查询第一个不为空的值
# v = models.UserInfo.objects.annotate(c=Coalesce('name', 'pwd'))
# v = models.UserInfo.objects.annotate(c=Coalesce(Value('666'),'name', 'pwd')) # 3. Concat,拼接
# models.UserInfo.objects.update(name=Concat('name', 'pwd'))
# models.UserInfo.objects.update(name=Concat('name', Value('666')))
# models.UserInfo.objects.update(name=Concat('name', Value('666'),Value('999'))) # 4.ConcatPair,拼接(仅两个参数)
# v = models.UserInfo.objects.annotate(c=ConcatPair('name', 'pwd'))
# v = models.UserInfo.objects.annotate(c=ConcatPair('name', Value('666'))) # 5.Greatest,获取比较大的值;least 获取比较小的值;
# v = models.UserInfo.objects.annotate(c=Greatest('id', 'pwd',output_field=FloatField())) # 6.Length,获取长度
# v = models.UserInfo.objects.annotate(c=Length('name')) # 7. Lower,Upper,变大小写
# v = models.UserInfo.objects.annotate(c=Lower('name'))
# v = models.UserInfo.objects.annotate(c=Upper('name')) # 8. Now,获取当前时间
# v = models.UserInfo.objects.annotate(c=Now()) # 9. substr,子序列
# v = models.UserInfo.objects.annotate(c=Substr('name',1,2)) # ########### 时间类函数 ###########
# 1. 时间截取,不保留其他:Extract, ExtractDay, ExtractHour, ExtractMinute, ExtractMonth,ExtractSecond, ExtractWeekDay, ExtractYear,
# v = models.UserInfo.objects.annotate(c=functions.ExtractYear('ctime'))
# v = models.UserInfo.objects.annotate(c=functions.ExtractMonth('ctime'))
# v = models.UserInfo.objects.annotate(c=functions.ExtractDay('ctime'))
#
# v = models.UserInfo.objects.annotate(c=functions.Extract('ctime', 'year'))
# v = models.UserInfo.objects.annotate(c=functions.Extract('ctime', 'month'))
# v = models.UserInfo.objects.annotate(c=functions.Extract('ctime', 'year_month'))
"""
MICROSECOND
SECOND
MINUTE
HOUR
DAY
WEEK
MONTH
QUARTER
YEAR
SECOND_MICROSECOND
MINUTE_MICROSECOND
MINUTE_SECOND
HOUR_MICROSECOND
HOUR_SECOND
HOUR_MINUTE
DAY_MICROSECOND
DAY_SECOND
DAY_MINUTE
DAY_HOUR
YEAR_MONTH
"""
# 2. 时间截图,保留其他:Trunc, TruncDate, TruncDay,TruncHour, TruncMinute, TruncMonth, TruncSecond, TruncYear
# v = models.UserInfo.objects.annotate(c=functions.TruncHour('ctime'))
# v = models.UserInfo.objects.annotate(c=functions.TruncDate('ctime'))
# v = models.UserInfo.objects.annotate(c=functions.Trunc('ctime','year'))
4、F对象和Q对象
1.F对象
如果需要在等号右侧需要使用当前querySet中的字段,就需要用到F对象。
from django.db.models import F
1.右侧需要用到本表字段,用F对象
Book.objects.all().update(price=F('price') + 20)
2.django支持对F()对象使用算数运算
list.filter(bread__gte=F('bcommet') * 2)
3.F()对象中还可以写作“模型类__列名”进行关联查询
list.filter(isDelete=F('heroinfo__isDelete'))
4.对于date/time字段,可与timedelta()进行运算
list.filter(bpub_date__lt=F('bpub_date') + timedelta(days=1))
2.Q对象
过滤器的方法中关键字参数查询,会合并为And进行;需要进行or查询,使用Q()对象。Q对象(django.db.models.Q)用于封装一组关键字参数,这些关键字参数与“比较运算符”中的相同。
from django.db.models import Q
1.基本操作:
Author.objects.filter(Q(name="Jan")) # 等价于Author.objects.filter(name="Jan")
2.Q对象可以使用&(and)、|(or)操作符组合起来:
Author.objects.filter(Q(name="Jan") | Q(name="Wise")) # 等价于Author.objects.filter(name__in=["Jan", "Wise"])
3.支持联表查询
Author.objects.filter(Q(book__name="Go") & Q(id__lt=2))
3.当操作符应用在两个Q对象时,会产生一个新的Q对象
list.filter(pk_ _lt=6).filter(bcommet_ _gt=10)
list.filter(Q(pk_ _lt=6) | Q(bcommet_ _gt=10))
Django(四):model的更多相关文章
- django (四) model模型
models模型 1. models 定义属性 概述 django根据属性的类型确定以下信息 ·当前选择的数据库支持字段的类型 ·渲染管理表单时使用的默认html控件 ·在管理站点最低限度的验证 dj ...
- Python之路【第二十二篇】:Django之Model操作
Django之Model操作 一.字段 AutoField(Field) - int自增列,必须填入参数 primary_key=True BigAutoField(AutoField) - bi ...
- Django之Model操作
Django之Model操作 本节内容 字段 字段参数 元信息 多表关系及参数 ORM操作 1. 字段 字段列表 AutoField(Field) - int自增列,必须填入参数 primary_ke ...
- Django的Model上都有些什么
Django的Model上都有些什么 modelinfo= ['DoesNotExist', 'MultipleObjectsReturned', '__class__', '__delattr__' ...
- django User model
django User model operation this tutorial will guide us to know how to manipulate django User model. ...
- Scrapy中使用Django的Model访问数据库
Scrapy中使用Django的Model进行数据库访问 当已存在Django项目的时候,直接引入Django的Model来使用比较简单 # 使用以下语句添加Django项目的目录到path impo ...
- django使用model创建数据库表使用的字段
Django通过model层不可以创建数据库,但可以创建数据库表,以下是创建表的字段以及表字段的参数.一.字段1.models.AutoField 自增列= int(11) 如果没有的话,默认会生成一 ...
- Django之Model组件
Model组件在django基础篇就已经提到过了,本章介绍更多高级部分. 一.回顾 1.定义表(类) ##单表 from django.db import models class user(mode ...
- django中将model转换为dict的方法
django中将model转换为dict的方法 from django.forms.models import model_to_dict from user.model import userpro ...
- Python学习---django之Model语法180124
django之Model语法[Models] 1 django默认支持sqlite,mysql, oracle,postgresql数据库. <1> sqlite django默认使 ...
随机推荐
- 如何使用socket进行java网络编程(一)
笔者进来遇到一个项目,一家公司的系统需要在完成自身业务逻辑的同时,接入到某银行的核心系统(这里准确说应该是前置机)进行一系列的账务处理,然后再将账务处理结果返回给该公司系统. 网络通信采用TCP协议. ...
- java入门——第一个java程序
来源:https://course.tianmaying.com/java-basic%2Bjava-hello-world# java的基础特征 1 Java是一种大小写敏感的语言 2 程序的文件名 ...
- JQuery Mobile - 需要注意问题!
一,JQuery Mobile 和 JQuery 版本对接,一定要选用和当前JQuery Mobile 对应版本的JQuery . 二,在台式机的模拟器和真机中的显示结果可能不一样.我在台式机中使用的 ...
- 974. Subarray Sums Divisible by K
Given an array A of integers, return the number of (contiguous, non-empty) subarrays that have a sum ...
- js闭包之我见
很久前的一个问题终于得以解决,内心是无比喜悦的,不多说,先上代码: function test(){ for(var i=0;i<5;i++){ window.onclick=function( ...
- python Udp与Tcp
一.UDP 首先导入socket 1.客户端 1.创建套接字(socket)udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)2 ...
- CDN添加流程
CDN的全称是Content Delivery Network,即内容分发网络.其基本思路是尽可能避开互联网上有可能影响数据传输速度和稳定性的瓶颈和环节,使内容传输的更快.更稳定.通过在网络各处放置节 ...
- 【xsy1156】 树套树(tree) 倍增
题目大意:给你$m$棵由$n$个点构成的全等的树$A$.这$m$棵树之间有$m-1$条边相连,组成了一棵大树. 有$q$组询问,每次询问这棵大树上两点之间的距离. $n,m,q≤10^5$ 这是一道小 ...
- 聚类系数可变无标度网络模型Holme-Kim HK模型
# -*- coding: cp936 -*- import random import networkx as nx from networkx.generators.classic import ...
- ajax--底层代码
ajax:Asynchronous JavaScript And XML,异步的js与XML.ajax并不是一种新的编程语言,而是一种使用现有标准的新方法.ajax能够在不重载整个网页的情况下与服务器 ...