Django Model 基础

程序涉及到数据库相关操作时,一般都会这样:

  • 创建数据库,设计表结构和字段

  • 使用 pymysql 来连接数据库,并编写数据访问层代码

  • 业务逻辑层去调用数据访问层执行数据库操作

import pymysql
  
def get_list(sql):
    db = pymysql.connect(user='root', db='db1', passwd='123456', host='localhost')
    cursor = db.cursor()
    cursor.execute(sql)
    data = cursor.fetchall()
    db.close()
    return data 

Django为使用一种新的方式,即:关系对象映射(Object Relational Mapping,简称ORM)。

  PHP:activerecord

  Java:Hibernate 

    C#:Entity Framework

Django中遵循 Code Frist 的原则,即:根据代码中定义的类来自动生成数据库表

一  创建表

1.  基本结构 

from django.db import models

class UserInfo(models.Model):
    name = models.CharField(max_length=32)
    email = models.EmailField()
    memo = models.TextField()
    num = models.IntegerField(null=True, blank=True, default=0)
    ctime = models.DateTimeField(auto_now=True)

    def __str__(self):
        return self.name
    # modes字段类型
    AutoField                 int自增列,必须填入参数 primary_key=True
    BigAutoField              bigint自增列,必须填入参数 primary_key=True
    注:当model中如果没有自增列,则自动会创建一个列名为id的列

    SmallIntegerField         小整数 -32768 ~ 32767
    PositiveSmallIntegerField 正小整数 0 ~ 32767
    IntegerField              整数列(有符号的) -2147483648 ~ 2147483647
    PositiveIntegerField      正整数 0 ~ 2147483647
    BigIntegerField           长整型(有符号的) -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          布尔值类型
    NullBooleanField      可以为空的布尔值


    CharField             字符类型,必须提供max_length参数, max_length表示字符长度
    TextField             文本类型
    EmailField            字符串类型,Django Admin以及ModelForm中提供验证机制
    IPAddressField        字符串类型,Django Admin以及ModelForm中提供验证 IPV4 机制
    GenericIPAddressField 字符串类型,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               字符串类型,Django Admin以及ModelForm中提供验证 URL
    SlugField  字          符串类型,Django Admin以及ModelForm中提供验证支持 字母、数字、下划线、连接符(减号)
    UUIDField              字符串类型,Django Admin以及ModelForm中提供对UUID格式的验证

    FilePathField
        - 字符串,Django Admin以及ModelForm中提供读取文件夹下文件的功能
        - 参数:
            path,                      文件夹路径
            match=None,                正则匹配
            recursive=False,           递归下面的文件夹
            allow_files=True,          允许文件
            allow_folders=False,       允许文件夹

    FileField
        - 字符串,路径保存在数据库,文件上传到指定目录
        - 参数:
            upload_to = ""      上传文件的保存路径
            storage = None      存储组件,默认django.core.files.storage.FileSystemStorage

    ImageField(FileField)
        - 字符串,路径保存在数据库,文件上传到指定目录
        - 参数:
            upload_to = ""      上传文件的保存路径
            storage = None      存储组件,默认django.core.files.storage.FileSystemStorage
            width_field=None,   上传图片的高度保存的数据库字段名(字符串)
            height_field=None   上传图片的宽度保存的数据库字段名(字符串)

    DateTimeField  日期+时间格式 YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ]
    DateField      日期格式      YYYY-MM-DD
    TimeField      时间格式      HH:MM[:ss[.uuuuuu]]

    DurationField  长整数,时间间隔,数据库中按照bigint存储,ORM中获取的值为datetime.timedelta类型
    FloatField     浮点型
    DecimalField
        -10进制小数
        - 参数:
            max_digits,小数总长度
            decimal_places,小数位长度
    BinaryField  二进制类型
    
    # 更多信息参考 https://docs.djangoproject.com/en/1.11/ref/models/fields/
字段
    # 参数
    null                数据库中字段是否可以为空
    db_colmun           数据库中字段的列名
    db_tablespace
    default             数据库中字段的默认值
    primary_key         数据库中字段是否为主键
    db_index            数据库中字段是否可以建立索引
    unique              数据库中字段是否可以建立唯一索引
    unique_for_date     数据库中字段【日期】部分是否可以建立唯一索引
    unique_for_month    数据库中字段【月】部分是否可以建立唯一索引
    unique_for_year     数据库中字段【年】部分是否可以建立唯一索引

    verbose_name        Admin中显示的字段名称
    blank               Admin中是否允许用户输入为空
    editable            Admin中是否可以编辑
    help_text           Admin中该字段的提示信息
    choices             dmin中显示选择框的内容,用不变动的数据放在内存中从而避免跨表操作
                        如:friend = models.IntegerField(choices=[(0, '小李子'),(1, '大表姐'),],default=1)

    error_messages      自定义错误信息(字典类型),从而定制想要显示的错误信息;
                        字典健:null, blank, invalid, invalid_choice, unique, and unique_for_date
                        如:{'null': "不能为空.", 'invalid': '格式错误'}

    validators          自定义错误验证(列表类型),从而定制想要的验证规则
                        from django.core.validators import RegexValidator
                        from django.core.validators import EmailValidator,URLValidator,DecimalValidator,
                        MaxLengthValidator,MinLengthValidator,MaxValueValidator,MinValueValidator
                        如:
                            test = models.CharField(
                                max_length=32,
                                error_messages={
                                    'c1': '优先错信息1',
                                    'c2': '优先错信息2',
                                    'c3': '优先错信息3',
                                },
                                validators=[
                                    RegexValidator(regex='root_d+', message='错误了', code='c1'),
                                    RegexValidator(regex='root_112233d+', message='又错误了', code='c2'),
                                    EmailValidator(message='又又错误了', code='c3'), ]
                            )
参数
class UserInfo(models.Model):
    name = models.CharField(max_length=30)
    email = models.EmailField()
    memo = models.TextField()

    class Meta:
        # 抽象基类,不会生成对应库表
        abstract = True

        # app名称
        app_label = 'myapp'

        # latest()方法默认排序字段
        get_latest_by = 'order_date'

        # 默认排序规则
        ordering = ['-order_date']

        # 代理继承
        proxy = True

        # 数据库中生成的表名称 默认 app名称_类名小写
        db_table = "table_name"

        # 联合索引
        index_together = [
            ("pub_date", "deadline"),
        ]

        # 联合唯一索引
        unique_together = (("driver", "restaurant"),)

        # admin中显示的表名称
        verbose_name = 'name'

        # verbose_name复数形式
        verbose_name_plural = 'names'

        # 只读属性
        # label,=app_label.object_name,如'polls.Question'
        # label_lower,=app_label.object_name,如'polls.question'

        # 更多参考 https://docs.djangoproject.com/en/1.11/ref/models/options/
元类

2.  连表结构

  • 一对多:models.ForeignKey(其他表)

  • 多对多:models.ManyToManyField(其他表)

  • 一对一:models.OneToOneField(其他表)

应用场景:

  • 一对多:当一张表中创建一行数据时,有一个单选的下拉框(可以被重复选择)

    例如:创建用户信息时候,需要选择一个用户类型【普通用户】【金牌用户】【铂金用户】等。

  • 多对多:在某表中创建一行数据是,有一个可以多选的下拉框

    例如:创建用户信息,需要为用户指定多个爱好

  • 一对一:在某表中创建一行数据时,有一个单选的下拉框(下拉框中的内容被用过一次就消失了)

    例如:用户基本表存储用户名、密码,用户详情表存储基本信息

二  操作表

1.  基本操作

 1     #
 2     #
 3     # models.userinfo.objects.create(name='Linda', email='linda@gmail.com', memo='xxxx') # 增加一条数据,可以接受字典类型数据 **kwargs
 4     # obj = models.userinfo(name='Green', email='Green@gmail.com', memo='xxxx')
 5     # obj.save()
 6 
 7     #
 8     #
 9     # models.userinfo.objects.get(id=1)     # 获取单条数据,不存在则报错(不建议)
10     # models.userinfo.objects.all()         # 获取所有对象,QuerySet列表,元素为对象
11     # models.userinfo.objects.filter(name="Curry")  # 过滤指定条件数据 <QuerySet [<userinfo: Curry>]>
12 
13     #
14     #
15     # models.userinfo.objects.filter(name='Bill').delete() # 删除指定条件的数据
16 
17     #
18     #
19     # models.userinfo.objects.filter(name='Green').update(num=10) # 将指定条件的数据更新,均支持 **kwargs
20     # obj = models.userinfo.objects.get(id=1)
21     # obj.num = 100
22     # obj.save()    # # 修改单条数据
View Code 

2.  进阶操作(了不起的双下划线)

 1     # 获取个数
 2     # models.userinfo.objects.filter(name='Green').count()
 3 
 4     # 大于,小于
 5     # models.userinfo.objects.filter(id__gt=1)            # 获取id大于1的值
 6     # models.userinfo.objects.filter(id__gte=1)           # 获取id大于等于1的值
 7     # models.userinfo.objects.filter(id__lt=8)            # 获取id小于8的值
 8     # models.userinfo.objects.filter(id__lte=8)           # 获取id小于8的值
 9     # models.userinfo.objects.filter(id__lt=8, id__gt=1)  # 获取id大于1 且 小于8的值
10 
11     # in
12     # models.userinfo.objects.filter(id__in=[1, 2, 3])
13     # models.userinfo.objects.exclude(id__in=[1, 2, 3])
14 
15     # isnull
16     # models.userinfo.objects.filter(ctime__isnull=True)
17 
18     # contains
19     # models.userinfo.objects.filter(name__contains='Lin')
20     # models.userinfo.objects.filter(name__icontains='lin')  # icontains大小写不敏感
21     # models.userinfo.objects.exclude(name__icontains='lin')
22 
23     # range
24     # models.userinfo.objects.filter(id__range=[1, 2])
25 
26     # 其他类似
27     # startswith, istartswith, endswith, iendswith
28 
29     # order_by
30     # models.userinfo.objects.all().order_by('id')  # asc
31     # models.userinfo.objects.all().order_by('-id') # desc
32 
33     # group by
34 
35     # limit, offset
36     # models.userinfo.objects.all()[10:12]
37 
38     # regex正则匹配,iregex 不区分大小写
39     # models.userinfo.objects.get(name__regex=r'^(An?|The)+')
40     # models.userinfo.objects.get(name__iregex=r'^(An?|The)+')
View Code

3.  extra、F、Q及原生SQL

 1     # extra
 2     #
 3     # models.userinfo.objects.extra(select={'new_id': 'select name from app_userinfo where id > %s'}, select_params=(1,))
 4     # models.userinfo.objects.extra(where=['name=%s'],params=["Linda"])
 5     # models.userinfo.objects.extra(where=["name='Linda' OR name='Green' OR name='Logan'"])
 6     # models.userinfo.objects.extra(select={'new_id': 'select name from app_userinfo where id > %s'}, select_params=(1,),order_by=['-id'])
 7 
 8     # F
 9     #
10     # from django.db.models import F
11     # models.userinfo.objects.filter(name='Linda').update(num=F('num')+1)
12 
13     # Q
14     #
15     # 方式一:
16     # Q(nid__gt=10)
17     # Q(nid=8) | Q(nid__gt=10)
18     # Q(Q(nid=8) | Q(nid__gt=10)) & Q(caption='root')
19     # 方式二:
20     # con = Q()
21     # q1 = Q()
22     # q1.connector = 'OR'
23     # q1.children.append(('id', 1))
24     # q1.children.append(('id', 10))
25     # q1.children.append(('id', 9))
26     # q2 = Q()
27     # q2.connector = 'OR'
28     # q2.children.append(('name', 'Linda'))
29     # q2.children.append(('name', 'Logan'))
30     # q2.children.append(('nmae', 'Green'))
31     # con.add(q1, 'AND')
32     # con.add(q2, 'AND')
33     #
34     # models.userinfo.objects.filter(con)
35 
36     # from django.db import connection, connections
37     # cursor = connection.cursor()  # # cursor = connections['default'].cursor()
38     # cursor.execute("""SELECT * from app_userinfo where id = %s""", [1])
39     # row = cursor.fetchone()  # (1, 'Linda', 'linda@gmail.com', 'xxxx', 102, datetime.datetime(2017, 8, 3, 3, 50, 28, 145647))
View Code

4.  连表操作(了不起的双下划线)

利用双下划线和_set将表之间的操作连接起来

 1 class UserProfile(models.Model):
 2     user_info = models.OneToOneField('UserInfo1')
 3     username = models.CharField(max_length=64)
 4     password = models.CharField(max_length=64)
 5 
 6     def __str__(self):
 7         return self.username
 8 
 9 
10 class UserInfo1(models.Model):
11     user_type_choice = (
12         (0, u'普通用户'),
13         (1, u'高级用户')
14     )
15     user_type = models.IntegerField(choices=user_type_choice,default=0)
16     name = models.CharField(max_length=32)
17     email = models.CharField(max_length=32)
18     address = models.CharField(max_length=128)
19 
20     def __str__(self):
21         return self.name
22 
23 
24 class UserGroup(models.Model):
25     caption = models.CharField(max_length=64)
26     user_info = models.ManyToManyField('UserInfo1')
27 
28     def __str__(self):
29         return self.caption
30 
31 
32 class Host(models.Model):
33     hostname = models.CharField(max_length=64)
34     ip = models.GenericIPAddressField()
35     user_group = models.ForeignKey('UserGroup')
36 
37     def __str__(self):
38         return self.hostname
表结构实例
 1     user_info_obj = models.UserInfo1.objects.filter(id=1).first()
 2     print(user_info_obj.user_type)
 3     print(user_info_obj.get_user_type_display())
 4     print(user_info_obj.userprofile.password)   # 默认userprofile属性对象
 5 
 6     user_profile_obj = models.UserProfile.objects.filter(id=1).first()
 7     print(user_profile_obj.user_info.address)   # user_info 当做对象来处理
 8 
 9     user_info_obj = models.UserInfo1.objects.filter(id=1).values('email','userprofile__username').first()
10     print(user_info_obj)          # <QuerySet [{'email': 'tom@gmail.com', 'userprofile__username': 'tommm'}]>
11     print(user_info_obj.keys())
12     print(user_info_obj.values())
一对一操作
 1     """
 2     1. 搜索条件使用 __ 连接
 3     2. 获取值时使用 . 连接
 4     3. 从主键表到外键表,即方向操作时,主键对象.外键表名_set.all()
 5     """
 6     host_obj = models.Host.objects.filter(id=1).first()
 7     print(host_obj.user_group.caption)
 8 
 9     user_group_obj = models.UserGroup.objects.filter(id=1).first()
10     print(user_group_obj.host_set.all())  # <QuerySet [<Host: host1>, <Host: host2>]>
一对多操作
 1     user_info_obj = models.UserInfo1.objects.filter(name='Tim').first()
 2     user_info_objs = models.UserInfo1.objects.all()
 3 
 4     group_obj = models.UserGroup.objects.filter(caption='GroupB').first()
 5     group_objs = models.UserGroup.objects.all()
 6 
 7     # 添加数据
 8     # group_obj.user_info.add(user_info_obj)    # 组对象GroupB 添加单个对象 Tim
 9     # group_obj.user_info.add(*user_info_objs)  # 组对象GroupB 批量添加对象
10 
11     # 删除数据
12     # group_obj.user_info.remove(user_info_obj)   # 组对象GroupB 删除单个对象 Tim
13     # group_obj.user_info.remove(*user_info_objs) # 组对象GroupB 批量删除对象
14 
15     # 添加数据
16     # user_info_obj.usergroup_set.add(group_obj)   # 对象Tim 添加到组对象GroupB中
17     # user_info_obj.usergroup_set.add(*group_objs) # 对象Tim 批量添加到各个组对象中
18 
19     # 删除数据
20     # user_info_obj.usergroup_set.remove(group_obj)   # 对象Tim 从组对象GroupB中删除
21     # user_info_obj.usergroup_set.remove(*group_objs) # 对象Tim 从各个组对象中删除
22 
23     # 获取数据
24     # class UserGroup中定义 user_info = models.ManyToManyField('UserInfo1')
25     print(group_obj.user_info.all())               # <QuerySet [<UserInfo1: tom>, <UserInfo1: Tim>, <UserInfo1: linda>]>
26     print(group_obj.user_info.all().filter(id=1))  # <QuerySet [<UserInfo1: tom>]>
27 
28     # 获取数据
29     # 获取user_info_obj所在哪些组
30     print(user_info_obj.usergroup_set.all())      # <QuerySet [<UserGroup: GroupB>, <UserGroup: GroupA>]>
31     print(user_info_obj.usergroup_set.all().filter(caption='GroupB'))  # <QuerySet [<UserGroup: GroupB>]>
多对多操作

更多信息参考: http://www.cnblogs.com/wupeiqi/articles/5246483.html

原文地址:https://www.cnblogs.com/jonathan1314/p/7278645.html