Django Models

数据库配置

django的数据库相关表配置在models.py文件中,数据库的连接相关信息配置在settings.py中

  • models.py相关相关参数配置

如下:是一张userinfo表,分别有三个字端,name、email、memeo

from django.db import models
  
class Person(models.Model):
    first_name = models.CharField(max_length=30)
    last_name = models.CharField(max_length=30)

上面定义的class,相当于下面的sql语句

CREATE TABLE myapp_person (
    "id" serial NOT NULL PRIMARY KEY,
    "first_name" varchar(30) NOT NULL,
    "last_name" varchar(30) NOT NULL
);

  • 注意:
    • 表名myapp_person由Django自动生成:项目名称+下划线+小写类名。你可以重写这部分功能的机制。
    • Django自动创建id自增主键,当然,你也可以自己指定主键,
    • 上面的sql语句基于PostgreSQL 语法,可能与你的实际情况有差别。

Django可用的field字段:

参考:https://docs.djangoproject.com/en/1.10/ref/models/fields/#model-field-types


1、models.AutoField  自增列 = int(11)
  如果没有的话,默认会生成一个名称为 id 的列,如果要显示的自定义一个自增列,必须将给列设置为主键 primary_key=True。
2、models.CharField  字符串字段
		必须设置 max_length 参数
3、models.BooleanField  布尔类型=tinyint(1)
  不能为空,Blank=True
4、models.ComaSeparatedIntegerField  用逗号分割的数字=varchar
  继承CharField,所以必须 max_lenght 参数
5、models.DateField  日期类型 date
  对于参数,auto_now = True 则每次更新都会更新这个时间;auto_now_add 则只是第一次创建添加,之后的更新不再改变。
6、models.DateTimeField  日期类型 datetime
  同DateField的参数
7、models.Decimal  十进制小数类型 = decimal
  必须指定整数位max_digits和小数位decimal_places
8、models.EmailField  字符串类型(正则表达式邮箱) =varchar
  对字符串进行正则表达式
9、models.FloatField  浮点类型 = double
10、models.IntegerField  整形
11、models.BigIntegerField  长整形
  integer_field_ranges = {
    'SmallIntegerField': (-32768, 32767),
    'IntegerField': (-2147483648, 2147483647),
    'BigIntegerField': (-9223372036854775808, 9223372036854775807),
    'PositiveSmallIntegerField': (0, 32767),
    'PositiveIntegerField': (0, 2147483647),
  }
12、models.IPAddressField  字符串类型(ip4正则表达式)
13、models.GenericIPAddressField  字符串类型(ip4和ip6是可选的)
  参数protocol可以是:both、ipv4、ipv6
  验证时,会根据设置报错
14、models.NullBooleanField  允许为空的布尔类型
15、models.PositiveIntegerFiel  正Integer
16、models.PositiveSmallIntegerField  正smallInteger
17、models.SlugField  减号、下划线、字母、数字
18、models.SmallIntegerField  数字
  数据库中的字段有:tinyint、smallint、int、bigint
19、models.TextField  字符串=longtext
20、models.TimeField  时间 HH:MM[:ss[.uuuuuu]]
21、models.URLField  字符串,地址正则表达式
22、models.BinaryField  二进制
23、models.ImageField   图片
24、models.FilePathField 文件

字段相关参数:


1、null=True
  数据库中字段是否可以为空
2、blank=True
  django的 Admin 中添加数据时是否可允许空值
3、primary_key = False
  主键,对AutoField设置主键后,就会代替原来的自增 id 列
4、auto_now 和 auto_now_add
  auto_now   自动创建---无论添加或修改,都是当前操作的时间
  auto_now_add  自动创建---永远是创建时的时间
5、choices
GENDER_CHOICE = (
        (u'M', u'Male'),
        (u'F', u'Female'),
    )
gender = models.CharField(max_length=2,choices = GENDER_CHOICE)
6、max_length	最大长度
7、default  默认值
8、verbose_name  Admin中字段的显示名称
9、name|db_column  数据库中的字段名称
10、unique=True  不允许重复
11、db_index = True  数据库索引
12、editable=True  在Admin里是否可编辑
13、error_messages=None  错误提示
14、auto_created=False  自动创建
15、help_text  在Admin中提示帮助信息
16、validators=[]
17、upload-to

  • settings.py相关配置

数据库连接配置:

DATABASES = {
    'default': {
        #'ENGINE': 'django.db.backends.', # Add 'postgresql_psycopg2', 'mysql', 'sqlite3' or 'oracle'.
        'ENGINE': 'django.db.backends.sqlite3', #添加数据库引擎;选项['postgresql_psycopg2', 'mysql', 'sqlite3' or 'oracle'].
        'NAME': 'F:/TestPython/blog/blog/db/data.db', # 数据库文件的路径.
        # The following settings are not used with sqlite3:
        # 下面的配置不适用于sqlite3:
        'USER': '',    # 数据库登陆用户名
        'PASSWORD': '', # 数据库登陆密码
        'HOST': '',                      # Empty for localhost through domain sockets or '127.0.0.1' for localhost through TCP. # 主机名
        'PORT': '',                      # Set to empty string for default. # 端口号
    }
}

注册app:
在settings里的INSTALLED_APPS里面加上你的app名字

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

生成数据库表

python  manage.py makemigrations 
# 生成一个数据库结构migrations里面一个表
python  manage.py migrate      
# 根据migrations里面的表来创建数据库

将app的数据库注册到admin

在app01下面的admin.py写入以下内容:

from django.contrib import admin

# Register your models here.
# 导入app01的数据库模块
from app01 import models

# 注册咱们创建的类,通过他来访问
admin.site.register(models.UserInfo)

数据库相关操作

增删改查

# 插入数据:
UserInfo.objects.create(name='rain',password='123',email='rain@163.com')

# 删除数据:
UserInfo.objects.filter(name='rain').delete()

# 修改数据:
UserInfo.objects.filter(name='rain').update(name='Rain1')

# 查找数据:
UserInfo.objects.filter(name='rain')
UserInfo.objects.all()
UserInfo.objects.all()[:10] 
# 切片操作,获取10个人,不支持负索引,切片可以节约内存
UserInfo.objects.get(name='rain')
#查找所有
models.UserInfo.objects.all()
#查找指定条件
models.UserInfo.objects.filter(age=18)
#查找第一个
models.UserInfo.objects.filter(age=18).first()
#查找所有并且显示出来
user_list_obj = models.UserInfo.objects.all()
for line in user_list_obj:
	print(line.username,line.age)

进阶操作

  • 利用双下划线将字段和对应的操作连接起来
	 # 获取个数
	 
    models.Tb1.objects.filter(name='seven').count()

    # 大于,小于
 
    models.Tb1.objects.filter(id__gt=1)              # 获取id大于1的值
    models.Tb1.objects.filter(id__lt=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

    # 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

    # limit 、offset
   
    models.Tb1.objects.all()[10:20]

    # 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"
  • F和Q操作
# F 使用查询条件的值

from django.db.models import F
models.Tb1.objects.update(num=F('num')+1)

# Q 构建搜索条件
from django.db.models import Q
con = Q()

q1 = Q()
q1.connector = 'OR'
q1.children.append(('id', 1))
q1.children.append(('id', 10))
q1.children.append(('id', 9))

q2 = Q()
q2.connector = 'OR'
q2.children.append(('c1', 1))
q2.children.append(('c1', 10))
q2.children.append(('c1', 9))

con.add(q1, 'AND')
con.add(q2, 'AND')

models.Tb1.objects.filter(con)

from django.db import connection
cursor = connection.cursor()
cursor.execute("""SELECT * from tb where name = %s""", ['Lennon'])
row = cursor.fetchone()

连表操作

连表关系:

  • 一对多,models.ForeignKey(ColorDic)
  • 一对一,models.OneToOneField(OneModel)
  • 多对多,authors = models.ManyToManyField(Author)

应用场景:

  • 一对一:在某表中创建一行数据时,有一个单选的下拉框(下拉框中的内容被用过一次就消失了)。
    例如:原有含10列数据的一张表保存相关信息,经过一段时间之后,10列无法满足需求,需要为原来的表再添加5列数据。
  • 一对多:当一张表中创建一行数据时,有一个单选的下拉框(可以被重复选择)。
    例如:创建用户信息时候,需要选择一个用户类型【普通用户】【金牌用户】【铂金用户】等。
  • 多对多:在某表中创建一行数据是,有一个可以多选的下拉框。
    例如:创建用户信息,需要为用户指定多个爱好。

一对多

  • 数据库表:models.py
    UserType存放用户类型,UserInfo存放用户信息

from django.db import models
# Create your models here.

class UserType(models.Model):
	caption = models.CharField(max_length=32)
		# 超级管理员,普通用户,游客,黑河
	def __str__(self):
		return self.caption

class UserInfo(models.Model):
    user = models.CharField(max_length=32)
    pwd = models.CharField(max_length=32)
    user_type = models.ForeignKey('UserType')
  • 创建有外键的数据
#方法一:需要进行两次数据库操作,不推荐
UserInfo.objects.create(user='test',pwd='123',user_type=UserType.objects.get(id=1))
#方法二:利用外键关系进行直接插入值,此时user_type_id其实就是本表中的一个字段,但是逻辑上user_type是指的user_type表,所以user_type_id相当于跨表到了user_type
UserInfo.objects.create(user='test',pwd='123',user_type_id=1)

>>> from app01 import models
>>> models.UserInfo.objects.create(user='test',pwd='123',user_type=models.UserType.objects.get(id=1))
<UserInfo: UserInfo object>
>>> models.UserInfo.objects.create(user='asdasdadas',pwd='123',user_type_id=3)
<UserInfo: UserInfo object>

  • 数据:

  • 查找

1.根据用户,查找用类型

>>> models.UserInfo.objects.filter(user="test")[0].user_type.caption
'管理员'
此时user_type对应的就是usertype的表,所以直接使用.caption就可以拿到数据

2.根据用户类型查找用户

#方法一:先查找出用户类型对应的user_type的id,然后再去userinfo表中查找id对应的用户
>>> role_id = models.UserType.objects.get(caption='管理员').id
>>> role_id
1
>>> models.UserInfo.objects.filter(user_type=role_id).values('user','pwd')
<QuerySet [{'pwd': '123', 'user': '张三'}, {'pwd': '123', 'user': 'test2'}, {'pwd': '123', 'user': 'test'}]>

#方法二:使用双下划线进行一次连表操作
>>> models.UserInfo.objects.filter(user_type__caption="管理员")
<QuerySet [<UserInfo: UserInfo object>, <UserInfo: UserInfo object>, <UserInfo: UserInfo object>]>
>>> sql[0].user
'张三'
>>> sql[0].pwd
'123'
>>> sql[0].user_type.caption
'管理员'
>>> sql[0].user_type.id
1

继续封装,同时取用户的所有信息:
>>> sql = models.UserInfo.objects.filter(user_type__caption="管理员").values('user','pwd','user_type__id','user_type__caption')
>>> sql
<QuerySet [{'user_type__id': 1, 'pwd': '123', 'user': '张三', 'user_type__caption': '管理员'}, {'user_type__id': 1, 'pwd': '123', 'user': 'test2', 'user_type__caption': '管理员'}, {'user_type__'pwd': '123', 'user': 'test', 'user_type__caption': '管理员'}]>


打印sql语句:
>>> print(sql.query)
SELECT "app01_userinfo"."user", "app01_userinfo"."pwd", "app01_userinfo"."user_type_id", "app01_usertype"."caption" FROM "app01_userinfo" INNER JOIN "app01_usertype" ON ("app01_userinfo"."user_type_id" = "app01_usertype"."id") WHERE "app01_usertype"."caption" = 管理员


跨多张表进行操作,如果UserType表中还有外键指向另一张表的主键,怎么查呢?
新的表结构如下:


from django.db import models
# Create your models here.

class UserType(models.Model):
	caption = models.CharField(max_length=32) # 超级管理员,普通用户,游客,黑河
	s = models.ForeignKey('something')
	def __str__(self):
		return self.caption

class UserInfo(models.Model):
    user = models.CharField(max_length=32)
    pwd = models.CharField(max_length=32)
    user_type = models.ForeignKey('UserType')
    
class something(models.Model):
	name = models.CharField(max_length=32)

查询:

models.UserInfo.objects.filter(user_type__s__name="一些条件值"

这是跨两张表,跨三张表、四张表都这样

ForeignKey 外键关联的配置

  • on_delete: 当删除 "一" 模型对象时,django会根据该参数的值对与该对象相关联的其他对象(也就是 ‘多’)进行操作。
    • models.CASCADE: 默认为models.CASCADE 级联删除。当删除'一'时,‘多’会被删除
    • modles.PROTECT : 当删除一个具有外键关系的对象时,会引发一个异常,阻止删除该对象
    • models.SET_NULL: 设置删除对象所关联的外键字段为null。但字段的null属性必需为True
    • models.SET_DEFAULT : 设置删除对象所关联的外键字段为默认的值。
    • models.SET(value) :设置删除对象所关联的对象的外键字段为value,value也可以是一个可调用函数
    • models.DO_NOTHING : 不做任何操作
  • related_name 设置从关联对象到自身的关系的名称,若值为'+' 则关联对象与自身无逆向关系
  • to_field 设置所关联对象的关联字段。默认为关联对象的主键字段

多对多

  • 表结构:
    一个girl表、一个boy表,还一个boy_girl的关系表
class Girl(models.Model):
	name = models.CharField(max_length=32)
	b = models.ManyToManyField('Boy')


class Boy(models.Model):
	name = models.CharField(max_length=32)

PS:多对多关系需要三张表,两张数据表,一张关系表,但是在django 中如果使用ManyToManyField的话,不需要在指定第三张表,默认django会创建。当然,如果不使用该字段的话,也可以手动指定第三张表,然后使用models.ForeignKey做外键关联

  • 添加数据

添加数据到关系表:

女孩跟男孩建立关系   正向操作
>>> G = models.Girl.objects.get(id=1)
>>> g = models.Girl.objects.get(id=1)
>>> girl = models.Girl.objects.get(id=1)
>>> boy = models.Boy.objects.get(id=3)
>>> girl.name
'fuzj3'
>>> boy.name
'fuzj2'

#使用对象建立关系

>>> girl.b.add(boy)			#此时的b为多对多的字段
>>> bs = models.Boy.objects.all()   #获取男孩的所有对象,返回数组
>>> g.b.add(*bs)		#批量将关系插入到关系表

#使用主键值建立关系
>>> girl = models.Girl.objects.get(id=3)
>>> girl.b.add(3)
>>> bs_list = [1,4,5]
>>> girl.b.add(*bs_list)


男孩跟女孩建立关系  反向操作

>>> boy = models.Boy.objects.get(id=1)
>>> boy
<Boy: Boy object>
>>> boy.girl_set.add(3)

  • 删除

    remove() 删除
    clear() 清空

>>> g1 = models.Girl.objects.get(id=1)   #获取一个女孩对象
>>> g1.b.remove(2)				#单个删除一个关系
>>> g1.b.remove(*[3,4])		#批量删除多个关系
>>> g1.b.clear()				#清空本对象对应的所有关系

  • 查询
    支持all() filer()等操作

    1. 通过女孩查找男孩(正向查找)

      >>> models.Girl.objects.filter(name='fuzj2').values('id','name','b__name')
      <QuerySet [{'name': 'fuzj2', 'id': 3, 'b__name': 'fuzj'}, {'name': 'fuzj2', 'id': 3, 'b__name': 'fuzj2'}, {'name': 'fuzj2', 'id': 3, 'b__name': 'fuzj3'}, {'name': 'fuzj2', 'id': 3, 'b__name': None}]>
      
      'b__name'中 b此时代指的关系表,所以b__name 就是跨到了boy表,。此时相当于直接跨了两张表
      
    2. 通过男孩查找女孩(反向查找)

      >>> models.Boy.objects.filter(name='fuzj').values('id','name','girl__name')
      <QuerySet [{'name': 'fuzj', 'id': 1, 'girl__name': 'fuzj2'}]>
      
      'girl__name' 中,girl是boy表中隐藏的字段,代指的是和girl的关系表,所以girl__name就跨到了girl表
      
      
  • 修改

    默认django不支持修改操作,如果实现修改操作,只能是先删除,然后再创建,显然这个效率不是很高。所以,我们可以通过原生的sql语句进行操作

from django.db import connection
cursor = connection.cursor()
cursor.execute("update tbname set girl_id = '3' where boy_id = %s",[3])

ManyToManyField 多对多字段

  • othermodel: 所关联的model名称
  • db_table: 多对多关系会在两个模型所对应的表中间创建一个‘中间表’ ,将多对多转换为两个多对一,该选项为这个中间表设置名称。一般来说django会默认为中间表创建名称,但人们读起来可能搞不清楚究竟中间表关联到了哪里。
  • related_name: 同多对一字段中的related_name
  • symmetrical: 当多对多关联对象为自身时可能会用到的参数。默认为True。a,b同属于person模型,person中的friends字段与自身设置了多对多关系,当该值设置为True时,django假定关系为对称,即:a是b的朋友,那么b也是a的朋友。设置为False时,django会强制为逆向关系创建描述信息。
  • though: 不想让django自动创建中间表,手动创建中间表所对应的model,通过though指定对应的model名称。
  • though_field: 当though参数被使用时,该参数才会有效。指定使用哪些中间模型字段来确立两个模型的多对多关系。
posted @ 2017-01-22 13:43  Fuzengjie  阅读(383)  评论(0)    收藏  举报