Django Model 核心用法详解:字段定义、方法重写与查询操作
本文系统讲解Django中Model的核心用法,涵盖CharField、ForeignKey等常用字段类型及参数配置,详解auto_now与default的时间处理差异。通过重写delete与save方法实现软删除与数据预处理,并深入解析create、get_or_create、update_or_create及filter链式查询等高频API,结合Q对象实现复杂搜索逻辑,助力开发者高效构建数据模型。
前言
本文主要介绍Django框架中Model的使用规范与技巧,旨在为开发者提供清晰的参考。接下来将详细展开具体实现步骤与注意事项。
创建模型
在Django中使用Model时,需重点关注字段类型的定义以及核心方法的重写。下文将通过一个综合示例,展示常用字段类型的应用及方法重写的具体实现。
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"
字段类型
以下对常见字段中需要特别注意的配置点进行说明。
CharField
对于字符串类型字段,若其值仅限于某些特定选项,应通过choices参数指定预定义的值列表。
IntergerField & PositiveIntegerField
分别用于定义整数类型和正整数类型的字段。
DecimalField
用于存储十进制浮点数。其中,max_digits参数指定数字的总位数,decimal_places参数指定小数部分的位数。
ForeignKey
通过to参数指定被关联的目标模型,并通过on_delete参数定义关联对象被删除时的处理策略。主要取值包括models.CASCADE和models.SET_NULL。models.CASCADE表示级联删除,即关联对象被删时当前对象也随之删除;models.SET_NULL表示将当前对象字段置为空,前提是允许该字段为空。
ImageField & FileField
通过upload_to参数指定文件保存的相对路径。该路径需与settings中配置的MEDIA_ROOT路径拼接,形成文件在服务器上的真实存储路径。例如,若MEDIA_ROOT为'/home/media',upload_to设为'img/',则上传文件实际保存路径类似'/home/media/img/2018/03/06'。
BooleanField
布尔类型字段,可通过default参数指定默认值。
DateTimeField
Django中涉及时间的字段主要有三种:DateTimeField、DateField和TimeField,分别对应Python中的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:指定该模型在数据库中对应的表名。
常用方法
在介绍常用方法时,为避免前文模型字段过多造成干扰,此处使用更简洁的常见模型进行演示。通过方法名即可理解其功能,故不再列出具体模型定义。
创建实例
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)的元组。object为查询或创建的对象实例,created为布尔值,表示是否为新创建的实例。查询时使用defaults以外的参数进行匹配,若实例不存在,则结合defaults参数创建新实例。其功能等效于以下代码:
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)的元组。object为更新或创建的对象实例,created为布尔值,表示是否为新创建的实例。若查询到的实例存在,则使用defaults中的参数进行更新;若不存在,则创建新实例,并将需要更新的字段值设为defaults中的值。其功能等效于:
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方法,该方法用于多对多关系模型,表示向关系中添加入关联对象。
>>> 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方法查询单个实例,若实例不存在则抛出DoesNotExist异常。
>>> entry = Entry.objects.get(pk=1) >>> cheese_blog = Blog.objects.get(name="Cheddar Talk")
filter
filter方法返回一个QuerySet对象而非单个实例。若查询无结果,返回空的QuerySet而非抛出异常。可对QuerySet进行切片操作以获取具体实例。以下代码在存在实例时功能等同于get操作:
>>> entry = Entry.objects.filter(pk=1)[0] >>> cheese_blog = Blog.objects.filter(name="Cheddar Talk")[0]
filter的结果支持链式调用,即可在其后追加多个过滤条件。
Entry.objects.filter(pub_date__year=2006) Entry.objects.all().filter(pub_date__year=2006) Entry.objects.filter(blog__name__year="zhangsan")
例如,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过滤大于等于某个自定义日期的数据。
除上述过滤条件外,常见的还有__icontains,表示内容包含指定字符串(不区分大小写)。
Q
Q是Django内置的查询对象,主要用于实现复杂查询,例如在页面搜索框中输入关键词后,后台根据Q对象查询相应的数据集。
student = student.filter(Q(name__icontains=search) |
Q(teacher__name__icontains=search) |
Q(gender__icontains=search) |
Q(url__icontains=search))
上述示例常用于单个搜索框需检索多个字段内容的场景。各过滤条件之间使用“|”进行逻辑或运算。当需要多条件同时满足时,使用“&”进行逻辑与运算。
Q对象可赋值给变量。若需对查询条件进行预处理(如拼接日期等),可先将Q对象赋值给变量,再对变量执行“|”或“&”操作。
query = Q(name__icontains=search) query = query | Q(teacher__name__icontains=search) student = student.filter(query)
总结
以上就是本文的全部内容,希望这些内容对您的学习或工作有所帮助。如有任何疑问,欢迎留言交流,感谢大家对本站的支持。
免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。









