Django的Model使用
创建模型
使用Django的模型主要注意两个方面:字段的类型和方法的重写。这里用一个例子来说明,其中包含了常用的字段类型和如何重写方法。
from django.db import models
class School(models.Model):
pass
class Message(models.Model):
pass
class Teacher(models.Model):
pass
class Student(models.Model):
GENDER_CHOICES = (
('male', "男"),
('female', "女"),
('secret', "保密")
)
name = models.CharField(max_length=40, blank=True, verbose_name="姓名")
gender = models.CharField(max_length=6, choices=GENDER_CHOICES, default="secret", verbose_name="性别")
age = models.IntegerField(default=0, verbose_name="年龄")
rank = models.PositiveIntegerField(default=1, verbose_name="排名", unique=True)
discount = models.DecimalField(max_digits=3, decimal_places=2, verbose_name="折扣", default=1.0)
school = models.ForeignKey(to=School, verbose_name="学校", on_delete=models.CASCADE)
message = models.OneToOneField(to=Message, verbose_name="信息", on_delete=models.CASCADE)
teacher = models.ManyToManyField(verbose_name="老师", to=Teacher, blank=True)
introduce = models.TextField(blank=True, verbose_name="介绍")
grade = models.FloatField(default=0.0, verbose_name="成绩")
url = models.URLField(verbose_name="个人主页", max_length=100)
email = models.EmailField(verbose_name="邮箱")
image = models.ImageField(upload_to='img/%Y/%m/%d/', verbose_name='上传图片', null=True)
file = models.FileField(upload_to="file/%Y/%m/%d/", verbose_name="上传文件", blank=True)
is_deleted = models.BooleanField(verbose_name="已删除", default=False, blank=True)
time_added = models.DateTimeField(verbose_name="添加时间", auto_now_add=True, blank=True)
def delete(self, using=None, keep_parents=False):
self.is_deleted = True
# some actions
self.save()
def save(self, force_insert=False, force_update=False, using=None,
update_fields=None):
# some actions
self.name = self.name.capitalize() # 首字母大写
return super().save(force_insert=force_insert, force_update=force_update, using=using,
update_fields=update_fields)
def __repr__(self):
return "UserProfile:{}".format(self.name)
def __str__(self):
return self.name
class Meta:
ordering = ['-time_added']
verbose_name = "用户信息"
verbose_name_plural = verbose_name
db_table = "student_info"
unique_together = ("name", "gender")
字段类型
这里对常见字段中值得注意的地方作一下说明。
CharField
字符串类型值得注意的是当该字段只能在是某些指定的值时,要使用choices参数来指向预先设定的值,如果要在templates中展示说明使用{{ get_gender_display }}。
IntergerField & PositiveIntegerField
整数类型和正整数类型。
DecimalField
十进制浮点数,其中,参数max_digits代表数字有多少位,decimal_places代表小数部分有多少位。
ForeignKey
使用to指向被关联的模型,使用on_delete来规定被关联对象删除时该对象的处理方式。主要有两种取值,models.CASCADE和models.SET_NULL。models.CASCADE表示当被关联对象删除时删除该对象,models.SET_NULL表示当被关联对象被删除时将该对象设置为空,此设置的前提是该字段要允许为空。
需要注意的是,有时候需要实现自关联,比如部门的上级还是部门,这时候使用self表示本身模型:
class Department(models.Model):
'''''
some other filed
'''
super_department = models.ForeignKey('self')
ImageField & FileField
使用upload_to参数来指定文件保存的路径。注意,该路径前面再加上 MEDIA_ROOT中设置的路径就是上传的文件真实保存路径了,如 MEDIA_ROOT的路径是'/home/media',那图片上传的路径就类似/home/media/img/2018/03/06。
BooleanField
布尔类型,可以使用default指定默认值。
DateTimeField
在Django中,代表时间字段的有三种:DateTimeField、DateField、TimeField,三种类型分别对应datetime()、date()、time(),都有auto_now和auto_now_add参数。
- auto_now
默认值为False,设置为True时会在每次修改该对象时自动更新为当前时间,但是无法手动修改该字段的值。 - auto_now_add
默认值为False,设置为True时会在创建对象时自动设置为当前时间,之后都不再修改,也不能手动修改其值。 - 默认当前时间,又能修改
有时候我们需要在创建对象时设置字段的值为当前时间,在后续时又能修改,使用auto_now或者auto_now_add都无法实现这一点。此时,可以使用default参数来设置默认值,如下
from django.db import models
from django.utils import timezone
class Message(models.Model):
add_date = models.DateTimeField(verbose_name='保存日期',default = timezone.now)
mod_date = models.DateTimeField(verbose_name='最后修改日期', auto_now = True)
重写方法
delete
Django默认的删除是将数据从数据库里删除,有时候我们需要软删除,保存以前的数据,这时候我们可以使用一个布尔类型的字段标识该条数据是否删除,这时需要重写delete方法实现软删除。
在delete方法中将is_deleted的值设置为True,表示该条数据已删除。此外还可以执行一些关联的动作,比如对相关字段赋值等,最后保存对象。
save
重写save方法可以让我们在保存数据时做一些相关的操作,比如保存姓名时自动设置为首字母大写,执行完之后需要调用父类的save方法进行保存。
repr & str
两者的作用是将变量或者常量转换为字符串对象,这里重写该方法使得对象实例能被转化为字符串。
class Meta
- ordering:结果集按照何种方式排序,上面例子表示按添加时间的逆序排序
- verbose_name:对象的名称
- verbose_name_plural:对象复数形式的名称
- db_table:在数据库中的表名
- unique_together: 联合唯一
常用方法
在对常用方法介绍部分,由于上面的模型包含字段较多,所以不使用上面创建的模型。这里使用一些常见的模型,通过名字就可以知道代表的内容,因此就不列出模型了。
创建实例
create
使用create方法可以创建一个模型实例,将各字段在参数中设置各个字段的值。
student = Student.objects.create(name='zhangsan', gender='male')
get_or_create
get_or_create的作用是查询一个实例,当实例不存在时则创建一个实例。
obj, created = Person.objects.get_or_create(
first_name='John',
last_name='Lennon',
defaults={'birthday': date(1940, 10, 9)},
)
函数返回一个(object, created)的tuple,object是查询或者创建的对象实例,created是个布尔类型的值,表示是否是新创建的实例。在查询时使用defaults以外的参数进行查询,当实例不存在时将包含default参数一起创建一个新的实例。功能类似于如下代码:
try:
obj = Person.objects.get(first_name='John', last_name='Lennon')
except Person.DoesNotExist:
obj = Person(first_name='John', last_name='Lennon', birthday=date(1940, 10, 9))
obj.save()
update_or_create
update_or_create的作用是更新一个实例,当实力不存在时则创建一个实例。
obj, created = Person.objects.update_or_create(
first_name='John', last_name='Lennon',
defaults={'first_name': 'Bob'},
)
函数返回一个(object, created)的tuple,object是更新或者创建的对象实例,created是个布尔类型的值,表示是否是新创建的实例。在查询的对象实例存在时,使用default中的参数进行更新,当实例不存在时,创建新的对象实例,需要更新的字段的值设置为default中的值。功能类似:
defaults = {'first_name': 'Bob'}
try:
obj = Person.objects.get(first_name='John', last_name='Lennon')
for key, value in defaults.items():
setattr(obj, key, value)
obj.save()
except Person.DoesNotExist:
new_values = {'first_name': 'John', 'last_name': 'Lennon'}
new_values.update(defaults)
obj = Person(**new_values)
obj.save()
add
这里补充一下add方法,add用在多对多的关系模型上,表示添加该字段的指向对象。
>>> john = Author.objects.create(name="John")
>>> paul = Author.objects.create(name="Paul")
>>> george = Author.objects.create(name="George")
>>> ringo = Author.objects.create(name="Ringo")
>>> entry.authors.add(john, paul, george, ringo)
上面的Author表示作者模型,entry表示书籍条目,一本书可以有多个作者,采用多对多关系。add可以为书的实例添加多个作者。
查询
all
all方法查询该对象的所有实例。
all_entries = Entry.objects.all()
get
使用get查询实例,当实例不存在时会返回一个不存在异常。
>>> entry = Entry.objects.get(pk=1)
>>> cheese_blog = Blog.objects.get(name="Cheddar Talk")
filter
filter返回一个QuerySet,而不是对象实例,当查询结果不存在时返回空的QuerySet,而不是返回异常,可以对结果集作切片操作来获取实例内容。下面代码功能在有对象实例时等同于上面get的操作。
>>> entry = Entry.objects.filter(pk=1)[0]
>>> cheese_blog = Blog.objects.filter(name="Cheddar Talk")[0]
filter结果可以链式地进行操作,也就是后面可以接多个过滤条件。
import datetime
time = datetime.datetime.now()
Entry.objects.filter(status=type).exclude(time_start__gte=time)
Entry.objects.filter(pub_date__year=2006)
Entry.objects.all().filter(pub_date__year=2006)
上面的pub_date__year表示取出DateField类型的pub_date的年,类似的可以取出月__month,日__day。在使用外键ForeignKey时可以使用双下划线来表示被关联对象的字段。
现在来看一下链式过滤的例子。
Entry.objects.filter(
... headline__startswith='What'
... ).exclude(
... pub_date__gte=datetime.date.today()
... ).filter(
... pub_date__gte=datetime.date(2005, 1, 30)
... )
首先使用__startswith过滤标题以'What'开始的数据。然后保留让发布日期小于今天的数据,exclude表示排除条件内的那部分数据,条件使用了__gte表示大于当前日期,该部分过滤类似于filter后面使用__lte小于。最后也是使用__gte大于一个自定义的日期。
除了上面列举的一些查询条件外还有很多常用的:
__exact 精确等于
__iexact 精确等于 忽略大小写
__contains 包含
__icontains 包含 忽略大小写
__gt 大于
__gte 大于等于
__lt 小于
__lte 小于等于
__in 存在于一个list范围内
__startswith 以...开头
__istartswith 以...开头 忽略大小写
__endswith 以...结尾
__iendswith 以...结尾 忽略大小写
__range 在...范围内
__year 日期字段的年份
__month 日期字段的月份
__day 日期字段的日
__isnull=True/False
Q
Q是Django自带的内容,用于查询。主要的用途是在页面的搜索框中输入内容后台查询相应的数据集。
from django.db.models import Q
student = student.filter(Q(name__icontains=search) |
Q(teacher__name__icontains=search) |
Q(gender__icontains=search) |
Q(url__icontains=search) |
Q(id__in=lid_lists))
上述例子常用在一个搜索框可能搜索多个字段的内容时,各个过滤条件之间使用“|”进行或者运算。当多条件查询时,各个条件是并运算,使用“&”代替“|”。
Q可以复制给个变量,有时候我们需要对Q后面的内容先做一些处理,如将日期拼凑出来等,这时候可以先把Q赋值给一个变量,然后对变量进行“|”或者“&”操作。
query = Q(name__icontains=search)
query = query | Q(teacher__name__icontains=search)
student = student.filter(query)
反向查找
反向查找主要是用在外键的情况下,通过被关联对象查找关联对象。
# post文章,comment评论
comment_list = post.comment_set.all() # 获取文章的所有评论
post.comment_set.count # 文章的所有评论数
除了上面的用法,还可以使用related_name来进行反向查找,而且当一个模型中有两个字段关联同一个模型时,在外键中一定要用related_name。
class School(models.Model):
name = models.CharField()
class Student(models.Model):
school = models.ForeignKey(School, related_name='SS')
code = models.CharField()
这样可以根据Student来查School:
School.objects.filter(SS_code="123456")
也可以通过School的实例查找所有以该实例为外键的Student:
school.SS.all()
外键列表
students = Students.objects.all()
# 外键school的id列表
school_ids = students.values_list("school", flat=True)
# school列表
schools = School.objects.filter(id__in=school_ids)
当要使获取的列表去重时,使用distinct
school_ids = students.values_list("school", flat=True).distinct()
values()和values_list()区别:
students.values_list("school_id", flat=True).distinct()
# 获取一个list [1, 2]
# 如果不加 flat=True, 返回一个tuple的list [(1,), (2,)]
students.values("school_id").distinct()
# 返回一个dict的list
# [{'school_id': 1}, {'school_id': 2}]
Django的Model使用的更多相关文章
- Django之Model操作
Django之Model操作 本节内容 字段 字段参数 元信息 多表关系及参数 ORM操作 1. 字段 字段列表 AutoField(Field) - int自增列,必须填入参数 primary_ke ...
- Django的Model上都有些什么
Django的Model上都有些什么 modelinfo= ['DoesNotExist', 'MultipleObjectsReturned', '__class__', '__delattr__' ...
- Python之路【第二十二篇】:Django之Model操作
Django之Model操作 一.字段 AutoField(Field) - int自增列,必须填入参数 primary_key=True BigAutoField(AutoField) - bi ...
- django User model
django User model operation this tutorial will guide us to know how to manipulate django User model. ...
- Scrapy中使用Django的Model访问数据库
Scrapy中使用Django的Model进行数据库访问 当已存在Django项目的时候,直接引入Django的Model来使用比较简单 # 使用以下语句添加Django项目的目录到path impo ...
- django使用model创建数据库表使用的字段
Django通过model层不可以创建数据库,但可以创建数据库表,以下是创建表的字段以及表字段的参数.一.字段1.models.AutoField 自增列= int(11) 如果没有的话,默认会生成一 ...
- Django之Model组件
Model组件在django基础篇就已经提到过了,本章介绍更多高级部分. 一.回顾 1.定义表(类) ##单表 from django.db import models class user(mode ...
- django中将model转换为dict的方法
django中将model转换为dict的方法 from django.forms.models import model_to_dict from user.model import userpro ...
- Python学习---django之Model语法180124
django之Model语法[Models] 1 django默认支持sqlite,mysql, oracle,postgresql数据库. <1> sqlite django默认使 ...
- Django的model查询操作 与 查询性能优化
Django的model查询操作 与 查询性能优化 1 如何 在做ORM查询时 查看SQl的执行情况 (1) 最底层的 django.db.connection 在 django shell 中使用 ...
随机推荐
- spring: ?.运算符
?.运算符 对于被调用方法的返回值来说,我们同样可以调用它的方法.例如,如果selectArtist()方法返回的是一个String,那么可以调用toUpperCase()将整个名字改为大写字母形式: ...
- java:jsp: ResourceBundle国际化多语言
java提供了一个资源类java.util.ResourceBundle来试下多国语言版本.其实ResourceBundle只是一个抽象的类,她有两个子类:ListResourceBundle,和,P ...
- poj3252 数位dp
这题不是用10进制储存的,要转化成2进制再计算 dp[i][j][k] i是位数,j是1的个数,k是0的个数 #include<map> #include<set> #in ...
- Object.assign()与深拷贝(一)
深拷贝与浅拷贝 所谓深拷贝与浅拷贝,是围绕引用类型变量的拷贝进行的讨论. 在ECMAScript中,变量分为基本类型和引用类型两种.其本质区别是不可变性,基本类型是不可变的,而引用类型是可变的. 所谓 ...
- [转载] Java开发在线编辑Word同时实现全文检索
一.背景介绍 Word文档与日常办公密不可分,在实际应用中,当某一文档服务器中有很多Word文档,假如有成千上万个文档时,用户查找打开包含某些指定关键字的文档就变得很困难,一般情况下能想到的解决方案是 ...
- 第三方开源--Android Image Cropper--图片裁剪
github下载地址:https://github.com/ArthurHub/Android-Image-Cropper 有两种使用方式: 第一种:Activity用法 1.添加 CropImage ...
- 16 Python 递归函数
递归 1.什么是递归 recursion 递归 递归的定义——在一个函数里再调用这个函数本身 在一个函数里再调用这个函数本身,这种魔性的使用函数的方式就叫做递归. 递归的最大深度——997 一个函数在 ...
- LeetCode OJ:Maximum Depth of Binary Tree(二叉树最大深度)
Given a binary tree, find its maximum depth. The maximum depth is the number of nodes along the long ...
- C#进阶之路(五):Linq初识
关于LINQ的文章,网上有很多,所以这篇文章我主要是总结下我自己的学习心得. 首先需要先了解的相关技术 1.隐式类型.匿名类型.对象初始化器 1)隐式类型,使用var关键字创建,C#编译器会根据用于初 ...
- django模型models.py文件内容理解
首先,要理解这句话:模型是你的数据的唯一的.权威的信息源.它包含你所存储数据的必要字段和行为.通常,每个模型对应数据库中唯一的一张表 基础:每个模型都是django.db.models.Model的一 ...