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() 
View Code
复制代码

数据库基本操作

复制代码
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()
View Code
复制代码

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)

进阶操作
View Code
复制代码

 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() 
View Code
复制代码

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):
   # 是否有结果

其他操作
View Code
复制代码

连表操作(了不起的双下划线、反查)

 

点击此处跳转

 

 性能优化

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请求
View Code
复制代码

 

 

 

 

 

posted @   磕伴  阅读(248)  评论(0编辑  收藏  举报
编辑推荐:
· 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应用必不可少的技术
点击右上角即可分享
微信分享提示