韩非囚秦
——独善其身者,难成大事也。

导航

 

一、创建model

  django.db.models是django自带的创建数据库的ORM。

  在models.py中以继承models.Model创建表后,需要在setttngs中确保添加了当前应用,并执行

    python3 manage.py makemigrations app[应用名称]

    python3 manage.py migrate app[应用名称]

  来生成迁移文件并提交到数据库执行建表操作。

  一、创建单张表

# models.py
from django.db import models
class Person(models.Model): name = models.CharField(max_length=30) age = models.CharField(max_length=30)
from app02.models import Person
p1 = Person(name="Jan", age=20)   # 声明一个实例,也就是一条记录
p1.save() # 必须保存
p2 = Person()
p2.name = "Li"   
p2.age = 18    # 可以声明一个实例,也可以修改一个字段,同样需要提交
p2.save()

  二、创建一对一表

  当一张既有的表需要扩充字段时,为了保持原有的表字段和结构不变,可以创建另一张表存储扩充的字段;第二张表的主键和第一张表的主键一一对应。

# models.py
from django.db import models

class Place(models.Model):
    name = models.CharField(max_length=50)
    address = models.CharField(max_length=80)

class Restaurant(models.Model): place = models.OneToOneField(Place,on_delete=models.CASCADE,primary_key=True) serves_hot_dogs = models.BooleanField(default=False) serves_pizza = models.BooleanField(default=False)
>>> p1 = Place(name='Demon Dogs', address='944 W. Fullerton')
>>> p1.save()
>>> p2 = Place(name='Ace Hardware', address='1013 N. Ashland')
>>> p2.save()
>>> r1 = Restaurant(place=p1, serves_hot_dogs=True, serves_pizza=False) # 插入记录时,如果需要同时插入扩充的字段,就在后面继续添加扩充表 >>> r1.save()
>>> p1.restaurant
>>> r2.place
>>> hasattr(p2, 'restaurant') # 可以用hasattr检查是否已插入扩充字段

  三、创建多对一表

# models.py
from django.db import models

class Reporter(models.Model):
    first_name = models.CharField(max_length=30)
    last_name = models.CharField(max_length=30)
    email = models.EmailField()
class Article(models.Model):
    headline = models.CharField(max_length=100)
    pub_date = models.DateField()
    reporter = models.ForeignKey(Reporter, on_delete=models.CASCADE)
>>> r1 = Reporter(first_name='John', last_name='Smith',
email='john@example.com')
>>> r1.save()    # 一定要save,否则下面的Article外键无法绑定需要的reporter字段
>>> r2 = Reporter(first_name='Paul', last_name='Jones', email='paul@example.com')
>>> r2.save()
>>> from datetime import date
>>> a1 = Article(id=None, headline="This is a test", pub_date=date(2005, 7, 27), reporter=r1)      # 正向添加-添加记录时需要指定reporter
>>> a1.save()
>>> a2 = Article.objects.create(headline="Paul's story", pub_date=date(2006, 1, 17), reporter=r2) # 正向添加-用管理器的方式添加,不需要save()
>>> r2.article_set.create(headline="John's second story", pub_date=date(2005, 7, 29)) # 反向添加-注意r2.article_set的方式
>>> r3 = Reporter(first_name="Jan", last_name="--", email="jan@example.com")
>>> r3.save()
>>> r3.article_set.add(a2) # 反向添加一个对象
>>> r3.artilce_set.remove(a2) # 反向删除

  add()和remove()是django默认的用于处理一对多或者多对多的增删操作。对于ForeignKey,只有“一”的那张表可以使用add和remove来一次性添加一个或者多个“多”的记录。对于ManyToManyField,两张表都可以使用add和remove添加或者删除一个或者多个记录。

  四、创建多对多表

# models.py
from django.db import models

class Publication(models.Model):
    title = models.CharField(max_length=30)
    def __str__(self):
        return self.title
    class Meta:
        ordering = ('title',)

class Article(models.Model):
    headline = models.CharField(max_length=100)
    publications = models.ManyToManyField(Publication)
    def __str__(self):
        return self.headline
    class Meta:
        ordering = ('headline',)
>>> p1 = Publication(title='The Python Journal')
>>> p1.save()
>>> p2 = Publication(title='Science News')
>>> p2.save()
>>> p3 = Publication(title='Science Weekly')
>>> p3.save()
>>> a1 = Article(headline='Django lets you build Web apps easily')
>>> a1.save()
>>> a1.publications.add(p1,p2,p3) # 直接用add添加一个或多个记录
>>> a2 = Article(headline='NASA uses Python') >>> a2.save()
>>>
new_publication = a2.publications.create(title='Highlights for Children') # 或者直接用管理器(models.objects.create)创建一条记录并添加进去
>>> p2.article_set.all() # 可以通过article_set访问
>>> a4 = Article(headline='NASA finds intelligent life on Earth') # 反向添加记录:可以先写好记录,再添加给另一张表 >>> a4.save() >>> p2.article_set.add(a4)
>>> new_article = p2.article_set.create(headline='Oxygen-free diet works wonders') # 或者也用管理器的方式添加

二、Field和字段

 名称  解释
AutoField 一个根据实际ID自动增长的IntegerField,通常不指定;如果不指定,一个主键字段将自动添加到模型中
BooleanField true/false 字段,此字段的默认表单控制是CheckboxInput 
NullBooleanField 支持null、true、false三种值
CharField(max_length=字符长度) 字符串,默认的表单样式是 TextInput
TextField 大文本字段,一般超过4000使用,默认的表单控件是Textarea
IntegerField 整数
DecimalField(max_digits=None, decimal_places=None) 使用python的Decimal实例表示的十进制浮点数;DecimalField.max_digits=位数总数,DecimalField.decimal_places=小数点后的数字位数
FloatField 用Python的float实例来表示的浮点数
DateField[auto_now=False, auto_now_add=False])

使用Python的datetime.date实例表示的日期;

参数DateField.auto_now:每次保存对象时,自动设置该字段为当前时间,用于"最后一次修改"的时间戳,它总是使用当前日期,默认为false;

参数DateField.auto_now_add:当对象第一次被创建时自动设置当前时间,用于创建的时间戳,它总是使用当前日期,默认为false

该字段默认对应的表单控件是一个TextInput. 在管理员站点添加了一个JavaScript写的日历控件,和一个“Today"的快捷按钮,包含了一个额外的invalid_date错误消息键

auto_now_add, auto_now, and default 这些设置是相互排斥的,他们之间的任何组合将会发生错误的结果

TimeField 使用Python的datetime.time实例表示的时间,参数同DateField
DateTimeField 使用Python的datetime.datetime实例表示的日期和时间,参数同DateField
FileField 一个上传文件的字段
ImageField 继承了FileField的所有属性和方法,但对上传的对象进行校验,确保它是个有效的image

   通过字段选项,可以实现对字段的约束;在字段对象时通过关键字参数指定。

 名称 解释
null 如果为True,Django 将空值以NULL 存储到数据库中,默认值是 False
blank 如果为True,则该字段允许为空白,默认值是 False;对比:null是数据库范畴的概念,blank是表单验证证范畴的
db_column 字段的名称,如果未指定,则使用属性的名称
db_index 若值为 True, 则在表中会为此字段创建索引
default 默认值
primary_key:若为 True 则该字段会成为模型的主键字段
unique 如果为 True, 这个字段在表中必须有唯一值;唯一索引
auto_now 创建时生成创建时间
auto_now_add 更新时自动更新当前时间
choices admin: 默认元组列表,user_type=[(1, "普通用户"), (2, "VIP用户"), (3, "超级用户")];modesl.IntegerField(choices=user_type);在admin中会自动显示这几个分类,但是对表无影响,可以是任意整数
verbose_name admin: 别名,支持中文
editable admin: 是否可以被编辑
error_message admin: 自定义错误信息
help_text admin: 帮助信息

三、自定义管理器

  objects是Manager类型的对象,用于与数据库进行交互。当定义模型类时没有指定管理器,则Django会为模型类提供一个名为objects的管理器,当为模型类指定管理器后,django不再为模型类生成名为objects的默认管理器。

  管理器是Django的模型进行数据库的查询操作的接口,Django应用的每个模型都拥有至少一个管理器。

  自定义管理器类主要用于两种情况:向管理器类中添加额外的方法,或者修改管理器返回的原始查询集:重写get_queryset()方法。

from django.db import models

class BookInfoManager(models.Model):
    """
    可以重写Model中的方法
    """
    def get_queryset(self):
        return super(BookInfo, self.get_queryset().filter(isdelete=False))

    # 创建BookInfo
    def create(self, name, pub_date):
        b = BookInfo()
        b.name = name
        b.headline = pub_date
        b.isdelete = False
        return b

class BookInfo(models.Model):
    name = models.CharField(max_length=20)
    headline = models.CharField(default="this's a python book")
    isdelete = models.BooleanField(default=False)
    # 自定义管理器被定义时,继承了默认管理器
    manager = BookInfoManager()

# BookInfo.manager.create(name="Jan")

四、数据库操作

  1、多对一操作

  1.批量添加

# models.py
from django.db import models

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

class City(models.Model):
    name = models.CharField(max_length=32)
    pro = models.ForeignKey("Province", to_field="id", on_delete=models.CASCADE)
# app01/insert_records.py

import os, django
# 添加django的环境配置
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "app.settings")
django.setup()

from app01.models import Province, City

city_dict = {"东莞": 2, "深圳": 2, "惠州": 2, "河源": 2, "泰安": 3, "青岛": 3, "济南": 3, "张家口": 1,"邢台": 1}
province_dict = {"河北": 1, "山东": 3, "广东": 2,}
province_records_dict
= {id: Province(id=id, name=name) for name, id in province_dict.items()} print(province_records_dict) # 先创建Province Province.objects.bulk_create(province_records_dict.values()) # 再创建City city_records_list = [City(pro=province_records_dict[id], name=name) for name, id in city_dict.items()] print(city_records_list) City.objects.bulk_create(city_records_list) print("ok")

  2.正向查询与反向查询

# 1.all - 查找全city表中的全部记录,返回所有的querySet
City.objects.all()
# 正向查询:指定获取的字段,外表需要用外键+双下划线的形式访问外键表中的字段;如果有两个表中的字段,相当于对两个表同时进行操作
City.objects.all().values("id", "name", "pro__id", "pro_name")
# 反向查询:默认会将外键表的模型类小写当做id,相当于city__id,它同样支持表名+双下划线+字段的形式查询
Province.objects.all().values("id", "name", "city", "city__name", "city__id")
# 2.filter - 过滤器
# 正向过滤: 根据某个外键表或者外表中的字段对外表记录进行过滤查询
City.objects.all().filter(pro__name="河北") # 过滤字段
# 反向过滤: 根据某个外键表或者外表中的字段对外键表进行过滤查询
Province.objects.all().filter(name="河北")[0].city_set.all()

  3、多对多操作

  1.批量添加

# models.py
from django.db import models

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

class Author(models.Model):
    name = models.CharField(max_length=32)
    book = models.ManyToManyField(Book, related_name="book")
import os, django
# 添加django的环境配置
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "app.settings")
django.setup()

from app01.models import *

Book.objects.all().delete()
Author.objects.all().delete()

book_dict = {1: "Python", 2: "Go", 3: "Linux", 4: "PHP"}
author_dict = {1: "Jan", 2: "Li", 3: "wise"}
together_dict = {
    "Jan": ["Python", "Go"],
    "Li": ["Linux", "Go"],
    "wise": ["PHP", "Go", "Python"]
}
# 根据以上信息创建ManyToMany
# 先创建两个表的记录
book_records_list = {name: Book(id=id, name=name) for id, name in book_dict.items()}
Book.objects.bulk_create(book_records_list.values())
author_records_list = {name: Author(id=id, name=name) for id, name in author_dict.items()}
Author.objects.bulk_create(author_records_list.values())
# 再根据关系写入数据库
for key, vlist in together_dict.items():
    # 获取书名对应的querySet
    for i in vlist:
        author_records_list[key].book.add(book_records_list[i])

  2、正向查询与反向查询

# 正向查找 
Author.objects.get(id=1).book.all()
# 反向查找
Book.objects.get(id=1).book.all() # 这里写.book.all()是因为在Author模型类中声明了related_name,默认的话是author_set.all()
Book.objects.get(id=1).book.all().values("id", "name", "book__name")
# 遍历
for item in Author.objects.values("id", "name", "book"):
  print(item["id"], item["name"], item["book"])

  3、基本查询

  1.返回querySet集合的方法

 名称  解释
filter 过滤器
exclude 排除满足条件的对象
order_by 查询结果排序
annotate 分组函数,在分组后的数据集上进行操作
distinct 去重
values 将querySet以字典形式返回到一个查询集里
raw 处理一个原始的sql语句
aggregate 聚合函数,在每个记录上进行操作

  2.返回单个对象

 名称  函数
get() 返回单个满足条件的对象
first() 返回第一个对象
last() 返回最后一个对象
exists() 判断查询集中是否有数据,如果有则返回True
count() 返回当前查询的总条数
select_related() 返回当前querySet的前一条和后一条数据

  3.字段查询

  实现where子名,作为方法filter()、exclude()、get()的参数。语法:属性名称__比较运算符=值。

1.exact:表示判等,大小写敏感;如果没有写“ 比较运算符”,表示判等
  filter(isDelete=False)
2.contains:是否包含,大小写敏感
  exclude(btitle__contains='传')
3.startswith、endswith:以value开头或结尾,大小写敏感
  exclude(btitle__endswith='传')
4.isnull、isnotnull:是否为null
  filter(btitle__isnull=False)
5.在前面加个i表示不区分大小写,如iexact、icontains、istarswith、iendswith
6.in:是否包含在范围内
  filter(pk__in=[1, 2, 3, 4, 5])
7.gt、gte、lt、lte:大于、大于等于、小于、小于等于
  filter(id__gt=3)
8.对year、month、day、week_day、hour、minute、second:对日期间类型的属性进行运算
  filter(bpub_date__year=1980)   filter(bpub_date__gt=date(1980, 12, 31))
9.查询的快捷方式:pk,pk表示primary key,默认的主键是id
  filter(pk__lt=6)

  4、跨表查询

  多对一或者多对多都可以使用模型类+双下划线+字段名的形式进行跨表操作。

Author.objects.filter(book__name="Go")
Book.objects.filter(book__name="Jan"

  5、聚合函数

  使用aggregate()函数返回聚合函数的值,函数包括(Avg,Count,Max,Min,Sum)。

from django.db.models import Max
maxDate = list.aggregate(Max('bpub_date'))

  6、其它相关

    # 1. Cast,用于做类型转换
    # v = models.UserInfo.objects.annotate(c=Cast('pwd', FloatField()))

    # 2. Coalesce,从前向后,查询第一个不为空的值
    # v = models.UserInfo.objects.annotate(c=Coalesce('name', 'pwd'))
    # v = models.UserInfo.objects.annotate(c=Coalesce(Value('666'),'name', 'pwd'))

    # 3. Concat,拼接
    # models.UserInfo.objects.update(name=Concat('name', 'pwd'))
    # models.UserInfo.objects.update(name=Concat('name', Value('666')))
    # models.UserInfo.objects.update(name=Concat('name', Value('666'),Value('999')))

    # 4.ConcatPair,拼接(仅两个参数)
    # v = models.UserInfo.objects.annotate(c=ConcatPair('name', 'pwd'))
    # v = models.UserInfo.objects.annotate(c=ConcatPair('name', Value('666')))

    # 5.Greatest,获取比较大的值;least 获取比较小的值;
    # v = models.UserInfo.objects.annotate(c=Greatest('id', 'pwd',output_field=FloatField()))

    # 6.Length,获取长度
    # v = models.UserInfo.objects.annotate(c=Length('name'))

    # 7. Lower,Upper,变大小写
    # v = models.UserInfo.objects.annotate(c=Lower('name'))
    # v = models.UserInfo.objects.annotate(c=Upper('name'))

    # 8. Now,获取当前时间
    # v = models.UserInfo.objects.annotate(c=Now())

    # 9. substr,子序列
    # v = models.UserInfo.objects.annotate(c=Substr('name',1,2))

    # ########### 时间类函数 ###########
    # 1. 时间截取,不保留其他:Extract, ExtractDay, ExtractHour, ExtractMinute, ExtractMonth,ExtractSecond, ExtractWeekDay, ExtractYear,
    # v = models.UserInfo.objects.annotate(c=functions.ExtractYear('ctime'))
    # v = models.UserInfo.objects.annotate(c=functions.ExtractMonth('ctime'))
    # v = models.UserInfo.objects.annotate(c=functions.ExtractDay('ctime'))
    #
    # v = models.UserInfo.objects.annotate(c=functions.Extract('ctime', 'year'))
    # v = models.UserInfo.objects.annotate(c=functions.Extract('ctime', 'month'))
    # v = models.UserInfo.objects.annotate(c=functions.Extract('ctime', 'year_month'))
    """
    MICROSECOND
    SECOND
    MINUTE
    HOUR
    DAY
    WEEK
    MONTH
    QUARTER
    YEAR
    SECOND_MICROSECOND
    MINUTE_MICROSECOND
    MINUTE_SECOND
    HOUR_MICROSECOND
    HOUR_SECOND
    HOUR_MINUTE
    DAY_MICROSECOND
    DAY_SECOND
    DAY_MINUTE
    DAY_HOUR
    YEAR_MONTH
    """
    # 2. 时间截图,保留其他:Trunc, TruncDate, TruncDay,TruncHour, TruncMinute, TruncMonth, TruncSecond, TruncYear
    # v = models.UserInfo.objects.annotate(c=functions.TruncHour('ctime'))
    # v = models.UserInfo.objects.annotate(c=functions.TruncDate('ctime'))
    # v = models.UserInfo.objects.annotate(c=functions.Trunc('ctime','year'))

  4、F对象和Q对象

  1.F对象

  如果需要在等号右侧需要使用当前querySet中的字段,就需要用到F对象。

from django.db.models import F
1.右侧需要用到本表字段,用F对象

  Book.objects.all().update(price=F('price') + 20) 2.
django支持对F()对象使用算数运算   list.filter(bread__gte=F('bcommet') * 2) 3.F()对象中还可以写作“模型类__列名”进行关联查询   list.filter(isDelete=F('heroinfo__isDelete')) 4.对于date/time字段,可与timedelta()进行运算   list.filter(bpub_date__lt=F('bpub_date') + timedelta(days=1))

  2.Q对象

  过滤器的方法中关键字参数查询,会合并为And进行;需要进行or查询,使用Q()对象。Q对象(django.db.models.Q)用于封装一组关键字参数,这些关键字参数与“比较运算符”中的相同。

from django.db.models import Q
1.基本操作:
   Author.objects.filter(Q(name="Jan")) # 等价于Author.objects.filter(name="Jan")
2.Q对象可以使用&(and)、|(or)操作符组合起来:
  Author.objects.filter(Q(name="Jan") | Q(name="Wise")) # 等价于Author.objects.filter(name__in=["Jan", "Wise"])
3.支持联表查询
  Author.objects.filter(Q(book__name="Go") & Q(id__lt=2))
3.当操作符应用在两个Q对象时,会产生一个新的Q对象
  list.filter(pk_ _lt
=6).filter(bcommet_ _gt=10)
  list.filter(Q(pk_ _lt
=6) | Q(bcommet_ _gt=10))

 

posted on 2018-08-23 15:32  一只火眼金睛的男猴  阅读(1430)  评论(0编辑  收藏  举报