zoukankan      html  css  js  c++  java
  • 【python】-- Django ORM(基础)

    Django ORM(基础)

    Django 框架十分强大,自带数据库操作功能。Django 跟 SQLAchemy 一样,也是通过ORM(Object Relational Mapping,关系对象映射)的方式对数据库进行操作,django中遵循 Code Frist (根据代码中定义的类来自动生成数据库表)的原则。

     

    一、创建表

    1、在SQLite中创建表

    1.1、在app中的models.py中先写类:

    from django.db import models
    # Create your models here.
    
    
    class UserInfo(models.Model):
        # id列,Django框架会默认生成id(自增,主键),也可以通过AutoField类型自定义主键,不过Django框架默认生成ID列会失效
        # 用户名列,字符串类型,最大长度长度
        username = models.CharField(max_length=32)
        password = models.CharField(max_length=64)
    
      1  AutoField(Field)
      2         - int自增列,必须填入参数 primary_key=True
      3 
      4     BigAutoField(AutoField)
      5         - bigint自增列,必须填入参数 primary_key=True
      6 
      7         注:当model中如果没有自增列,则自动会创建一个列名为id的列
      8         from django.db import models
      9 
     10         class UserInfo(models.Model):
     11             # 自动创建一个列名为id的且为自增的整数列
     12             username = models.CharField(max_length=32)
     13 
     14         class Group(models.Model):
     15             # 自定义自增列
     16             nid = models.AutoField(primary_key=True)
     17             name = models.CharField(max_length=32)
     18 
     19     SmallIntegerField(IntegerField):
     20         - 小整数 -3276832767
     21 
     22     PositiveSmallIntegerField(PositiveIntegerRelDbTypeMixin, IntegerField)
     23         - 正小整数 032767
     24     IntegerField(Field)
     25         - 整数列(有符号的) -21474836482147483647
     26 
     27     PositiveIntegerField(PositiveIntegerRelDbTypeMixin, IntegerField)
     28         - 正整数 02147483647
     29 
     30     BigIntegerField(IntegerField):
     31         - 长整型(有符号的) -92233720368547758089223372036854775807
     32 
     33     自定义无符号整数字段
     34 
     35         class UnsignedIntegerField(models.IntegerField):
     36             def db_type(self, connection):
     37                 return 'integer UNSIGNED'
     38 
     39         PS: 返回值为字段在数据库中的属性,Django字段默认的值为:
     40             'AutoField': 'integer AUTO_INCREMENT',
     41             'BigAutoField': 'bigint AUTO_INCREMENT',
     42             'BinaryField': 'longblob',
     43             'BooleanField': 'bool',
     44             'CharField': 'varchar(%(max_length)s)',
     45             'CommaSeparatedIntegerField': 'varchar(%(max_length)s)',
     46             'DateField': 'date',
     47             'DateTimeField': 'datetime',
     48             'DecimalField': 'numeric(%(max_digits)s, %(decimal_places)s)',
     49             'DurationField': 'bigint',
     50             'FileField': 'varchar(%(max_length)s)',
     51             'FilePathField': 'varchar(%(max_length)s)',
     52             'FloatField': 'double precision',
     53             'IntegerField': 'integer',
     54             'BigIntegerField': 'bigint',
     55             'IPAddressField': 'char(15)',
     56             'GenericIPAddressField': 'char(39)',
     57             'NullBooleanField': 'bool',
     58             'OneToOneField': 'integer',
     59             'PositiveIntegerField': 'integer UNSIGNED',
     60             'PositiveSmallIntegerField': 'smallint UNSIGNED',
     61             'SlugField': 'varchar(%(max_length)s)',
     62             'SmallIntegerField': 'smallint',
     63             'TextField': 'longtext',
     64             'TimeField': 'time',
     65             'UUIDField': 'char(32)',
     66 
     67     BooleanField(Field)
     68         - 布尔值类型
     69 
     70     NullBooleanField(Field):
     71         - 可以为空的布尔值
     72 
     73     CharField(Field)
     74         - 字符类型
     75         - 必须提供max_length参数, max_length表示字符长度
     76 
     77     TextField(Field)
     78         - 文本类型
     79 
     80     EmailField(CharField):
     81         - 字符串类型,Django Admin以及ModelForm中提供验证机制
     82 
     83     IPAddressField(Field)
     84         - 字符串类型,Django Admin以及ModelForm中提供验证 IPV4 机制
     85 
     86     GenericIPAddressField(Field)
     87         - 字符串类型,Django Admin以及ModelForm中提供验证 Ipv4和Ipv6
     88         - 参数:
     89             protocol,用于指定Ipv4或Ipv6, 'both',"ipv4","ipv6"
     90             unpack_ipv4, 如果指定为True,则输入::ffff:192.0.2.1时候,可解析为192.0.2.1,开启刺功能,需要protocol="both"
     91 
     92     URLField(CharField)
     93         - 字符串类型,Django Admin以及ModelForm中提供验证 URL
     94 
     95     SlugField(CharField)
     96         - 字符串类型,Django Admin以及ModelForm中提供验证支持 字母、数字、下划线、连接符(减号)
     97 
     98     CommaSeparatedIntegerField(CharField)
     99         - 字符串类型,格式必须为逗号分割的数字
    100 
    101     UUIDField(Field)
    102         - 字符串类型,Django Admin以及ModelForm中提供对UUID格式的验证
    103 
    104     FilePathField(Field)
    105         - 字符串,Django Admin以及ModelForm中提供读取文件夹下文件的功能
    106         - 参数:
    107                 path,                      文件夹路径
    108                 match=None,                正则匹配
    109                 recursive=False,           递归下面的文件夹
    110                 allow_files=True,          允许文件
    111                 allow_folders=False,       允许文件夹
    112 
    113     FileField(Field)
    114         - 字符串,路径保存在数据库,文件上传到指定目录
    115         - 参数:
    116             upload_to = ""      上传文件的保存路径
    117             storage = None      存储组件,默认django.core.files.storage.FileSystemStorage
    118 
    119     ImageField(FileField)
    120         - 字符串,路径保存在数据库,文件上传到指定目录
    121         - 参数:
    122             upload_to = ""      上传文件的保存路径
    123             storage = None      存储组件,默认django.core.files.storage.FileSystemStorage
    124             width_field=None,   上传图片的高度保存的数据库字段名(字符串)
    125             height_field=None   上传图片的宽度保存的数据库字段名(字符串)
    126 
    127     DateTimeField(DateField)
    128         - 日期+时间格式 YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ]
    129 
    130     DateField(DateTimeCheckMixin, Field)
    131         - 日期格式      YYYY-MM-DD
    132 
    133     TimeField(DateTimeCheckMixin, Field)
    134         - 时间格式      HH:MM[:ss[.uuuuuu]]
    135 
    136     DurationField(Field)
    137         - 长整数,时间间隔,数据库中按照bigint存储,ORM中获取的值为datetime.timedelta类型
    138 
    139     FloatField(Field)
    140         - 浮点型
    141 
    142     DecimalField(Field)
    143         - 10进制小数
    144         - 参数:
    145             max_digits,小数总长度
    146             decimal_places,小数位长度
    147 
    148     BinaryField(Field)
    149         - 二进制类型
    models字段类型
     1 class User(models.Model):
     2     name = models.CharField(max_length=32)
     3     pwd = models.CharField(max_length=32)
     4 #class User(models.Model):
     5 #    name = models.CharField(max_length=32,db_index=True)
     6 #    pwd = models.CharField(max_length=32,db_index=True)
     7 class Meta:
     8     #指定数据库表名:tb1,如果不指定表名将会默认生成表名:app名称 + 下划线 + 类名
     9     db_table = "tb1"
    10 
    11     #索引,mysql每一列加上索引就会生成一个文件,因此当上面被注释的User表生成是mysql数据库就会生成一个表,两个文件,
    12     #因此不想数据库生成太多索引文件,又想个别列名能够支持索引查询,这个时候就需要用到联合索引,
    13     index_together = [  # 联合索引,只会生成一个索引文件 但是有一个缺点就是,遵循最左前缀模式查询
    14         ("name", 'pwd'),
    15     ]
    16 
    17     # 最左前缀的模式:
    18     # select * from where name='xx'
    19     # select * from where name='xx' and email = 'xx'
    20     # select * from where email = 'xx' # 无法命中索引
    21 
    22     #联合唯一索引,与上面的联合索引一样,就是多了一个列名组合唯一的限制
    23     unique_together = (("driver", "restaurant"),)
    24 
    25     #admin中的配置
    26     verbose_name = “name”  #在admin中会将name显示成names,多加一个“s”
    27     verbose_name_plural=““name””  #在admin中会将name显示成name,显示原生自定义的名字
    db_table、联合索引、联合唯一索引
     1     null                数据库中字段是否可以为空
     2     db_column           数据库中字段的列名
     3     db_tablespace
     4     default             数据库中字段的默认值
     5     primary_key         数据库中字段是否为主键
     6     db_index            数据库中字段是否可以建立索引
     7     unique              数据库中字段是否可以建立唯一索引
     8     unique_for_date     数据库中字段【日期】部分是否可以建立唯一索引
     9     unique_for_month    数据库中字段【月】部分是否可以建立唯一索引
    10     unique_for_year     数据库中字段【年】部分是否可以建立唯一索引
    11 
    12     verbose_name        Admin中显示的字段名称
    13     blank               Admin中是否允许用户输入为空
    14     editable            Admin中是否可以编辑
    15     help_text           Admin中该字段的提示信息
    16     choices             Admin中显示选择框的内容,用不变动的数据放在内存中从而避免跨表操作
    17                         如:gf = models.IntegerField(choices=[(0, '何穗'),(1, '大表姐'),],default=1) 想要在HTML中显示choice中的字段值,而不是数学索引,需要用到{{k.get_带choices参数的字段_display}}方法
    18 
    19     error_messages      自定义错误信息(字典类型),从而定制想要显示的错误信息;
    20                         字典健:null, blank, invalid, invalid_choice, unique, and unique_for_date
    21                         如:{'null': "不能为空.", 'invalid': '格式错误'}
    22 
    23     validators          自定义错误验证(列表类型),从而定制想要的验证规则
    24                         from django.core.validators import RegexValidator
    25                         from django.core.validators import EmailValidator,URLValidator,DecimalValidator,
    26                         MaxLengthValidator,MinLengthValidator,MaxValueValidator,MinValueValidator
    27                         如:
    28                             test = models.CharField(
    29                                 max_length=32,
    30                                 error_messages={
    31                                     'c1': '优先错信息1',
    32                                     'c2': '优先错信息2',
    33                                     'c3': '优先错信息3',
    34                                 },
    35                                 validators=[
    36                                     RegexValidator(regex='root_d+', message='错误了', code='c1'),
    37                                     RegexValidator(regex='root_112233d+', message='又错误了', code='c2'),
    38                                     EmailValidator(message='又错误了', code='c3'), ]
    39                             )
    models中的参数

    1.2、在settings.py中注册app:

    INSTALLED_APPS = [
        'django.contrib.admin',
        'django.contrib.auth',
        'django.contrib.contenttypes',
        'django.contrib.sessions',
        'django.contrib.messages',
        'django.contrib.staticfiles',
        'app1',
    ]
    

    1.3、在控制台输出cmd 命令:

    python3 manage.py  makemigrations #相当于在该app的migrations目录,记录下该app下modes.py所有表结构类型的改动(普通增删改查不记录)
    python3 manage.py  migrate        #将刚刚对于表结构的改动作用至数据库
    

      

    2、在MySQL中创建表

    2.1、在上面步骤1.1 先写类、1.2 注册app的基础上,在与Django project中与project同名目录下的__init__.py文件中配置如下代码:

    import pymysql
    pymysql.install_as_MySQLdb()

    注:# 由于Django内部连接MySQL时使用的是MySQLdb模块,而python3中还无此模块,所以需要使用pymysql来代替

    2.2,在settings.py中更改数据库配置

    #将原先数据库配置注释,使用mysql配置
    # DATABASES = {
    #     'default': {
    #         'ENGINE': 'django.db.backends.sqlite3',
    #         'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
    #     }
    # }
    
    
    
    DATABASES = {
        'default': {
            'ENGINE': 'django.db.backends.mysql',
            'NAME': 'test1',       # 数据库名称
            'USER': 'root',         # 用户名
            'PASSWORD': '123456',      # 密码
            'HOST': 'localhost',             # ip
            'PORT': '3306',             # 端口
        }
    }

    2.3、执行命令

    python3 manage.py  makemigrations
    python3 manage.py  migrate  

    注:配置好数据库为mysql后,重新启动Django工程,如果报错mysql django.core.exceptions.ImproperlyConfigured: mysqlclient 1.3.3 or newer is required;的话, 这是因为 mysql client 端的版本小于1.3.3。最简单的解决办法是:

    #找到Django的安装路径的mysql配置下的base.py,如C:Python36Libsite-packagesdjangodbackendsmysqlase.py(根据实际安装路径)
    #注释这句断言:
    #if version < (1, 3, 3):
        #raise ImproperlyConfigured("mysqlclient 1.3.3 or newer is required; you have %s" % Database.__version__)
    

    二、增删改查

     利用Django的ORM连接数据库进行增删改查和其他一些进阶操作。

    1、增:

    # 第一种方式
    models.UserInfo.objects.create(username='root', password='123')
    # 第二种方式
    dic = {'username': 'root1', 'password': '456'}
    models.UserInfo.objects.create(**dic)
    #第三种方式
    obj = models.UserInfo(username='root2', password='789')
    obj.save()
    

    2、删:

    models.UserInfo.objects.filter(id="2").delete()
    

    3、改:

    models.UserInfo.objects.filter(id=1).update(password="111")
    

    4、查:

    models.User.objects.filter(id=1)             #id=1
    models.User.objects.filter(id=1,name='root') #id=1 and name = root
    models.User.objects.filter(id__gt=1)         #id>1
    models.User.objects.filter(id__lt=1)	     #id<1
    models.User.objects.filter(id__gte=1)		 #id>=1
    models.User.objects.filter(id__lte=1)		 #id<=1
    models.Tb1.objects.filter(id__lt=10, id__gt=1)  #1<id<10 dic = {'name': 'xx', 'age__gt': 19} #**字典形式多条件查询 models.User.objects.filter(**dic) models.Business.objects.all() #QuerySet ,内部元素都是对象 [obj(id,caption,code),obj(id,caption,code),obj(id,caption,code) ] models.Business.objects.all().values('id','caption') # QuerySet ,内部元素都是字典 [{'id':1,'code': 'QA'},{'id':2,'code': 'PM'},...] models.Business.objects.all().values_list('id','caption') # QuerySet ,内部元素都是元组 [(1,"QA"),(2,"PM")] models.Business.objects.get(id=1) # 获取到的一个对象,如果不存在就报错 models.Business.objects.filter(id=1).first() # 获取到的一个对象,如果不存在返回NONE

    5、更多进阶操作:

     1 # 获取个数
     2         #
     3         # models.Tb1.objects.filter(name='seven').count()
     4 
     5         # in
     6         #
     7         # models.Tb1.objects.filter(id__in=[11, 22, 33])   # 获取id等于11、22、33的数据
     8         # models.Tb1.objects.exclude(id__in=[11, 22, 33])  # not in
     9 
    10         # isnull
    11         # Entry.objects.filter(pub_date__isnull=True)
    12 
    13         # contains
    14         #
    15         # models.Tb1.objects.filter(name__contains="ven")
    16         # models.Tb1.objects.filter(name__icontains="ven") # icontains大小写不敏感
    17         # models.Tb1.objects.exclude(name__icontains="ven")
    18 
    19         # range
    20         #
    21         # models.Tb1.objects.filter(id__range=[1, 2])   # 范围bettwen and
    22 
    23         # 其他类似
    24         #
    25         # startswith,istartswith, endswith, iendswith,
    26 
    27         # order by
    28         #
    29         # models.Tb1.objects.filter(name='seven').order_by('id')    # asc
    30         # models.Tb1.objects.filter(name='seven').order_by('-id')   # desc
    31 
    32         # group by
    33         #
    34         # from django.db.models import Count, Min, Max, Sum
    35         # models.Tb1.objects.filter(c1=1).values('id').annotate(c=Count('num'))
    36         # SELECT "app01_tb1"."id", COUNT("app01_tb1"."num") AS "c" FROM "app01_tb1" WHERE "app01_tb1"."c1" = 1 GROUP BY "app01_tb1"."id"
    37 
    38         # limit 、offset
    39         #
    40         # models.Tb1.objects.all()[10:20]
    41 
    42         # regex正则匹配,iregex 不区分大小写
    43         #
    44         # Entry.objects.get(title__regex=r'^(An?|The) +')
    45         # Entry.objects.get(title__iregex=r'^(an?|the) +')
    46 
    47         # date
    48         #
    49         # Entry.objects.filter(pub_date__date=datetime.date(2005, 1, 1))
    50         # Entry.objects.filter(pub_date__date__gt=datetime.date(2005, 1, 1))
    51 
    52         # year
    53         #
    54         # Entry.objects.filter(pub_date__year=2005)
    55         # Entry.objects.filter(pub_date__year__gte=2005)
    56 
    57         # month
    58         #
    59         # Entry.objects.filter(pub_date__month=12)
    60         # Entry.objects.filter(pub_date__month__gte=6)
    61 
    62         # day
    63         #
    64         # Entry.objects.filter(pub_date__day=3)
    65         # Entry.objects.filter(pub_date__day__gte=3)
    66 
    67         # week_day
    68         #
    69         # Entry.objects.filter(pub_date__week_day=2)
    70         # Entry.objects.filter(pub_date__week_day__gte=2)
    71 
    72         # hour
    73         #
    74         # Event.objects.filter(timestamp__hour=23)
    75         # Event.objects.filter(time__hour=5)
    76         # Event.objects.filter(timestamp__hour__gte=12)
    77 
    78         # minute
    79         #
    80         # Event.objects.filter(timestamp__minute=29)
    81         # Event.objects.filter(time__minute=46)
    82         # Event.objects.filter(timestamp__minute__gte=29)
    83 
    84         # second
    85         #
    86         # Event.objects.filter(timestamp__second=31)
    87         # Event.objects.filter(time__second=2)
    88         # Event.objects.filter(timestamp__second__gte=31)
    进阶操作

    注:all()、all().values()、all().values_list()示例:

     1 <!DOCTYPE html>
     2 <html lang="en">
     3 <head>
     4     <meta charset="UTF-8">
     5     <title></title>
     6 </head>
     7 <body>
     8     <h1>业务线列表(对象)</h1>
     9     <ul>
    10         {% for row in v1 %}
    11             <li>{{ row.id }} - {{ row.caption }} - {{ row.code }}</li>
    12         {% endfor %}
    13     </ul>
    14     <h1>业务线列表(字典)</h1>
    15     <ul>
    16         {% for row in v2 %}
    17             <li>{{ row.id }} - {{ row.code }}</li>
    18         {% endfor %}
    19     </ul>
    20     <h1>业务线列表(元组)</h1>
    21     <ul>
    22         {% for row in v3 %}
    23             <li>{{ row.0 }} - {{ row.1 }}</li>
    24         {% endfor %}
    25     </ul>
    26 </body>
    27 </html>
    templates模板中的模板语言
     1 from django.shortcuts import render
     2 from app1 import models
     3 
     4 
     5 
     6 def business(request):
     7     v1 = models.Business.objects.all()
     8     #  QuerySet [obj(id,caption,code),obj(id,caption,code),obj(id,caption,code) ]
     9 
    10     v2 = models.Business.objects.all().values("id", "code")
    11     # QuerySet [{'id':1,'code': 'QA'},{'id':2,'code': 'PM'},...]
    12 
    13     v3 = models.Business.objects.all().values_list('id', 'code')
    14     # QuerySet [(1,"QA"),(2,"PM")]
    15     return render(request, 'business.html', {'v1': v1, 'v2': v2, 'v3': v3})
    views.py中all()、all().values()、all().values_list()示例

    三、ORM基础操作示例:

    简单模拟用户登陆跳转后台,实现编辑用户、新增用户、删除用户、查看用户详情等功能小示例

    1、templates:

     1 <!DOCTYPE html>
     2 <html lang="en">
     3 <head>
     4     <meta charset="UTF-8">
     5     <title>Title</title>
     6 </head>
     7 <body>
     8     <form action="/app2/login/" method="POST" enctype="multipart/form-data">
     9         <p>
    10             <input type="text" name="user" placeholder="用户名" />
    11         </p>
    12         <p>
    13             <input type="password" name="pwd" placeholder="密码" />
    14         </p>
    15         <input type="submit" value="提交"/>
    16     </form>
    17 </body>
    18 </html>
    login.html
     1 <!DOCTYPE html>
     2 <html lang="en">
     3 <head>
     4     <meta charset="UTF-8">
     5     <title>Title</title>
     6     <style>
     7         body {
     8             margin: 0;
     9         }
    10 
    11         .menu {
    12             display: block;
    13             padding: 5px;
    14 
    15         }
    16     </style>
    17 </head>
    18 <body>
    19 <div style="height: 48px;background-color: antiquewhite;color: burlywood">
    20     oms后台
    21 </div>
    22 <div>
    23     <div style="position: absolute;top:48px;bottom: 0;left: 0; 200px;background-color: sandybrown;">
    24         <a class="menu" href="/app2/user_info/">用户管理</a>
    25         <a class="menu" href="/app2/user_group/">用户组管理</a>
    26     </div>
    27     <div style="position:absolute;top:48px;left: 210px;bottom: 0;right: 0;overflow: auto">
    28         <h3>添加用户</h3>
    29 
    30         <form method="POST" action="/app2/user_info/">
    31             <input type="text" name="user"/>
    32             <input type="text" name="pwd"/>
    33             <input type="submit" value="添加"/>
    34         </form>
    35 
    36         <h3>用户列表</h3>
    37         <ul>
    38             {% for row in user_list %}
    39                 <li>
    40                     <a href="/app2/userDetail-{{ row.id }}">{{ row.username }}</a> |
    41                     <a href="/app2/userDel-{{ row.id }}">删除</a> |
    42                     <a href="/app2/userEdit-{{ row.id }}">编辑</a>
    43                 </li>
    44             {% endfor %}
    45         </ul>
    46     </div>
    47 
    48 </div>
    49 
    50 </body>
    51 </html>
    user_info.html
     1 <!DOCTYPE html>
     2 <html lang="en">
     3 <head>
     4     <meta charset="UTF-8">
     5     <title>Title</title>
     6     <style>
     7         body{
     8             margin: 0;
     9         }
    10         .menu{
    11             display: block;
    12             padding: 5px;
    13 
    14         }
    15     </style>
    16 </head>
    17 <body>
    18     <div style="height: 48px;background-color: antiquewhite;color: burlywood">
    19         oms后台
    20     </div>
    21     <div>
    22         <div style="position: absolute;top:48px;bottom: 0;left: 0; 200px;background-color: sandybrown;">
    23             <a class="menu" href="/app2/user_info/">用户管理</a>
    24             <a class="menu" href="/app2/user_group/">用户组管理</a>
    25         </div>
    26         <div style="position:absolute;top:48px;left: 210px;bottom: 0;right: 0;overflow: auto">
    27         <h1>编辑用户</h1>
    28             <form method="post" action="/app2/userEdit-{{ obj.id }}/">
    29                 <input style="display: none" type="text" name="id" value="{{ obj.id }}" />
    30                 <input type="text" name="username" value="{{ obj.username }}" />
    31                 <input type="text" name="password" value="{{ obj.password }}"/>
    32                 <input type="submit" value="提交" />
    33             </form>
    34         </div>
    35 
    36     </div>
    37 
    38 </body>
    39 </html>
    user_edit.html
     1 <!DOCTYPE html>
     2 <html lang="en">
     3 <head>
     4     <meta charset="UTF-8">
     5     <title>Title</title>
     6     <style>
     7         body{
     8             margin: 0;
     9         }
    10         .menu{
    11             display: block;
    12             padding: 5px;
    13 
    14         }
    15     </style>
    16 </head>
    17 <body>
    18     <div style="height: 48px;background-color: antiquewhite;color: burlywood">
    19         oms后台
    20     </div>
    21     <div>
    22         <div style="position: absolute;top:48px;bottom: 0;left: 0; 200px;background-color: sandybrown;">
    23             <a class="menu" href="/app2/user_info/">用户管理</a>
    24             <a class="menu" href="/app2/user_group/">用户组管理</a>
    25         </div>
    26         <div style="position:absolute;top:48px;left: 210px;bottom: 0;right: 0;overflow: auto">
    27             <h1>用户详细信息</h1>
    28             <h5>id:{{ obj.id }}</h5>
    29             <h5>name:{{ obj.username}}</h5>
    30             <h5>password:{{ obj.password }}</h5>
    31         </div>
    32 
    33     </div>
    34 
    35 </body>
    36 </html>
    user_detail.html

    2、app中的models.py:

    1 from django.db import models
    2 # Create your models here.
    3 
    4 
    5 class UserInfo(models.Model):
    6     # id列,Django框架会默认生成id(自增,主键),也可以通过AutoField类型自定义主键,不过Django框架默认生成ID列会失效
    7     # 用户名列,字符串类型,最大长度长度
    8     username = models.CharField(max_length=32)
    9     password = models.CharField(max_length=64)
    models.py

    2、app中的urls.py:

    from django.conf.urls import url
    from app2 import views
    urlpatterns = [
        url(r'^orm', views.orm_action),
        url(r'^login', views.login),
        url(r'^oms', views.oms),
        url(r'^user_info', views.user_info),
        url(r'^userDetail-(?P<nid>d+)', views.user_detail),
        url(r'^userDel-(?P<nid>d+)', views.user_del),
        url(r'^userEdit-(?P<nid>d+)', views.user_edit),
    ]
    urls.py

    3、app中的views.py:

     1 from django.shortcuts import render
     2 from django.shortcuts import redirect
     3 from app2 import models
     4 
     5 
     6 # 登录
     7 def login(request):
     8     if request.method == "GET":
     9         return render(request, 'login.html')
    10     elif request.method == "POST":
    11         u = request.POST.get('user')
    12         p = request.POST.get('pwd')
    13         # 两种方式判断数据库中是否有匹配的数据
    14         # obj = models.UserInfo.objects.filter(username=u,password=p).first() # 推荐这一种
    15         # count = models.UserInfo.objects.filter(username=u, password=p).count()
    16         obj = models.UserInfo.objects.filter(username=u, password=p).first()
    17         if obj:
    18             return redirect('/app2/user_info')
    19         else:
    20             return render(request, 'login.html')
    21     else:
    22         # PUT,DELETE,HEAD,OPTION...
    23         return redirect('/login')
    24 
    25 
    26 # 后台页面
    27 def user_info(request):
    28     if request.method == "GET":
    29         user_list = models.UserInfo.objects.all()
    30         print(user_list.query)  # .query 查看原生sql语句
    31         return render(request, "user_info.html", {"user_list": user_list})
    32     elif request.method == "POST":
    33         u = request.POST.get("user")
    34         p = request.POST.get("pwd")
    35         models.UserInfo.objects.create(username=u, password=p)
    36         # 添加用户后返回添加页面查看新增数据
    37         # 方式一
    38         # user_list = models.UserInfo.objects.all()
    39         # return render(request, "user_info.html", {"user_list": user_list})
    40         # 方式二 有效避免重复代码
    41         return redirect("/app2/user_info")
    42 
    43 
    44 # 查看用户详情
    45 def user_detail(request, nid):
    46     # 取单条数据的两种方式
    47     # 第一种(推荐)
    48     obj = models.UserInfo.objects.filter(id=nid).first()
    49     # 第二种(当数据为空,直接报错)
    50     # models.UserInfo.objects.get(id=nid)
    51     return render(request, "user_detail.html", {"obj": obj})
    52 
    53 
    54 # 删除用户
    55 def user_del(request, nid):
    56     models.UserInfo.objects.filter(id=nid).delete()
    57     return redirect("/app2/user_info")
    58 
    59 
    60 # 编辑用户
    61 def user_edit(request, nid):
    62     if request.method == "GET":
    63         obj = models.UserInfo.objects.filter(id=nid).first()
    64         return render(request, "user_edit.html", {"obj": obj})
    65     elif request.method == "POST":
    66         user_id = request.POST.get('id')
    67         u = request.POST.get('username')
    68         p = request.POST.get('password')
    69         models.UserInfo.objects.filter(id=user_id).update(username=u, password=p)
    70         return redirect("/app2/user_info")
    views.py

    四、QuerySet方法详细

    1、支持链式查询QuerySet方法:

      1 def all(self)
      2     # 获取所有的数据对象
      3 
      4 def filter(self, *args, **kwargs)
      5     # 条件查询
      6     # 条件可以是:参数,字典,Q
      7 
      8 def exclude(self, *args, **kwargs)
      9     # 条件查询
     10     # 条件可以是:参数,字典,Q
     11 
     12 def annotate(self, *args, **kwargs)
     13     # 用于实现聚合group by查询
     14 
     15     from django.db.models import Count, Avg, Max, Min, Sum
     16 
     17     v = models.UserInfo.objects.values('u_id').annotate(uid=Count('u_id'))
     18     # SELECT u_id, COUNT(ui) AS `uid` FROM UserInfo GROUP BY u_id
     19 
     20     v = models.UserInfo.objects.values('u_id').annotate(uid=Count('u_id')).filter(uid__gt=1)  # 支持having子句,放在最开始的地方就是where子句,放在这边就是having子句
     21     # SELECT u_id, COUNT(ui_id) AS `uid` FROM UserInfo GROUP BY u_id having count(u_id) > 1
     22 
     23     v = models.UserInfo.objects.values('u_id').annotate(uid=Count('u_id',distinct=True)).filter(uid__gt=1)  # distinct=True去重
     24     # SELECT u_id, COUNT( DISTINCT ui_id) AS `uid` FROM UserInfo GROUP BY u_id having count(u_id) > 1
     25 
     26 def distinct(self, *field_names)
     27     # 用于distinct去重
     28     models.UserInfo.objects.values('nid').distinct()
     29     # select distinct nid from userinfo
     30 
     31     注:只有在PostgreSQL中才能使用distinct进行去重,不支持mysql数据库
     32 
     33 def order_by(self, *field_names)
     34     # 用于排序
     35     models.UserInfo.objects.all().order_by('-id','age')
     36 
     37 def reverse(self):
     38     # 倒序
     39     models.UserInfo.objects.all().order_by('-nid').reverse()
     40     # 这个需要跟order_by配合使用,如果不存在order_by,则没有任何效果
     41     # 如果存在order_by,reverse则是倒序,如果多个排序则一一倒序
     42 
     43 def defer(self, *fields):
     44     #查询表中的数据,排除username、id列数据,将剩余列数据组合成querySet对象进行返回
     45     models.UserInfo.objects.defer('username','')
     46     models.UserInfo.objects.filter(...).defer('username','id')
     47 
     48 def only(self, *fields):
     49     #查询表中的数据,仅取username、id列中的数据组合成querySet对象进行返回,与defer相反
     50      models.UserInfo.objects.only('username','id')
     51      models.UserInfo.objects.filter(...).only('username','id')
     52 
     53 def using(self, alias):
     54      models.Blog.objects.filter(name="root").filter("id=1").all().using(alias="default1") #这个看你settings里面的设置
     55      #指定使用的数据库进行操作(从settings中读取DATABASES配置),使用场景:比如数据库的读写分离,读的是A库,写的是B库
     56 
     57 
     58 # 在原生的sql语句中会遇到一些复杂的sql,如msyql自定义的函数和过程、额外的查询条件、映射、子查询
     59 def extra(self, select=None, where=None, params=None, tables=None, order_by=None, select_params=None)  #tables可不传,实例化的时候已传表名,order_by看使用场景使用
     60 
     61     ## select与select_params配合,以%s进行传参,参数可以是元组,是可迭代的序列即可
     62     Entry.objects.extra(select={'new_id': "%s"}, select_params=(1,))#select的参数,%s 就会替换成 1
     63     #select *,1 as cid from Entry
     64     Entry.objects.extra(select={'new_id': "select col from sometable where othercol > %s"}, select_params=(1,))
     65     #select *,(select col from sometable where nid = 1) as new_id from Entry
     66     Entry.objects.extra(select={'new_id': "func(1)"}) #可以直接放函数
     67     #select func(1) as new_id
     68 
     69 
     70     ##where与params配合,加额外的where条件语句,以%s进行传参,参数可以是元组,是可迭代的序列即可
     71     Entry.objects.extra(where=["name='a' OR age = 22"]) # or
     72     Entry.objects.extra(where=["age = 22", "name='a'"]) # and
     73     Entry.objects.extra(where=["func(arg)=2000"], params=['5'])
     74     Entry.objects.extra(select={'new_id': "select id from tb where id > %s"}, select_params=(1,), order_by=['-nid'])
     75 
     76 
     77 #性能相关的内置方法
     78 def select_related(self, *fields)
     79     #1、
     80     users = User.objects.all()
     81     for row in users:
     82         #仅仅是用户表的数据不会再去请求数据库,user_type表需要再次发送请求,但是如果这边10条用户表的数据有十条,总共就会请求10+1次数据库
     83         print(row.name,row.sex)
     84         print(row.ut.type_name) #再次请求一次数据库
     85 
     86     #2、
     87     users = User.objects.all().values("name","sex","ut__type_name") #如果是这种的话,就会只请求一次数据库,但数据不是querySet对象类型
     88 
     89     #3、
     90     #只拿ut对应的user_type表一次性拿过来
     91     users = User.objects.all().select_related("ut") #只关联ut这张表,取出来,其他的表都不关联,因为一张表里面可以有多个外键
     92     for row in users:
     93         print(row.name,row.sex)
     94         print(row.ut.type_name)
     95         print(row.tu.name) #tu没有加进去,所以这边会再次django发送数据库请求
     96 
     97 
     98 
     99 def prefetch_related(self, *lookups)
    100     #一般在生产环境,很少连表查询,因为这样效率很低,我们一般都是空间换时间,所以这个就会用到prefetch_related,用到这个,会做多次查询,保证每次都是单表查询
    101     users = User.objects.filter(ut_id__gt=30).prefetch_related('ut') #这边也可以多加几个外键
    102     #解析步骤
    103     ## select * from users where id > 30 当然这边不会用*的,一般会把所有字段都打印出来,效率更高
    104     ## 获取上一步中所有ut_id = [1,2]的数据
    105     ## select * from user_type where id in [1,2]
    106     #这边django已经通过以上步骤,把要查询的数据放到内存中,所有就不用向数据库发送请求了,就可以直接从内存中获取
    107     for row in users:
    108         print(row.name,row.sex)
    109         print(row.ut.type_name)
    支持链式查询的QuerySet方法

    2、不支持链式查询QuerySet方法:

     1 def raw(self, raw_query, params=None, translations=None, using=None):
     2     # 执行原生SQL
     3     models.UserInfo.objects.raw('select * from userinfo')
     4     #obj = User.objects.raw('select id,name,password from tb ')
     5 
     6     # 如果SQL是其他表时,必须将名字设置为当前UserInfo对象的主键列名,
     7     models.UserInfo.objects.raw('select id as nid from 其他表')
     8     #可以下面的方式将tb2里面的数据复制在tb中
     9     #obj = User.objects.raw('select nid as id,username as name,email as password from tb2 ')
    10 
    11     # 为原生SQL设置参数
    12     models.UserInfo.objects.raw('select id as nid from userinfo where nid>%s', params=[12,])
    13 
    14     # 将获取的到列名转换为指定列名
    15     name_map = {'first': 'first_name', 'last': 'last_name', 'bd': 'birth_date', 'pk': 'id'}
    16     Person.objects.raw('SELECT * FROM some_other_table', translations=name_map)
    17 
    18     # 指定数据库
    19     models.UserInfo.objects.raw('select * from userinfo', using="default")
    20 
    21     ################### 原生SQL ###################
    22     from django.db import connection, connections
    23     cursor = connection.cursor()  # cursor = connections['default'].cursor()
    24     cursor.execute("""SELECT * from auth_user where id = %s""", [1])
    25     row = cursor.fetchone() # fetchall()/fetchmany(..)
    26 
    27 
    28 def values(self, *fields):
    29     # 获取每行数据为字典格式
    30 
    31 def values_list(self, *fields, **kwargs):
    32     # 获取每行数据为元祖
    33 
    34 def dates(self, field_name, kind, order='ASC'):
    35     # 根据数据库中时间列名进行某一部分进行去重查找并截取指定内容
    36     # kind只能是:"year"(年), "month"(年-月), "day"(年-月-日)
    37     # order只能是:"ASC"  "DESC"
    38     # 并获取转换后的时间
    39         - year : 年-01-01
    40         - month: 年-月-01
    41         - day  : 年-月-42 
    43     models.DatePlus.objects.dates('ctime','day','DESC')
    44 
    45 def datetimes(self, field_name, kind, order='ASC', tzinfo=None):
    46     # 根据数据库中时间列名进行某一部分进行去重查找并截取指定内容,将时间转换为指定时区时间
    47     # kind只能是 "year", "month", "day", "hour", "minute", "second"
    48     # order只能是:"ASC"  "DESC"
    49     # tzinfo时区对象
    50     #指定时区需要下载pytz库
    51     """
    52     pip3 install pytz
    53     import pytz
    54     pytz.all_timezones
    55     pytz.timezone(‘Asia/Shanghai’)
    56     """
    57     models.DDD.objects.datetimes('ctime','hour',tzinfo=pytz.UTC)
    58     models.DDD.objects.datetimes('ctime','hour',tzinfo=pytz.timezone('Asia/Shanghai'))
    59 
    60 
    61 
    62 def none(self):
    63     # 返回一个空QuerySet对象
    不支持链式查询的QuerySet方法

    3、数据库操作:

    如:批量插入数据库,对整个数据做聚合操作

     1 def aggregate(self, *args, **kwargs):
     2    # 聚合函数,获取字典类型聚合结果
     3    from django.db.models import Count, Avg, Max, Min, Sum
     4    result = models.UserInfo.objects.aggregate(k=Count('u_id', distinct=True), n=Count('nid')) # distinct=True 先去重,再执行聚合  相当于sql如下: #select count(nid) as n from user
     5 
     6 def count(self):
     7    # 获取个数
     8 
     9 def get(self, *args, **kwargs):
    10    # 获取单个对象
    11 
    12 def create(self, **kwargs):
    13    # 创建对象
    14 
    15 def bulk_create(self, objs, batch_size=None):
    16     # 批量插入
    17     # batch_size表示一次插入的个数
    18     objs = [
    19         models.DDD(name='r11'),
    20         models.DDD(name='r22')
    21     ]
    22     models.DDD.objects.bulk_create(objs, 10)
    23 
    24 def get_or_create(self, defaults=None, **kwargs):
    25     # 如果存在,则获取,否则,创建
    26     # defaults 指定创建时,其他字段的值
    27     obj, created = models.UserInfo.objects.get_or_create(username='root1', defaults={'email': '1111111','u_id': 2, 't_id': 2})
    28 
    29 def update_or_create(self, defaults=None, **kwargs):
    30     # 如果存在,则更新,否则,创建
    31     # defaults 指定创建时或更新时的其他字段
    32     obj, created = models.UserInfo.objects.update_or_create(username='root1', defaults={'email': '1111111','u_id': 2, 't_id': 1})
    33 
    34 def first(self):
    35    # 获取第一个
    36 
    37 def last(self):
    38    # 获取最后一个
    39 
    40 def in_bulk(self, id_list=None):
    41    # 根据主键ID进行查找
    42    id_list = [11,21,31]
    43    models.DDD.objects.in_bulk(id_list) #相当于in操作
    44 
    45 def delete(self):
    46    # 删除
    47 
    48 def update(self, **kwargs):
    49     # 更新
    50 
    51 def exists(self):
    52    # 是否有结果
    53 
    54 METHODS THAT DO DATABASE QUERIES
    直接对数据库操作

     4、QuerySet序列化:

     1 #第一种
     2 ##使用Django内置的方法对queryset类型的数据进行序列化
     3 
     4 from django.core import serializers
     5 ret = models.BookType.objects.all()
     6 data = serializers.serialize("json", ret)
     7 
     8 
     9 #第二种
    10 ##使用json.dumps对queryset类型的数据进行序列化
    11 ####当list中queryset类型中没有复杂的数据类型(如:时间类型)可以直接使用json.dumps
    12 import json
    13 #ret = models.BookType.objects.all().values('caption')
    14 ret = models.BookType.objects.all().values_list('id','caption')
    15 ret=list(ret)
    16 result = json.dumps(ret)
    17 
    18 ####当list中queryset类型中没有复杂的数据类型(如:时间)可以直接使用json.dumps
    19 import json
    20 from datetime import date
    21 from datetime import datetime
    22 
    23 #自定义encoder
    24 class JsonCustomEncoder(json.JSONEncoder):
    25 
    26     def default(self, field):
    27 
    28         if isinstance(field, datetime.datetime):
    29             return field.strftime('%Y-%m-%d %H:%M:%S')
    30         elif isinstance(field, date):
    31             return field.strftime('%Y-%m-%d')
    32         else:
    33             return json.JSONEncoder.default(self, field)
    34 
    35 #再序列化带有类似于ctime复杂的数据类型
    36 ret = models.BookType.objects.all().values_list('caption','ctime')
    37 
    38 ret=list(ret)
    39 
    40 result  = json.dumps(ret, cls=JsonCustomEncoder)
    QuerySet序列化的两种方式

     

    五、Model利用钩子进行数据验证(弱)

    django Model也是支持数据验证的,只是这个数据验证比较弱而已,只能支持单个的验证,但是对于组合的、固定的,就无法进行相关数据验证了

    1、models.py

    class User(models.Model):
        name = models.CharField(max_length=32,db_index=True) #创建索引
        email = models.EmailField(max_length=30)
        #Model通过clean()函数设置钩子
        def clean(self): #Model内部对所有字段进行正则验证,完毕之后才会执行这个clean方法
            from django.core.exceptions import ValidationError
            c = User.objects.filter(name=self.name).count()
            if c:
                raise ValidationError
    

    2、views.py

    from app01 import models
     
    def index(request):
        obj = models.User(name="root",email="root")
        obj.full_clean()  #没有这个,name是不做验证的,有了full_clean是需要做验证的,验证不通过是要报错的,所以验证的时候,我们直接自己抓异常,进行异常处理
        obj.save()
     
        return HttpResponse("hello")
    

      

  • 相关阅读:
    通过IDEA解决spring配置文件
    idea中xml打开方式变成file,改回来
    idea 搜索不到前端的ajax controller接口的原因
    IDEA 出现 updating indices 卡进度条问题的解决方案并加快索引速度
    java 循环中使用list时,出现list中全部加入了对象导致没有实现分组的解决方案
    java 从字符串中 以单个或多个空格进行分隔 提取字符串
    idea ssm项目出现日志中文乱码,封装的json中的msg字段中文乱码(但是json封装的bean中的字段不乱码)等其他各种项目下的中文乱码解决方案
    javaweb 解决jsp中${}传递中文值到后端以及get请求中文乱码的问题
    idea 开发javaee 时,出现访问的文件和源文件不一样,没有正常更新的解决方案
    java 迭代器只遍历了一次的解决方案
  • 原文地址:https://www.cnblogs.com/Keep-Ambition/p/8440833.html
Copyright © 2011-2022 走看看