django之Model(数据表)的增删改查

一、新闻模型

class BaseModel(models.Model):
    # 创建时间
    create_time = models.DateTimeField(auto_now_add=True, verbose_name="创建时间")
    # 更新时间
    update_time = models.DateTimeField(auto_now=True, verbose_name="更新时间")
    # 数据是否删除
    # 逻辑删除
    is_delete = models.BooleanField(default=False, verbose_name="逻辑删除")

    class Meta:
        # 这个类只是被继承的
        abstract = True

# 新闻
class News(BaseModel):
    title = models.CharField(max_length=150, verbose_name="文章标题")
    digest = models.CharField(max_length=200, verbose_name="文章摘要")
    content = models.TextField(verbose_name="文章内容")
    clicks = models.IntegerField(default=0, verbose_name="点击量")
    image_url = models.URLField(default="", verbose_name="图片链接")
    tag = models.ForeignKey("Tag", on_delete=models.SET_NULL, null=True)
    # 如果是其他模块的数据库,关联需要使用app_name.model_name
    author = models.ForeignKey("users.User", on_delete=models.SET_NULL, null=True)

    class Meta:
        # 默认排序
        ordering = ["-update_time", "-id"]
        # 指明数据库名
        db_table = "tb_news"
        verbose_name = "新闻"
        verbose_name_plural = verbose_name

    def __str__(self):
        return f"News({self.id}, {self.title})"

二、操作

  两种创建的对象:QuerySet(惰性机制)、Manager

1、添加

# 方式一
news = News(title="Python机器学习", 
            digest="...", 
            content="...", 
            )
news.save()

# 方拾二
news = News()
news.title = "Python机器学习"
news.digest = "..."
news.content = "..."
news.save()

# 方式三
News.objects.create(title="Python机器学习", 
                    digest="...", 
                    content="...",
                    )


# 方式四
# 返回一个元组(查到的数据,是否创建)
res = News.objects.get_or_create(id=2000)
print(res)

2、修改

# 修改一条
news = News.objects.get(id=3)
news.title = "机器学习"
news.content = "..."
news.save()

# 修改多条
News.objects.filter(tag__name="机器学习").update(title="机器学习")

3、删除

# 删除一条
News.objects.get(id=9).delete()

# 删除多条
News.objects.all().delete()

  4、查找

# 查询一条,返回模型对象,立即查询
News.objects.first() # 查询默认第一条数据
News.objects.last()  # 查询默认最后一条数据
# 查询不到和查询到多条都会报错,所以一般配合查询主键使用,pk指代主键
News.objects.get(pk=3)

# 查询多条
News.objects.all()  # 查询所有
News.objects.filter(title="Python高级", tag="Python全栈")  # 相当于执行while...and...
News.objects.exclude(title="Python高级", tag="Python全栈")  # 相当于执行while not (... and ...),与filter相反
# 切片,惰性机制:如果不计算,就不会执行数据库查询 res = News.objects.all()
print(res.query)  # 输出数据库查询语句
res[1:20].all()  # 切片相当于limit

# 多条件OR查询:Q查询
from django.db.models import Q
News.objects.filter(Q(name="Python")|Q(title="机器学习"))
# F查询:我们构造的过滤器只是将字段值与某个字符串常量做比较。如果我们要对两个字段的值做比较,那么就应该使用F查询
# Django 支持 F() 对象之间以及 F() 对象和常数之间的加减乘除和取模的操作
# 查询点击量与id相同的新闻
from django.db.models import F
News.objects.filter(id=F("clicks"))

# 不仅可以查询,也可以更新值,总而言之,F("field_name")就是获取对应记录的字段值
News.objects.update(id=F("id")+1)
# 指定字段查询,返回QuerySet字典列表
# <QuerySet [{"":"", "", ""}, {"":"", "":""}]>
News.objects.values("title", "content")
# 指定字段查询,返回QuerySet对象列表,一定包含主键,比较高效
# 即使只有三个字段,也可以访问其他字段,只不过是再查询数据库
# <QuerySet [News(id, title, content), News(id, title, content)]>
News.objects.only("title", "content")
# 指定排除字段查询,用法与only同,效果相反
News.objects.defer("title", "content")
# 排序
# 从小到大排序
News.objects.all().order_by("id")
# 从大到小排序
News.objects.all().order_by("-id")

# 查询条件,应用在get、filter、exclude上面
# 精准查询
News.objects.get(id__exact=7)
# 忽略大小写的精准查询
News.objects.get(id__iexact=7)

# 模糊查询,针对CharField,包含
News.objects.filter(title__contains="Python")
# 模糊查询,针对CharField,忽略大小写
News.objects.filter(title__icontains="Python")
# 模糊查询,针对CharField,以什么开头
News.objects.filter(title__startswith="Python")
# 模糊查询,针对CharField,以什么结尾
News.objects.filter(title__endswith="Python")

# 比较查询,针对IntegerField,大于
News.objects.filter(id__gt=2)
# 比较查询,针对IntegerField,小于
News.objects.filter(id__lt=2)
# 范围查询,针对IntegerField,在什么范围之内
News.objects.filter(id__range=(10, 200))

# 指定迭代条件, 针对IntegerField、CharField
News.objects.filter(id__in=[1, 2, 4])
News.objects.filter(title__in=["Python", "Java"])

# 字段值是否为空
News.objects.filter(title__isnull=True)

# 聚合查询,利用聚合函数
from django.db.models import Count, Sum, Avg, Max, Min
# 如果没有指定键名,则默认为field_name__func_name
# id__avg
News.objects.aggregate(Avg("id", "tag_id"))
# 指定键名
News.objects.aggregate(id_avg=Avg("id"))

# 分组查询(一般分组与聚合函数会连用)
# 单独的聚合函数是对数据集的某个字段进行聚合
# 分组加聚合是先分组,再对每个分组的相应字段进行聚合
# 对每个分类进行分组,在统计每个分类的新闻数量
Tag.objects.annotate(news_count=Count("news")).values("name", "news_count")


# 正向和反向查询
# 如果两个表具有关联关系,那么无论在哪一个表,我们都能查询到关联的表的信息
# 查询id为50的新闻的分类
# 这是多对一的关系
News.objects.get(id=5).tag.name
Tag.objects.get(news__id=5).name

# 多对多的关系
# 学生和课程表
from django.db.models import Model, ManyToManyField, CharField


class Student(Model):
    department = ManyToManyField("Department")


class Department(Model):
    name = CharField(max_length=20)


# 查询id为5的学生的课程
Student.objects.get(id=5).department.all()

Department.objects.filter(student__id=5)

# 查询上数学课的所有学生
# 最终是为了查询学生信息,但是我们连个表都可以查到,多对多中彼此都添加了一个对方的管理器,
# 只不过一个是显示声明,一个是隐式声明

Student.objects.filter(department__name="math")
# student_set是默认添加的
# modelname_set有add、remove、clear、all的功能,不需要save
Department.objects.get(name="math").student_set.filter()

三、优化

  优化主要是针对查询的,一般是同样的查询结果,最少的查询次数,这个参考django数据库查询优化文档:https://docs.djangoproject.com/en/3.0/topics/db/optimization/