Django模型层ORM学习笔记

一. 铺垫

1. 链接Django自带数据库sqlite3

  以前提到过Django自带一个叫作sqlite3的小型数据库,当咱们作本地测试时,能够直接在sqlite3上测试。不过该数据库是小型的,在有些细节可能体验不大好,好比用ORM用双下划线查询语法时,使用__contains和__icontains的结果是同样的,由于sqlite3不管怎么样都不区分大小写,并且它还会自动把日期格式的字段转为时间戳(该体验贼差)。python

  不过除此以外还好,目前也没发现其余问题,作一些数据的小测试仍是绰绰有余的。mysql

  1.1 项目settings.py文件git

  链接其余数据库时,咱们须要修改settings.py里面的相关配置,不过默认的配置就是sqlite3的,因此咱们不须要修改涉及数据库的配置。sql

  回忆一下,链接其余数据库时(以链接myqsl数据库为例),应该修改成如下配置:数据库

  1.2 修改应用下或项目下的的__init__.py文件django

  跟链接其余数据库同样,须要在__init__.py中加入替换操做数据库的模块的语句:并发

import pymysql

pymysql.install_as_MySQLdb()

  1.3 链接sqlite3数据库app

  选择链接sqlite3数据库:框架

  

  安装驱动,测试链接成功后点击OK链接sqlite数据库:less

  

   1.3步骤执行完毕后,咱们能够将下图显示的那个数据库删除(固然留着也没事)。

       

  1.4 在模型层中写几个映射数据库中表的类

from django.db import models

# Create your models here.


class User(models.Model):
    name = models.CharField(max_length=32)
    age = models.IntegerField()
    register_time = models.DateField()

   1.5 执行数据库迁移命令(可使用Tools中的Run manage.py Task)

#pycharm下方点击Terminal打开命令行窗口,执行如下两句命令
python3 manage.py makemigrations

python3 manage.py migrate

  执行完数据库迁移命令后,咱们会发现项目中出现了db.sqlite3数据库,直接双击打开:

  

 

 

 

 

  1.6 数据库sqlite3链接完成

2. 测试ORM的准备工做

  数据库链接完毕后,咱们能够选择新建.py文件或者使用应用文件夹下自带的tests.py来导入模型层models.py中的类来熟悉一下ORM语句,不过在这以前要作一些准备工做,否则当你经过ORM操做数据库时会报错。

  咱们直接使用应用文件夹下自带的tests.py文件测试ORM。首先输入如下语句(前几行能够从manage.py中复制)。

from django.test import TestCase

# Create your tests here.
import os


if __name__ == "__main__":
    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "day58.settings")
    import django
    django.setup()
    # 以上语句固定写法,接下来写导入models模块的语句
    from app01 import models
    # 从这开始正常写ORM操做数据库的语句便可

3.  查看ORM操做数据库内部走的mysql语句

  当咱们操做数据库拿回来的是QuerySet对象是,咱们能够经过QuerySet对象.query查看内部的sql语句,那么返回的不是QuerySet对象时该怎么作呢?只须要在settings.py中找个地方将下面语句放着便可(运用日志)。

配置文件配置参数查看全部orm操做内部的sql语句
LOGGING = {
            'version': 1,
            'disable_existing_loggers': False,
            'handlers': {
                'console':{
                    'level':'DEBUG',
                    'class':'logging.StreamHandler',
                },
            },
            'loggers': {
                'django.db.backends': {
                    'handlers': ['console'],
                    'propagate': True,
                    'level':'DEBUG',
                },
            }
        }
View Code

二. ORM单表查询、双下划线查询

  为了更好的了解ORM对数据库的操做,咱们选择链接mysql数据库,毕竟sqlite3仍是有点小瑕疵的。

from django.db import models

# Create your models here.
class Book(models.Model):
    title = models.CharField(max_length=32)
    price = models.DecimalField(max_digits=8, decimal_places=2)
    publish_time = models.DateField(auto_now_add=True)
    publish = models.ForeignKey(to='Publish')
    authors = models.ManyToManyField(to='Author')


class Publish(models.Model):
    name = models.CharField(max_length=32)
    addr = models.CharField(max_length=32)
    email = models.EmailField()


class Author(models.Model):
    name = models.CharField(max_length=32)
    age = models.IntegerField()
    author_detail = models.OneToOneField(to='AuthorDetail')


class AuthorDetail(models.Model):
    phone = models.CharField(max_length=32)
    addr = models.CharField(max_length=32)
models.py中建立的类

   ORM有不少经常使用字段,其中字段DateField的参数有auto_now跟auto_now_add,若是咱们配置了这两个参数中的一个,建立数据对象时DateField字段会自动建立,无需咱们传值。配置auto_now_add=True,建立数据记录的时候会把当前时间添加到数据库,以后就不在变化。配置上auto_now=True,每次更新数据记录的时候会更新该字段。友情提示,DateFIeld和DateTImeField能够直接接收datetime对象。

  ForeignKey有to_field参数,能够指定你想跟一张表的什么字段创建外键,不写默认是id。

  当使用数据对象进行数据的save()和delete()时,实际上找的是类Model中的方法(属性与方法的查找顺序),因此咱们能够经过重写save、delete方法来对数据对象保存和删除的过程加以限制。

1. 单表查询

  1.1 新增数据

# 第一种:有返回值,而且就是当前被建立的数据对象
modles.Publish.objects.create(name='',addr='',email='')

# 第二种:先实例化产生对象,而后调用save方法保存
book_obj = models.Publish(name='',addr='',email='')
book_obj.save()

  1.2 修改数据

# 基于数据对象
user_obj = models.User.objects.filter(name='jason').first()
user_obj.age = 17
user_obj.save()

# 基于queryset对象
models.User.objects.filter(name='kevin').update(age=66)

  1.3 删除数据

# 基于数据对象
# user_obj = models.User.objects.filter(name='owen').first()
# user_obj.delete()

# 基于queryset对象
 models.User.objects.filter(name='egon').delete()

  1.4 查询数据

  以前经常使用的查询是all(惰性查询)查全部及filter条件查询,其中filter条件查询有多个条件时,各条件是and的关系。

models.User.objects.filter(name='egon', age=18) # name='egon' and 'age'=18

  其实查询数据能用到的方法一共有13个(objects对象和QuerySet对象方法),最好都记住。而后QuerySet对象可以无限制的点QuerySet方法(后面点方法可能会没有提示,别慌,继续手打):

# 在过滤获得的QuerySet对象的基础上再进行过滤,依次类推
models.User.objects.filter(过滤条件1).filter(过滤条件2).order_by(排序依据的字段名).reverse()
# reverse方法使用的前提是QuerySet对象被排序过,order_by是排序(排序依据的字段名前加-号便是反向排序)
<1> all():                 #查询全部结果
<2> filter(**kwargs):      #它包含了与所给筛选条件相匹配的对象
<3> get(**kwargs):         #返回与所给筛选条件相匹配的对象,返回结果有且只有一个,若是符合筛选条件的对象超过一个或者没有都会抛出错误。
<4> exclude(**kwargs):     #它包含了与所给筛选条件不匹配的对象
<5> order_by(*field):      #对查询结果排序('-id')/('price')
                    
<6> reverse():             #对查询结果反向排序     >>>前面要先有排序才能反向
<7> count():               #返回数据库中匹配查询(QuerySet)的对象数量。
<8> first():               #返回第一条记录
<9> last():                #返回最后一条记录
<10> exists():             #若是QuerySet包含数据,就返回True,不然返回False
<11> values(*field):       #返回一个ValueQuerySet——一个特殊的QuerySet,运行后获得的并非一系列model的实例化对象,而是一个可迭代的字典序列
<12> values_list(*field):  #它与values()很是类似,它返回的是一个元组序列,values返回的是一个字典序列
<13> distinct():           #从返回结果中剔除重复纪录
查询用到的13种方法

   着重记住values方法(普通QuerySet对象:<QuerySet [<Author: Author object>]>):

  在上述13种方法中,有些方法执行完返回的不必定是QuerySet对象,多是其余对象。

# 返回QuerySet对象的方法
all()、filter()、exclude()、order_by()、reverse()、distinct()

# 特殊的QuerySet
values()        #返回一个可迭代的字典序列
values_list()  #返回一个可迭代的元祖序列

# 返回具体数据对象的
get()、first()、last()

# 返回布尔值的方法
exists() #判断QuerySet对象是否为空,空返回False,不然返回True

# 返回数字的方法
count()  #返回当前QuerySet对象中的数据对象个数

  舒适提示:all()跟filter()是惰性查询,即返回QuerySet对象,只有调用QuerySet对象时内部的sql语句才会执行(这就是惰性的精髓)。objects是管理器对象(objects = Manage()),是Models和数据库进行查询的接口。Manage存在于models模块中,因此咱们实际上是能够自定义一个类,继承models.Manage来定义本身的管理器对象的。

2. 双下划线查询

  上述的查询中,filter的查询条件都是name='值',age=值之类的,但是咱们查询时条件确定会有age>18,age<=18等状况。这个时候就须要用的双下划线查询。

  2.1 大于 小于 大于等于 小于等于

filter(price__gt=90)   # 大于 great than
filter(price__lt=90)    # 小于 less than
filter(price__gte=90) # 大于等于 great than equal
filter(price__lte=90)  # 小于等与 less than equal

  2.2 存在于某几个条件中

filter(age__in=[11,22,33])

  2.3 在某个范围内

filter(age__range=[50,90])

  2.4 模糊查询

filter(title__contains='p')   # 区分大小写
filter(title__icontains='P')  # 不区分大小写

  2.5 以什么开头,以什么结尾

# 查询名字以j开头的用户
res = models.User.objects.filter(name__startswith='j')
print(res)

# 查询名字以n结尾的用户
res = models.User.objects.filter(name__endswith='n')
print(res)

  2.6 按年查询(针对DateField和针对DateTImeField

filter(create_time__year='2017')

三. 多表操做

1. 一对多记录增删改查

  1.1 新增(主键用pk传比较好,比较稳)

 # 直接写id
models.Book.objects.create(title='红楼梦',price=66.66,publish_id=1)

# 传数据对象
publish_obj = models.Publish.objects.filter(pk=2).first()
models.Book.objects.create(title='三国演义',price=199.99,publish=publish_obj)

  1.2 修改

# Queryset修改
models.Book.objects.filter(pk=1).update(publish_id=3)
publish_obj = models.Publish.objects.filter(pk=2).first()
models.Book.objects.filter(pk=1).update(publish=publish_obj)

# 对象修改
book_obj = models.Book.objects.filter(pk=1).first()
book_obj.publish_id = 3  # 点表中真实存在的字段名
book_obj.save()

publish_obj = models.Publish.objects.filter(pk=2).first()
book_obj.publish = publish_obj  # 点orm中字段名 传该字段对应的表的数据对象
book_obj.save()

  1.3 删除

# 使用QuerySet对象删除
models.Book.objects.filter(pk=1).delete()
models.Publish.objects.filter(pk=1).delete()

# 使用数据对象删除
book_obj = models.Book.objects.filter(pk=3).first()
book_obj.delete()

2. 多对多记录增删改查

  2.1 添加(add)

# 拿到id=3的书籍数据对象
book_obj = models.Book.objects.filter(pk=3).first()

# 数据对象.authors能够直接跳到多对多那张表里
# add传值传做者id,能够传多个
book_obj.authors.add(1)
book_obj.authors.add(2,3)

# add传值支持传对象,并且能够传多个
author_obj = models.Author.objects.filter(pk=1).first()
author_obj1 = models.Author.objects.filter(pk=3).first()
book_obj.authors.add(author_obj)
book_obj.authors.add(author_obj,autor_obj1)

   2.2 修改(set)

   set接收的参数必须是可迭代对象!!!

# 拿到id=3的书籍数据对象
book_obj = models.Book.objects.filter(pk=3).first()

# 数据对象.authors能够直接跳到多对多那张表里
# set传值传做者id,能够传多个
book_obj.authors.set((1,))
book_obj.authors.set((1,2,3))

# set传值支持传对象,并且能够传多个
author_list = models.Author.objects.all()
book_obj = models.Book.objects.filter(pk=3).first()
book_obj.authors.set(author_list)

   2.3 删除(remove

# 拿到id=3的书籍数据对象
book_obj = models.Book.objects.filter(pk=3).first()

# 数据对象.authors能够直接跳到多对多那张表里
# remove传值支持传值,并且能够传多个
book_obj.authors.remove(1)
book_obj.authors.remove(2,3)

# remove传值支持传对象,并且能够传多个
author_obj = models.Author.objects.all().first()
author_list = models.Author.objects.all()
book_obj.authors.remove(author_obj)
book_obj.authors.remove(*author_list)  #须要将Queryset对象打散

   2.4 清空(clear)

   清空的是你当前这个表记录对应的绑定关系,不会影响其余表。

book_obj = models.Book.objects.filter(pk=3).first()
book_obj.authors.clear()

 3. 正向反向查询

  正向反向查询概念及方法:

# 一对一
# 正向:author---关联字段在author表里--->authordetail        按字段
# 反向:authordetail---关联字段在author表里--->author        按表名小写
    # 查询jason做者的手机号   正向查询
    # 查询地址是 :山东 的做者名字   反向查询
  
# 一对多
# 正向:book---关联字段在book表里--->publish        按字段
# 反向:publish---关联字段在book表里--->book        按表名小写_set.all() 由于一个出版社对应着多个图书

# 多对多
# 正向:book---关联字段在book表里--->author        按字段
# 反向:author---关联字段在book表里--->book        按表名小写_set.all() 由于一个做者对应着多个图书
  
  

# 连续跨表
    # 查询图书是三国演义的做者的手机号,先查书,再正向查到做者,在正向查手机号

# 总结:基于对象的查询都是子查询,这里能够用django配置文件自动打印sql语句的配置作演示
View Code  

  3.1 基于对象的表查询

# 查询书籍是三国演义的出版社邮箱
book_obj = models.Book.objects.filter(title='三国演义').first()
print(book_obj.publish.email)

# 查询书籍是水浒传的做者的姓名
book_obj = models.Book.objects.filter(title='水浒传').first()
print(book_obj.authors)  # app01.Author.None
print(book_obj.authors.all())

# 查询做者为jason电话号码
user_obj = models.Author.objects.filter(name='jason').first()
print(user_obj.authordetail.phone)
正向查询示例
# 查询出版社是东方出版社出版的书籍   一对多字段的反向查询
publish_obj = models.Publish.objects.filter(name='东方出版社').first()
print(publish_obj.book_set)  # app01.Book.None
print(publish_obj.book_set.all())

# 查询做者jason写过的全部的书           多对多字段的反向查询
author_obj = models.Author.objects.filter(name='jason').first()
print(author_obj.book_set)  # app01.Book.None
print(author_obj.book_set.all())

# 查询做者电话号码是110的做者姓名     一对一字段的反向查询
authordetail_obj = models.AuthorDetail.objects.filter(phone=110).first()
print(authordetail_obj.author.name)
反向查询示例

    3.2 基于双下划线的查询

# 查询书籍为三国演义的出版社地址
res = models.Book.objects.filter(title='三国演义').values('publish__addr','title')
print(res)

# 查询书籍为水浒传的做者的姓名
res = models.Book.objects.filter(title='水浒传').values("authors__name",'title')
print(res)

# 查询做者为jason的家乡
res = models.Author.objects.filter(name='jason').values('authordetail__addr')
print(res)
正向示例
# 查询南方出版社出版的书名
res = models.Publish.objects.filter(name='南方出版社').values('book__title')
print(res)

# 查询电话号码为120的做者姓名
res = models.AuthorDetail.objects.filter(phone=120).values('author__name')
print(res)

# 查询做者为jason的写的书的名字
res = models.Author.objects.filter(name='jason').values('book__title')
print(res)

# 查询书籍为三国演义的做者的电话号码
res = models.Book.objects.filter(title='三国演义').values('authors__authordetail__phone')
print(res)
反向示例

    3.3 小练习

# 查询jason做者的手机号
# 正向
res = models.Author.objects.filter(name='jason').values('authordetail__phone')
print(res)
# 反向
res = models.AuthorDetail.objects.filter(author__name='jason').values('phone')
print(res)

# 查询出版社为东方出版社的全部图书的名字和价格
# 正向
res = models.Publish.objects.filter(name='东方出版社').values('book__title','book__price')
# print(res)
反向
# res = models.Book.objects.filter(publish__name='东方出版社').values('title','price')
print(res)

# 查询东方出版社出版的价格大于400的书
# 正向
res = models.Publish.objects.filter(name="东方出版社",book__price__gt=400).values('book__title','book__price')
print(res)
# 反向
res = models.Book.objects.filter(price__gt=400,publish__name='东方出版社').values('title','price')
print(res)
View Code

  在查询的时候先把orm查询语句写出来,再看用到的条件是否在当前表内,在就直接获取,不在就按照正向按字段反向按表名小写来查便可。切忌一口吃成胖子。

4 聚合查询(aggregate)

  须要先导入模块:

from django.db.models import Max,Min,Count,Sum,Avg
# 查询全部书籍的做者个数
res = models.Book.objects.filter(pk=3).aggregate(count_num=Count('authors'))
print(res)

# 查询全部出版社出版的书的平均价格
res = models.Publish.objects.aggregate(avg_price=Avg('book__price'))
print(res)  # 4498.636

# 统计东方出版社出版的书籍的个数
res = models.Publish.objects.filter(name='东方出版社').aggregate(count_num=Count('book__id'))
print(res)
聚合查询例子

5 分组查询(annotate)

# 统计每一个出版社出版的书的平均价格
res = models.Publish.objects.annotate(avg_price=Avg('book__price')).values('name','avg_price')
print(res)

# 统计每一本书的做者个数
res = models.Book.objects.annotate(count_num=Count('authors')).values('title','count_num')
print(res)

# 统计出每一个出版社卖的最便宜的书的价格
res = models.Publish.objects.annotate(min_price=Min('book__price')).values('name','min_price')
print(res)

# 查询每一个做者出的书的总价格
res = models.Author.objects.annotate(sum_price=Sum('book__price')).values('name','sum_price')
print(res)
分组查询例子

 四. 其余

1. F、Q查询

  目前为止咱们filter的条件的值都是咱们本身给的,好比age=18。并且filter多个查询条件时,它们是and的关系。当咱们查询条件的值是来自表中某字段的值,或者咱们查询条件是or的关系,咱们就要引入F、Q查询。

  首先F、Q使用前要先导入:

from django.db.models import F,Q

  1.1 F查询

  假若有一张服装店的销售表(商品、价格、库存、销量),当咱们想要查询销量大于50的商品时很好实现:

res = models.Product.objects.filter(sell__gt=50)
print(res)

  当咱们要查询销量大于库存的商品时,就要使用F查询了:

from django.db.models import F,Q
# F查询
res = models.Product.objects.filter(sell__gt=F('stock'))
print(res)

  将全部商品的价格提升100:

models.Product.objects.update(price=F('price')+100)

  将全部商品的名字后面都加一个爆款:

# 是否是本能会这么想?注意,这是错误的写法,由于ORM不支持+拼接字符串
models.Product.objects.update(price=F('name')+'爆款')

  ORM不支持+拼接字符串,mysql中咱们拼接字符串要用concat,此处同理:

# 要进行字符串的拼接须要先导入Concat和Value模块
from django.db.models.functions import Concat
from django.db.models import Value

models.Product.objects.update(name=Concat(F('name'), Value('爆款')))

  1.2 Q查询

  Q查询能够将filter中的查询条件变成or的关系,并且还能经过实例化对象的方法实现属性能够是字符串的形式(查询时原本要写name='xxx',Q查询能够实现'name'='xxx')。

  注意:Q对象必须放在普通的过滤条件前面。

# Q查询
res = models.Product.objects.filter(price=188.88, name='连衣裙爆款')
print(res)
from django.db.models import F, Q
res = models.Product.objects.filter(Q(price=188.88), Q(name='连衣裙爆款'))  # and

res1 = models.Product.objects.filter(Q(price=188.88)|Q(name='连衣裙爆款'))  # or

res2 = models.Product.objects.filter(Q(price=188.88)|~Q(name='连衣裙爆款'))  # not

# 混合使用  须要注意的是Q对象必须放在普通的过滤条件前面
res3 = models.Product.objects.filter(~Q(name='连衣裙爆款'), price=188.88)  # not
上图代码

   前面说Q查询能够实现查询条件写成'name'='xxx'的格式(好比说咱们写一个函数,根据用户输入去数据库中查询,而用户输入都是字符串的形式)。也许你会进行如下尝试:

user_input = 'name'
res = models.Author.objects.filter(eval(user_input)='jason')
print(res)

   而后就会立刻迎来喜报:

  要实现该需求,咱们须要使用Q实例化出的对象来实现(先来看一下Q的源码):

  实现的代码以下:

from django.db.models import F, Q
q = Q()  # 先实例化出一个Q的对象
q.connector = 'or'  # 经过这个参数能够将Q对象默认的and关系变成or

q.children.append(('price', 188.88))
q.children.append(('name', '高跟鞋爆款'))

res = models.Product.objects.filter(q)  # Q对象查询默认是and,上方截图为证
print(res)
上图代码

 2. 事务

  2.1 事务的四大特性:

  Atomic(原子性):事务中包含的操做被看作一个逻辑单元,这个逻辑单元中的操做要么所有成 功,要么所有失败。

  Consistency(一致性):事务完成时,数据必须处于一致状态,数据的完整性约束没有被破坏,事务在执行过程当中发生错误,会被回滚(Rollback)到事务开始前的状态,就像这个事务历来没    有执行过同样。

  Isolation(隔离性):事务容许多个用户对同一个数据进行并发访问,而不破坏数据的正确性 和完整性。同时,并行事务的修改必须与其余并行事务的修改相互独立。

  Durability(持久性):事务结束后,事务处理的结果必须可以获得固化。

  2.2 事务的语法

  在sql语句中使用事务时,咱们须要用start开启事务,又要用end结束事务,这就须要咱们判断事务什么时候开始和结束比较好。而在Django的ORM中,直接使用上下文管理便可,省事又省心。

  这里直接拿上面提到过的销售表作示例,好比一件商品卖出后,销量要+1,对应的库存要-1。

# 导入事务的模块
from django.db import transaction
from django.db.models import F
with transaction.atomic():  # atomic原子性,要么全成功,要么全失败
    # 在with代码块儿写你的事务操做
    models.Product.objects.filter(id=1).update(stock=F('stock')-1)
    models.Product.objects.filter(id=1).update(sell=F('sell')+1)
# 写其余代码逻辑
print('支付宝到帐~~~')

 3. only和defer

  only和defer是相反的两个过程,有点相似filter()和exclude()的区别。咱们知道values返回的是列表套字典形式的QuerySet对象,而only和defer返回的是列表套对象的QuerySet对象。

  以Product为例,当使用only('name')时,返回的对象只携带Product对象的name属性,若是用对象.未携带的属性,那么它会自动再去数据库中Product映射的表中查找该属性,有就带回来返回给你。defer正好相反,defer('name')表示携带除name以外的全部属性,当对象.name时,会自动去数据库中Product映射的表中找name属性带回来给你。注意:only和defer自动找数据库找属性时会走sql语句。

# 输出一下用values取出来的结果(列表套字典,键为'name')
test = models.Product.objects.values('name')
print(test)


# only取出来的是列表套对象,对象只有name属性
res = models.Product.objects.only('name')
for i in res:
    print(i.name)


# defer取出来的是列表套对象,对象除了name属性,其余属性都有
res1 = models.Product.objects.defer('name')
for i in res:
    print(i.name)

 4. 自定义字段

  Django支持自定义字段,须要继承models.Field类。

# 自定义字段,对应数据库中的Char类型
class MyCharField(models.Field):
    # 数据库中Char类型须要指定长度,因此要传max_length
    def __init__(self,max_length,*args,**kwargs):
        self.max_length = max_length
        # 调用父类init,必定要写关键字传参,由于Field的init参数不少,能够看一下它的源码
        super().__init__(max_length=max_length,*args,**kwargs)
    
    # 该方法也不能少
    def db_type(self, connection):
        return 'char(%s)'%self.max_length

   父类models.Field中的db_type方法

 

5. 字段中的choices属性

  提一下,当咱们给一个表新增一个字段时,若是表中已经有数据了,那么咱们能够将models.py中新增的字段名null设置默认值或者是设置为空。

# 设置默认值
gender = models.IntegerField(default=2)

# 容许为空
gender = models.IntegerField(null=True)

  choices属性使用的场景也挺多,好比性别,在数据库中咱们能够存储数字,好比1表明男,2表明女,而显示给用户看时,要转变为对应的男或女。

  简单示范一下:

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

    choices = ((1,''),(2,''),(3,'其余'))
    gender = models.IntegerField(choices=choices,default=2)

  这样数据库里存的就是数字了,那么取出来怎么变成对应的男、女呢:

res = models.User.objects.filter(id=1).first()
print(res.gender)
# 获取编号对应的中文注释,固定写法get_字段名_display()
print(res.get_gender_display())  


# 建立对象是传数字便可
models.User.objects.create(...gender=1)

五. 补充

1. MVC与MTV

  Django大体分为模型层(models)、模板层(templates)、视图层(views)、路由层(urls)。由于Django中控制器接受用户输入的部分由框架自行处理,因此 Django 里更关注的是模型models、模板templates和视图views,称为 MTV模式。不过本质上也是属于MVC框架(模型model,视图view和控制器controller)。

 2. 多对多表建立的三种方式

  以前建立测试ORM的表时,多对多关系的表是经过语句让ORM自动帮咱们建立的,实际上建立多对多的表有三种方式。

  第一种:Django主动咱们帮咱们建立

  该方法很方便,可是第三张表字段都是固定的,没法扩展

class Book(models.Model):
    name = models.CharField(max_length=32)
    # 该命令让Django自动帮咱们建立多对多关系的第三张表
    authors = models.ManyToManyField(to='Author')


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

  第二种:纯手动建立第三张表

  该方式能够在第三张表中增长额外的字段,可是没法像第一种方式建立的表同样直接利用ORM正向反向查询信息(好比book对象要查询Author表中的内容,只能是反向查询至Book2Author这张表,而后经过该表正向查询Author表的内容)。

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

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

class Book2Author(models.Model):
    # 经过建立多对多关系的两张表的外键来实现
    book = models.ForeignKey(to='Book')
    author = models.ForeignKey(to='Author')
    info = models.CharField(max_length=32)

   第三种:半自动建立

  当一个项目中对数据库扩展性有要求时,虽然第二种的确增长了扩展性,可是没法充分利用ORM的多表查询。接下来讲的第三种方法结合了前两种的优势。建议使用该方式,扩展性高,若是使用第一种,后期须要在多对多关系的表增长字段时,须要改动的地方不少。

  注意:使用第三种方式建立多对多关联关系时,就没法使用set、add、remove、clear方法来管理多对多的关系了,只能经过第三张表的model来管理多对多关系。当更改book对应的author信息时,能够先将book2author中该book对象对应的信息所有删除,而后再根据author信息从新建立数据,实际上ORM管理多对多表关系的set方法内部也是采用该方式。

class Book(models.Model):
    name = models.CharField(max_length=32)
    # 第三种建立表的方式
    authors = models.ManyToManyField(to='Author',through='Book2Author',through_fields=('book','author'))

class Author(models.Model):
    name = models.CharField(max_length=32)
    # 跟上面的ManyToManyField选一个写便可
    book = models.ManyToManyField(to='Book',through='Book2Author',through_fields=('author','book'))


class Book2Author(models.Model):
    book = models.ForeignKey(to='Book')
    author = models.ForeignKey(to='Author')
    info = models.CharField(max_length=32)

  小提示:

  1. 若是数据库迁移命令一直有问题,能够选择删除migrations下的文件(__init__.py不要删,否则再次执行数据库迁移命令时会报错)。
  2. 千万不要多个项目共用一个数据库,否则很容易出各类bug,有时候第1条问题的出现跟多项目共用数据库也有关系,严重的可能须要删库重建。
相关文章
相关标签/搜索