目录
一、ORM (对象关系映射 Object Relational Mapping)
1-3 migrations 内 __init__.py文件修改
1、在py文件中调用Django环境(可用于orm记录操作语言的测试)
- values(*field):返回特殊的queryset类型
一、ORM (对象关系映射 Object Relational Mapping)
介绍:对pymysql模块的二次封装,进行操作mysql
优点:
- 提高了开发效率
- 可以使用代码创建表、并对表进行增删改查操作
缺点:
- 降低了执行效率
- 不可以自主创造数据库
二、表结构的创建和修改
1、表结构的创建
1-1 setting内建立数据库连接
DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', 'NAME': 'lqz', 'USER': 'root', 'PASSWORD': '123456', 'HOST': '127.0.0.1', 'PORT': 3306, 'ATOMIC_REQUEST': True, 'OPTIONS': { "init_command": "SET storage_engine=MyISAM", } } } ''' 'NAME':要连接的数据库,连接前需要创建好 'USER':连接数据库的用户名 'PASSWORD':连接数据库的密码 'HOST':连接主机,默认本机 'PORT':端口 默认3306 'ATOMIC_REQUEST': True, 设置为True统一个http请求对应的所有sql都放在一个事务中执行(要么所有都成功,要么所有都失败)。 是全局性的配置, 如果要对某个http请求放水(然后自定义事务),可以用non_atomic_requests修饰器 'OPTIONS': { "init_command": "SET storage_engine=MyISAM", } 设置创建表的存储引擎为MyISAM,INNODB '''
1-2 models.py 内创建模型
from django.db import models # 一个类就是一个表 class User(models.Model): # 自增int类型,是主键 id = models.AutoField(primary_key=True) # name 是一个varchar类型,长度是32 name = models.CharField(max_length=32) pwd = models.CharField(max_length=32)
1-3 项目 内 __init__.py文件修改
注意:
- 若只是在app文件夹下的init文件添加,则只能当前app内使用mysqldb
- 若在总项目文件夹下的init文件中添加,所有app的数据库都使用mysqldb
import pymysql pymysql.install_as_MySQLdb()
1-4 迁移命令的两种执行方式
- 方式一、终端命令
python3 manage.py makemigrations --- 记录数据库的修改记录
python3 manage.py migrate ---- 数据修改同步数据库- 方式二、pycharm工具栏操作
工具栏 -- tools--->Run manage.py Task
makemigrations
migrate- 注意:
1 数据库迁移记录都在 app01下的migrations里
2 使用showmigrations命令可以查看没有执行migrate的文件(python manage.py showmigrations)
3 makemigrations是生成一个文件,migrate是将更改提交到数据量
2、表结构的修改
2-1 增加字段
from django.db import models # 一个类就是一个表 class User(models.Model): # 自增int类型,是主键 id = models.AutoField(primary_key=True) # name 是一个varchar类型,长度是32 name = models.CharField(max_length=32) pwd = models.CharField(max_length=32) # 在原有结构上添加字段,必须带有默认值 phone=models.CharField(max_length=64,default='120')
2-2 删除字段
from django.db import models # 一个类就是一个表 class User(models.Model): # 自增int类型,是主键 id = models.AutoField(primary_key=True) # name 是一个varchar类型,长度是32 name = models.CharField(max_length=32) pwd = models.CharField(max_length=32) # 在原有结构上注释字段 # phone=models.CharField(max_length=64,default='120') ''' 文件修改完成,执行两句迁移命令 '''
2-3 修改字段
from django.db import models # 一个类就是一个表 class User(models.Model): # 自增int类型,是主键 id = models.AutoField(primary_key=True) # name 是一个varchar类型,长度是32 name = models.CharField(max_length=32) pwd = models.CharField(max_length=32) # 在原有结构上修改结构内容 phone=models.CharField(max_length=64,default='11111111111') ''' 文件修改完成,执行两句迁移命令 '''
3、模型内字段类型
- AutoField(Field) - int自增列,必须填入参数 primary_key=True
- BigAutoField(AutoField) - bigint自增列,必须填入参数 primary_key=True
//注:当model中如果没有自增列,则自动会创建一个列名为id的列 from django.db import models class UserInfo(models.Model): # 自动创建一个列名为id的且为自增的整数列 username = models.CharField(max_length=32) class Group(models.Model): # 自定义自增列 nid = models.AutoField(primary_key=True) name = models.CharField(max_length=32)
mallIntegerField(IntegerField): - 小整数 -32768 ~ 32767
PositiveSmallIntegerField(PositiveIntegerRelDbTypeMixin, IntegerField) - 正小整数 0 ~ 32767
IntegerField(Field) - 整数列(有符号的) -2147483648 ~ 2147483647
PositiveIntegerField(PositiveIntegerRelDbTypeMixin, IntegerField) - 正整数 0 ~ 2147483647
BigIntegerField(IntegerField): - 长整型(有符号的) -9223372036854775808 ~ 9223372036854775807
//自定义无符号整数字段 class UnsignedIntegerField(models.IntegerField): def db_type(self, connection): return 'integer UNSIGNED' ''' PS: 返回值为字段在数据库中的属性,Django字段默认的值为: 'AutoField': 'integer AUTO_INCREMENT', 'BigAutoField': 'bigint AUTO_INCREMENT', 'BinaryField': 'longblob', 'BooleanField': 'bool', 'CharField': 'varchar(%(max_length)s)', 'CommaSeparatedIntegerField': 'varchar(%(max_length)s)', 'DateField': 'date', 'DateTimeField': 'datetime', 'DecimalField': 'numeric(%(max_digits)s, %(decimal_places)s)', 'DurationField': 'bigint', 'FileField': 'varchar(%(max_length)s)', 'FilePathField': 'varchar(%(max_length)s)', 'FloatField': 'double precision', 'IntegerField': 'integer', 'BigIntegerField': 'bigint', 'IPAddressField': 'char(15)', 'GenericIPAddressField': 'char(39)', 'NullBooleanField': 'bool', 'OneToOneField': 'integer', 'PositiveIntegerField': 'integer UNSIGNED', 'PositiveSmallIntegerField': 'smallint UNSIGNED', 'SlugField': 'varchar(%(max_length)s)', 'SmallIntegerField': 'smallint', 'TextField': 'longtext', 'TimeField': 'time', 'UUIDField': 'char(32)', '''
BooleanField(Field) - 布尔值类型
NullBooleanField(Field): - 可以为空的布尔值
CharField(Field) - 字符类型 - 必须提供max_length参数, max_length表示字符长度
TextField(Field) - 文本类型
EmailField(CharField): - 字符串类型,Django Admin以及ModelForm中提供验证机制
IPAddressField(Field) - 字符串类型,Django Admin以及ModelForm中提供验证 IPV4 机制
GenericIPAddressField(Field) - 字符串类型,Django Admin以及ModelForm中提供验证 Ipv4和Ipv6
- 参数:
protocol,用于指定Ipv4或Ipv6, 'both',"ipv4","ipv6"
unpack_ipv4, 如果指定为True,则输入::ffff:192.0.2.1时候,可解析为192.0.2.1,开启刺功能,需要 protocol="both"URLField(CharField) - 字符串类型,Django Admin以及ModelForm中提供验证 URL
SlugField(CharField) - 字符串类型,Django Admin以及ModelForm中提供验证支持 字母、数字、下划线、连接符(减号)
CommaSeparatedIntegerField(CharField) - 字符串类型,格式必须为逗号分割的数字
UUIDField(Field) - 字符串类型,Django Admin以及ModelForm中提供对UUID格式的验证
FilePathField(Field) - 字符串,Django Admin以及ModelForm中提供读取文件夹下文件的功能
- 参数:
path, 文件夹路径
match=None, 正则匹配
recursive=False, 递归下面的文件夹
allow_files=True, 允许文件
allow_folders=False, 允许文件夹FileField(Field) - 字符串,路径保存在数据库,文件上传到指定目录
- 参数:
upload_to = "" 上传文件的保存路径
storage = None 存储组件,默认django.core.files.storage.FileSystemStorageImageField(FileField) - 字符串,路径保存在数据库,文件上传到指定目录
- 参数:
upload_to = "" 上传文件的保存路径
storage = None 存储组件,默认
django.core.files.storage.FileSystemStorage
width_field=None, 上传图片的高度保存的数据库字段名(字符串)
height_field=None 上传图片的宽度保存的数据库字段名(字符串)DateTimeField(DateField) - 日期+时间格式 YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ]
DateField(DateTimeCheckMixin, Field) - 日期格式 YYYY-MM-DD
TimeField(DateTimeCheckMixin, Field) - 时间格式 HH:MM[:ss[.uuuuuu]]
DurationField(Field) - 长整数,时间间隔,数据库中按照bigint存储,ORM中获取的值为datetime.timedelta类型
FloatField(Field) - 浮点型
DecimalField(Field) - 10进制小数
- 参数:
max_digits,小数总长度
decimal_places,小数位长度BinaryField(Field) - 二进制类型
4、字段参数
- (0) null 如果为True,Django 将用NULL 来在数据库中存储空值。 默认值是 False.
- (1) blank 如果为True,该字段允许不填。默认为False。 要注意,这与 null 不同。null纯粹是数据库范畴的,而 blank 是数据验证范畴的。 如果一个字段的blank=True,表单的验证将允许该字段是空值。如果字段的blank=False,该字段就是必填的。
- (2) default 字段的默认值。可以是一个值或者可调用对象。如果可调用 ,每有新对象被创建它都会被调用。
- (3) primary_key 如果为True,那么这个字段就是模型的主键。如果你没有指定任何一个字段的primary_key=True, Django 就会自动添加一个IntegerField字段做为主键,所以除非你想覆盖默认的主键行为, 否则没必要设置任何一个字段的primary_key=True。
- (4) unique 如果该值设置为 True, 这个数据字段的值在整张表中必须是唯一的
- (5) choices 由二元组组成的一个可迭代对象(例如,列表或元组),用来给字段提供选择项。 如果设置了choices ,默认的表单将是一个选择框而不是标准的文本框,<br>而且这个选择框的选项就是choices 中的选项。
5、元信息
class UserInfo(models.Model): nid = models.AutoField(primary_key=True) username = models.CharField(max_length=32) class Meta: # 数据库中生成的表名称 默认 app名称 + 下划线 + 类名 db_table = "table_name" # 联合索引 index_together = [ ("pub_date", "deadline"), ] # 联合唯一索引 unique_together = (("driver", "restaurant"),) # admin中显示的表名称 verbose_name # verbose_name加s verbose_name_plural
三、单表记录操作
1、在py文件中调用Django环境(可用于orm记录操作语言的测试)
import os if __name__ == '__main__': os.environ.setdefault("DJANGO_SETTINGS_MODULE", "day76orm.settings") import django django.setup() from app01 import models # 记录的操作 book=models.Book.objects.create(name='红楼梦',price=23.8,publish='人民出版社',author='曹雪芹',create_data='2018-09-17') print(book.name) …… ……
2、查(API)
总结:
- python数据精度存在盲点,使用查询数字类型的时候,注意转换的sql语句所传输的数字是否精确
- 可以对queryset对象使用.query方法调用,可以查询最终传输到数据的纯生sql语句
- 查询得到的queryset可以进行后续的查询方法,通过.进行调用
all() - models.User.objects.all() 查询所有结果,得到的是一个queryset对象(列表),列表内存储对象。 filter(**kwargs)
-- models.User.objects.filter(name='红楼梦').first()包含与所给筛选条件匹配的对象,返回queryset对象 get(**kwargs)
-- models.User.objects.get(name='红楼梦')
返回筛选条件匹配的对象,且返回结果有且只有一个;若存在符合对象超过一个或者不存在,抛出异常 exclude(*field)
-- models.User.objects.exclude(name='红楼梦')
包含了所有与筛选条件不匹配的对象,返回queryset对象 order_by(*field)
-- models.User.objects.all.order_by('id')
-- models.User.objects.all.order_by('-id','name')
对查询结果排序 ('-id'),默认升序,加- 降序。多个过滤条件可以同时共用,返回queryset对象 reverse()
-- models.User.objects.all().reverse()
对查询结果反向排序,返回queryset对象 count()
-- models.User.objects.all().count()
queryset为调用对象,返回数据库中匹配查询(QuerySet)的对象数量 first()
- models.User.objects.first()
返回第一条记录 last()
-models.User.objects.last()
返回最后一条记录 exists() 若queryset包含数据,返回True,否则False,返回布尔类型 values(*field)
-- models.User.objects.all().values('name')
返回一个ValueQuerySet - 一个特殊的QuerySet,运行后得到一个可迭代的字典序列
<QuerySet [{'name': '红楼梦'}, {'name': '水浒传'}, {'name': '西游记'}]>values_list(*field)
-- models.User.objects.all().values_list('name','id')
同values()相似,返回一个元组列表
<QuerySet [('红楼梦', Decimal('23.80')), ('水浒传', Decimal('99.80')), ('西游记', Decimal('73.80'))]>distinct()
-- models.User.objects.all().distinct()
-- models.Book.objects.all().values('name').distinct()
从返回的结果中剔除重复记录;distinct seletc * 的时候没有意义,只要存在唯一的字段(id段等)都没有去重意义 - filter() - 返回queryset对象
# 查询名字叫西游记的这本书,返回单个对象 ret = models.Book.objects.filter(name='西游记').first() print(ret) print(type(ret)) # 支持类列表的查询方式 ret = models.Book.objects.filter(name='西游记')[1] # 类列表的查询方式,不支持负数,只支持正数 ret = models.Book.objects.filter(name='西游记')[-1] # filter内可以传多个参数,用逗号分隔,他们之间是and的关系 # 返回queryset # 价格使用字符串,防止精度不准确,导致无法进行查询 ret = models.Book.objects.filter(name='西游记', price='73.8') print(ret) print(type(ret)) # ret.query -->queryset对象打印sql print(ret.query) ''' SELECT `app01_book`.`id`, `app01_book`.`name`, `app01_book`.`price`, `app01_book`.`publish`, `app01_book`.`author`, `app01_book`.`create_data` FROM `app01_book` WHERE ( `app01_book`.`name` = 西游记 AND `app01_book`.`price` = 73.8 ) '''
- 基于filter的双下划线模糊查询
# filter(字段名__gt='') ---- 大于 # 查询价格大于89 的书 ret=models.Book.objects.filter(price__gt='89') # filter(字段名__lt='') ---- 小于 # 查询价格小于89 的书 ret=models.Book.objects.filter(price__lt='89') # ret=models.Book.objects.filter(price__lt='89',price='89') --- 错误的小于等于 # filter(字段名__lte='') ---- 小于等于 ret=models.Book.objects.filter(price__lte='89') # filter(字段名__gte='') ---- 大于等于 ret = models.Book.objects.filter(price__gte='89') # filter(字段名__in='') ---- 字段存在列表中 ret=models.Book.objects.filter(price__in=['23.8','89','100']) # filter(字段名__range='') ---- 字段数据在范围内(between and) ret=models.Book.objects.filter(price__range=[50,100]) # filter(字段名__contains='') ---- 字段数据包含内容 模糊查询 like % % # 查询名字有'%红%'的书 ret=models.Book.objects.filter(name__contains='红') # filter(字段名__icontains='') ---- 字段数据包含内容,并且忽略大小写 模糊查询 like % % # 查询名字带p的书,忽略大小写 ret=models.Book.objects.filter(name__icontains='P') # filter(字段名__startswith='') ---- 字段数据以内容开头 ret=models.Book.objects.filter(name__startswith='红') # filter(字段名__endswith='') ---- 字段数据以内容结尾 ret=models.Book.objects.filter(name__endswith='梦') # filter(字段名__year='') ---- 查询字段内容以指定年份查询 ret=models.Book.objects.filter(create_data__year='2018') # filter(字段名__month='') ---- 查询字段内容以指定月份查询 ret = models.Book.objects.filter(create_data__month='9') # filter(字段名__day='') ---- 查询字段内容以指定日期查询 ret = models.Book.objects.filter(create_data__day='8')
- values(*field):返回特殊的queryset类型
# values(*field): queryset对象里套字典 ret=models.Book.objects.all().values('name','price') print(ret) # <QuerySet [{'name': '红楼梦', 'price': Decimal('23.80')}, {'name': '水浒传', 'price': Decimal('99.80')}, {'name': '西游记', 'price': Decimal('73.80')}]> print(ret[1]) # {'name': '水浒传'} print(ret.query) ''' SELECT `app01_book`.`name`, `app01_book`.`price` FROM `app01_book` ''' ret=models.Book.objects.all().values('name') print(ret) # <QuerySet [{'name': '红楼梦'}, {'name': '水浒传'}, {'name': '西游记'}]> print(ret[1]) # {'name': '水浒传'} print(ret.query) ''' SELECT `app01_book`.`name` FROM `app01_book` '''
3、增(两种方式)
方式一、create方法创建记录对象
name=request.POST.get('name') pwd=request.POST.get('password') addr=request.POST.get('addr') user=models.User.objects.create(name=name,password=pwd,address=addr)
方式二、创建对象,save方法保存
name=request.POST.get('name') pwd=request.POST.get('password') addr=request.POST.get('addr') user=models.User(name=name,password=pwd,address=addr) user.save()
4、改(两种方式)
1、方式一:update()方法
注意:update方法对于任何结果集(queryset)有效,可以同时更新多条记录,使用update()方法会返回一个整数数值,表示受影响的记录条数。
name=request.POST.get('name') pwd=request.POST.get('password') addr=request.POST.get('addr') models.User.objects.filter(id=id).update(name=name,password=pwd,address=addr)
2、方式二、修改对象,save 保存
book = models.Book.objects.filter(name='西游记').first() book.price=89 book.save()
5、删(delete())
1、所有对象删除
models.User.objects.all().delete()
2、根据记录删除
id = request.GET.get('id') ret = models.User.objects.filter(id=id).delete() ret = models.Book.objects.filter(name='西游记').first() ret.delete()