Django/MySql数据库基本操作&ORM操作
数据库配置:

#第一步在settings里面 DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', 'NAME':'dbname', 'USER': 'root', 'PASSWORD': 'xxx', 'HOST': 'xx', 'PORT': 6666, } } #第二步 # 如下设置放置的与project同名的配置的 __init__.py文件中 import pymysql pymysql.install_as_MySQLdb()
数据库基本操作

conn = pymysql.connect(host='localhost', port=3307, user='root', passwd='88888', db='learing',charset='utf8') # 创建连接 cursor = conn.cursor(cursor=pymysql.cursors.DictCursor) # 创建游标 cursor.execute("select id,title from class") #执行SQL语句 #cursor.fetchone() #是个字典 #conn.commit() 增、删、改 class_list=cursor.fetchall() cursor.close() conn.close() #--------大量重复后可以将其功能写成一个类 class SqlHelper(): # def __init__(self): # self.connect() #也可以把那个链接的内容写成配置文件(活的) #只要一建立对象,就直接链接上 def connect(self): self.conn=pymysql.connect(host='127.0.0.1', port=3306, user='root', passwd='94188', db='exercise',charset='utf8') self.cursor = self.conn.cursor(cursor=pymysql.cursors.DictCursor) def get_list(self,sql,args): self.cursor.execute(sql,args) result=self.cursor.fetchall() return(result) def get_one(self,sql,args): self.cursor.execute(sql,args) result = self.cursor.fetchone() return (result) def modify(self,sql,args): self.cursor.execute(sql,args) self.conn.commit() def multiple_modify(self,sql,args): #self.cursor.executemany('insert into ba(id,name)'value(%s,%s),[(1,'abv'),(2,'ffff')]) self.cursor.executemany(sql,args) self.conn.commit() def add_create(self,sql,args): self.cursor.execute(sql,args) self.conn.commit() return self.cursor.lastrowid #获取最后的一个id并且返回 def close(self): self.cursor.close() # 关闭连接 self.conn.close() #后面使用建立个类的对象,调用其方法就行 obj = SqlHelper() obj.connect() obj.get_list() ... obj.close()
ORM操作
ORM利用pymysql等第三方工具连接数据库
Django默认连接SQLlite(文件型数据库db.sqlite3)
所以要把setting里面修改为
DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', 'NAME': 'Kant', } } #这个数据库要事先创建好
默认用的是mysql-->MySQLDB(下面方法修改Django默认连接方式)
# 如下设置放置的与project同名的配置的 __init__.py文件中 import pymysql pymysql.install_as_MySQLdb()
在目录app01--models.py里面 写上对应的类,然后生成表
class UserGroup(models.Model): title=models.CharField(max_length=32) #生成的表会自动带id属性, #然后顺序执行下面个代码(每次修改表都要顺序执行一遍) #python manage.py makemigrations #python manage.py migrate
基本操作语句
models.UserInfo.objects.create(user='程颢',password=12306,age=365,ug_id=1) #增加 models.UserGroup.objects.filter(id=2).delete() #删除 models.UserGroup.objects.filter(id=1).update(title='明道先生') #修改 models.UserGroup.objects.filter(id=2).first()
resdult=models.UserInfo.objects.all()
models.Tb1.objects.get(id=123) #获取单条数据,不存在则报错,不推荐
#查找
补充语句(.values() & .all() & .filter(**condition) )
resdult=models.UserInfo.objects.all().values('user','age') # 字典类型python for row in resdult: print(row,row['user']) #从完整表找出其'user','age',以之为key构造关于其对应内容的字典 #格式为:{'user': '程颐', 'age': 18, } resdult=models.UserInfo.objects.all() #<QuerySet [<UserInfo: 1-程颐>, <UserInfo: 2-王阳明>]> #拿到表全部数据,形式类似列表,可通过循环或者.values获取相关分量 resdult=models.UserInfo.objects.all().first #取出第一个对象,相当于一行(一个元组) #可以通过(.属性名)来获取相关分量
condition={'xx':'xx','yy':'yy'}
models.UserGroup.objects.filter(**condition)
#还可以传字典,查询的时候是and的关系
进阶操作(神奇双下划线__进行数据库操作)

# 获取个数 # # models.Tb1.objects.filter(name='seven').count() # 大于,小于 # # models.Tb1.objects.filter(id__gt=1) # 获取id大于1的值 # models.Tb1.objects.filter(id__gte=1) # 获取id大于等于1的值 # models.Tb1.objects.filter(id__lt=10) # 获取id小于10的值 # models.Tb1.objects.filter(id__lte=10) # 获取id小于10的值 # models.Tb1.objects.filter(id__lt=10, id__gt=1) # 获取id大于1 且 小于10的值 # in # # models.Tb1.objects.filter(id__in=[11, 22, 33]) # 获取id等于11、22、33的数据 # models.Tb1.objects.exclude(id__in=[11, 22, 33]) # not in # isnull # Entry.objects.filter(pub_date__isnull=True) # contains # # models.Tb1.objects.filter(name__contains="ven") # models.Tb1.objects.filter(name__icontains="ven") # icontains大小写不敏感 # models.Tb1.objects.exclude(name__icontains="ven") # range # # models.Tb1.objects.filter(id__range=[1, 2]) # 范围bettwen and # 其他类似 # # startswith,istartswith, endswith, iendswith, # order by # # models.Tb1.objects.filter(name='seven').order_by('id') # asc # models.Tb1.objects.filter(name='seven').order_by('-id') # desc # group by # # from django.db.models import Count, Min, Max, Sum # models.Tb1.objects.filter(c1=1).values('id').annotate(c=Count('num')) # SELECT "app01_tb1"."id", COUNT("app01_tb1"."num") AS "c" FROM "app01_tb1" WHERE "app01_tb1"."c1" = 1 GROUP BY "app01_tb1"."id" # limit 、offset # # models.Tb1.objects.all()[10:20] # regex正则匹配,iregex 不区分大小写 # # Entry.objects.get(title__regex=r'^(An?|The) +') # Entry.objects.get(title__iregex=r'^(an?|the) +') # date # # Entry.objects.filter(pub_date__date=datetime.date(2005, 1, 1)) # Entry.objects.filter(pub_date__date__gt=datetime.date(2005, 1, 1)) # year # # Entry.objects.filter(pub_date__year=2005) # Entry.objects.filter(pub_date__year__gte=2005) # month # # Entry.objects.filter(pub_date__month=12) # Entry.objects.filter(pub_date__month__gte=6) # day # # Entry.objects.filter(pub_date__day=3) # Entry.objects.filter(pub_date__day__gte=3) # week_day # # Entry.objects.filter(pub_date__week_day=2) # Entry.objects.filter(pub_date__week_day__gte=2) # hour # # Event.objects.filter(timestamp__hour=23) # Event.objects.filter(time__hour=5) # Event.objects.filter(timestamp__hour__gte=12) # minute # # Event.objects.filter(timestamp__minute=29) # Event.objects.filter(time__minute=46) # Event.objects.filter(timestamp__minute__gte=29) # second # # Event.objects.filter(timestamp__second=31) # Event.objects.filter(time__second=2) # Event.objects.filter(timestamp__second__gte=31) 进阶操作
F、Q、extra

###F可把表里面同一属性集体增减,比如全部人工资增加1000 from django.db.models import F models.Tb1.objects.update(salary=F('salary')+1000) ###Q可以多复杂条件同时查询(同时存在and & or) from django.db.models import Q #Q是写在.filter()里面 方法一: Q(id=10) Q(id=8) | Q(id=10) #or Q(id=8) & Q(id=10) #and Q(Q(nid=8) | Q(nid__gt=10)) & Q(caption='root') models.UserInfo.objects.filter(Q(nid=1) | Q(nid=3) ).all().values('user','age',).first()['user'] 方法二: # q1 = Q() # q1.connector = 'OR' # q1.children.append(('id', 1)) # q1.children.append(('id', 10)) # q1.children.append(('id', 9)) #q1内部加这么多条件通过OR连接 # q2 = Q() # q2.connector = 'OR' # q2.children.append(('c1', 1)) # q2.children.append(('c1', 10)) # q2.children.append(('c1', 9)) #q2内部加这么多条件通过OR连接 con = Q() con.add(q1, 'AND') con.add(q2, 'AND') #con内部加这么多条件通过AND连接 #以便应对组合查询 #可以写个字典,动态生成这个查询 #models.Tb1.objects.filter(con) ###extra,额外的 # extra(self, select=None,select_params=None, where=None, params=None, tables=None, order_by=None, ) # Entry.objects.extra(select={'new_id': "select col from sometable where othercol > %s"}, select_params=(1,)) # Entry.objects.extra(where=['headline=%s'], params=['Lennon']) #where跟 params匹配用 # Entry.objects.extra(where=["foo='a' OR bar = 'a'", "baz = 'a'"]) #列表元素跟元素之间通过and连接,元素内部可以用or连接 # Entry.objects.extra(select={'new_id': "select id from tb where id > %s"}, select_params=(1,), order_by=['-nid']) # Entry.objects.extra(tables=['app01_usertype'],where=[]) #相当于select * from Entry,app01_usertype #笛卡尔积 v=models.UserInfo.objects.all().extra(select={'n':'select count(1) from app01_UserGroup where id>%s and id<%s' },select_params=[1,4]) for i in v: print(i.user,i.n) #占位符号多的话可以挨个加, 往后面加就行 #这个i.n为新的字段(列)会加到查询的表中 extra #可以全部用上 models.UserInfo.objects.extra ( select={ 'newid' : 'select count(1) from app01_ usertype where id>&s'}, select_ params=[1,] , where =['age>%s'] , params= [18,], order_by=['-age'], tables= ['app01_ usertype'] ) 相当于: select app01_userinfo.id, (select count(1) from app01_usertype where id>1) as newid from app01_userinfo, app01_ usertype where app01_ userinfo.age > 18 order by app01_ userinfo.age desc # 执行原生SQL # from django.db import connection, connections # cursor = connection.cursor() #默认的数据库 # cursor = connections['default'].cursor() #指定的数据库 settings里面可以DATABASES可以有多个数据库 # cursor.execute("""SELECT * from auth_user where id = %s""", [1]) # row = cursor.fetchone() # row = cursor.fetchall()
models. xxx.objects.** . **可以是一些操作(多)

################################################################## # PUBLIC METHODS THAT ALTER ATTRIBUTES AND RETURN A NEW QUERYSET # ################################################################## def all(self) # 获取所有的数据对象 def filter(self, *args, **kwargs) # 条件查询 # 条件可以是:参数,字典,Q def exclude(self, *args, **kwargs) # 条件查询 # 条件可以是:参数,字典,Q def select_related(self, *fields) 性能相关:表之间进行join连表操作,一次性获取关联的数据。 model.tb.objects.all().select_related() model.tb.objects.all().select_related('外键字段') model.tb.objects.all().select_related('外键字段__外键字段') def prefetch_related(self, *lookups) 性能相关:多表连表操作时速度会慢,使用其执行多次SQL查询在Python代码中实现连表操作。 # 获取所有用户表 # 获取用户类型表where id in (用户表中的查到的所有用户ID) models.UserInfo.objects.prefetch_related('外键字段') from django.db.models import Count, Case, When, IntegerField Article.objects.annotate( numviews=Count(Case( When(readership__what_time__lt=treshold, then=1), output_field=CharField(), )) ) students = Student.objects.all().annotate(num_excused_absences=models.Sum( models.Case( models.When(absence__type='Excused', then=1), default=0, output_field=models.IntegerField() ))) def annotate(self, *args, **kwargs) # 用于实现聚合group by查询 from django.db.models import Count, Avg, Max, Min, Sum v = models.UserInfo.objects.values('u_id').annotate(uid=Count('u_id')) # SELECT u_id, COUNT(ui) AS `uid` FROM UserInfo GROUP BY u_id v = models.UserInfo.objects.values('u_id').annotate(uid=Count('u_id')).filter(uid__gt=1) # SELECT u_id, COUNT(ui_id) AS `uid` FROM UserInfo GROUP BY u_id having count(u_id) > 1 v = models.UserInfo.objects.values('u_id').annotate(uid=Count('u_id',distinct=True)).filter(uid__gt=1) # SELECT u_id, COUNT( DISTINCT ui_id) AS `uid` FROM UserInfo GROUP BY u_id having count(u_id) > 1 def distinct(self, *field_names) # 用于distinct去重 models.UserInfo.objects.values('nid').distinct() # select distinct nid from userinfo 注:只有在PostgreSQL中才能使用distinct进行去重 def order_by(self, *field_names) # 用于排序 models.UserInfo.objects.all().order_by('-id','age') def extra(self, select=None, where=None, params=None, tables=None, order_by=None, select_params=None) # 构造额外的查询条件或者映射,如:子查询 Entry.objects.extra(select={'new_id': "select col from sometable where othercol > %s"}, select_params=(1,)) Entry.objects.extra(where=['headline=%s'], params=['Lennon']) Entry.objects.extra(where=["foo='a' OR bar = 'a'", "baz = 'a'"]) Entry.objects.extra(select={'new_id': "select id from tb where id > %s"}, select_params=(1,), order_by=['-nid']) def reverse(self): # 倒序 models.UserInfo.objects.all().order_by('-nid').reverse() # 注:如果存在order_by,reverse则是倒序,如果多个排序则一一倒序 def defer(self, *fields): models.UserInfo.objects.defer('username','id') 或 models.UserInfo.objects.filter(...).defer('username','id') #映射中排除某列数据 def only(self, *fields): #仅取某个表中的数据 models.UserInfo.objects.only('username','id') 或 models.UserInfo.objects.filter(...).only('username','id') def using(self, alias): 指定使用的数据库,参数为别名(setting中的设置) ################################################## # PUBLIC METHODS THAT RETURN A QUERYSET SUBCLASS # ################################################## def raw(self, raw_query, params=None, translations=None, using=None): # 执行原生SQL models.UserInfo.objects.raw('select * from userinfo') # 如果SQL是其他表时,必须将名字设置为当前UserInfo对象的主键列名 models.UserInfo.objects.raw('select id as nid from 其他表') # 为原生SQL设置参数 models.UserInfo.objects.raw('select id as nid from userinfo where nid>%s', params=[12,]) # 将获取的到列名转换为指定列名 name_map = {'first': 'first_name', 'last': 'last_name', 'bd': 'birth_date', 'pk': 'id'} Person.objects.raw('SELECT * FROM some_other_table', translations=name_map) # 指定数据库 models.UserInfo.objects.raw('select * from userinfo', using="default") ################### 原生SQL ################### from django.db import connection, connections cursor = connection.cursor() # cursor = connections['default'].cursor() cursor.execute("""SELECT * from auth_user where id = %s""", [1]) row = cursor.fetchone() # fetchall()/fetchmany(..) def values(self, *fields): # 获取每行数据为字典格式 def values_list(self, *fields, **kwargs): # 获取每行数据为元祖 def dates(self, field_name, kind, order='ASC'): # 根据时间进行某一部分进行去重查找并截取指定内容 # kind只能是:"year"(年), "month"(年-月), "day"(年-月-日) # order只能是:"ASC" "DESC" # 并获取转换后的时间 - year : 年-01-01 - month: 年-月-01 - day : 年-月-日 models.DatePlus.objects.dates('ctime','day','DESC') def datetimes(self, field_name, kind, order='ASC', tzinfo=None): # 根据时间进行某一部分进行去重查找并截取指定内容,将时间转换为指定时区时间 # kind只能是 "year", "month", "day", "hour", "minute", "second" # order只能是:"ASC" "DESC" # tzinfo时区对象 models.DDD.objects.datetimes('ctime','hour',tzinfo=pytz.UTC) models.DDD.objects.datetimes('ctime','hour',tzinfo=pytz.timezone('Asia/Shanghai')) """ pip3 install pytz import pytz pytz.all_timezones pytz.timezone(‘Asia/Shanghai’) """ def none(self): # 空QuerySet对象 #################################### # METHODS THAT DO DATABASE QUERIES # #################################### def aggregate(self, *args, **kwargs): # 聚合函数,获取字典类型聚合结果 from django.db.models import Count, Avg, Max, Min, Sum result = models.UserInfo.objects.aggregate(k=Count('u_id', distinct=True), n=Count('nid')) ===> {'k': 3, 'n': 4} def count(self): # 获取个数 def get(self, *args, **kwargs): # 获取单个对象 def create(self, **kwargs): # 创建对象 def bulk_create(self, objs, batch_size=None): # 批量插入 # batch_size表示一次插入的个数 objs = [ models.DDD(name='r11'), models.DDD(name='r22') ] models.DDD.objects.bulk_create(objs, 10) def get_or_create(self, defaults=None, **kwargs): # 如果存在,则获取,否则,创建 # defaults 指定创建时,其他字段的值 obj, created = models.UserInfo.objects.get_or_create(username='root1', defaults={'email': '1111111','u_id': 2, 't_id': 2}) def update_or_create(self, defaults=None, **kwargs): # 如果存在,则更新,否则,创建 # defaults 指定创建时或更新时的其他字段 obj, created = models.UserInfo.objects.update_or_create(username='root1', defaults={'email': '1111111','u_id': 2, 't_id': 1}) def first(self): # 获取第一个 def last(self): # 获取最后一个 def in_bulk(self, id_list=None): # 根据主键ID进行查找 id_list = [11,21,31] models.DDD.objects.in_bulk(id_list) def delete(self): # 删除 def update(self, **kwargs): # 更新 def exists(self): # 是否有结果 其他操作
连表操作(了不起的双下划线、反查)
性能优化
resdult=models.UserInfo.objects.all() for row in resdult: print(row.name,row.ut.title) #row.ut.title是通过外键ut跨表后查询另外表中对应的titile属性 #存在问题:这样要执行很多次数据库操作,比较耗资源

#改进1.查询一次,生成个字典,然后通过索引取值 resdult=models.UserInfo.objects.all().values('user','age','password') #.values字典类型 每一个元素都是一个字典(包含一行数据) for row in resdult: print(row,row['user']) #通过索引取值 #改进2.select_related主动做连表查询一次 (数据量小的时候可以用) resdult=models.UserInfo.objects.all().select_related('ut','gp',...) #直接与外键('ut','gp')连接的表(可以多个)连接起来 [一次就好] for row in resdult: #row是对象 print(row.name,row.ut.title) # 这样就不同发额外sql请求 #与下面的prefetch_related比较: #优点:节省硬盘空间 #缺点:连表性能差(用户量大的时候) #改进3:prefetch_related不做连表,做两次查询 #一次查询UserInfo整合结果集(去重),再根据已知条件查一次ut外键相关的那个表,然后两者结果合一。(数据量大的时候用) resdult=models.UserInfo.objects.all().prefetch_related('ut') for row in resdult: #row是对象 print(row.name,row.ut.title) # 这样就不同发额外sql请求
标签:
Django
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
· 字符编码:从基础到乱码解决
· 提示词工程——AI应用必不可少的技术