Django ORM(多表)

文章目录


前言

表与表之间的关系可分为以下三种:

bash 复制代码
一对一: 一对一关系表示一个模型的每个实例与另一个模型的每个实例都只关联一次
用 OneToOneField 来定义这种关系
一对多: 一对多关系表示一个模型的每个实例可以关联多个另一个模型的实例,但另一个模型的实例只能关联一个前者的实例
用 ForeignKey 来定义这种关系
多对多: 多对多关系表示两个模型的每个实例可以与对方的多个实例关联
用 ManyToManyField 来定义这种关系

之前我们定义了一个article模型,我们就基于这个模型实现关联关系

一、关联关系模型

更新fa下models.py

bash 复制代码
from django.db import models

class Tag(models.Model):
    id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=50, unique=True)
    created_at = models.DateTimeField(auto_now_add=True)    
    updated_at = models.DateTimeField(auto_now=True)
    def __str__(self):
        return self.name

class Author(models.Model):
    id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=255)
    email = models.EmailField(max_length=255)
    created_at = models.DateTimeField(auto_now_add=True)    
    updated_at = models.DateTimeField(auto_now=True)
    def __str__(self):
        return self.name

class Article(models.Model):
    id = models.AutoField(primary_key=True)
    title = models.CharField(max_length=255)
    content = models.TextField()
    author = models.ForeignKey(Author, null=True, on_delete=models.CASCADE)
    # ManyToManyField不会直接在article表显示tag相关字段
    # Django 会为 ManyToManyField 创建一个中间表来存储 Article 和 Tag 之间的多对多关系
    # Django 会创建一个类似于 article_tags 的中间表,它包含 article_id 和 tag_id 两个字段,分别表示 Article 和 Tag 之间的关联
    tags = models.ManyToManyField(Tag, blank=True, related_name='articles')  # Many-to-many relationship with Tag model
    created_at = models.DateTimeField(auto_now_add=True)    
    updated_at = models.DateTimeField(auto_now=True)
    def __str__(self):
        return self.title

再次生成和应用迁移:

bash 复制代码
python manage.py makemigrations
python manage.py migrate

二、一对多写入数据

views.py增加方法

bash 复制代码
def add_article(request):
    author = models.Author.objects.filter(pk=1).first()
    article = models.Article.objects.create(title="Test Article", content='123456', author=author)
    return HttpResponse(article)

urls.py增加路由

bash 复制代码
path('add_article', views.add_article, name='add_article')

访问链接http://127.0.0.1:8082/article/add_article

二、多对多写入数据

views.py里面新增方法

bash 复制代码
def add_tag(request):
    tag = models.Tag.objects.filter(pk=1).first()
    article = models.Article.objects.filter(pk=1).first()
    # add() 在即外键中只能传对象( *QuerySet数据类型)不能传 id(*[id表])
    article.tags.add(tag)
    return HttpResponse(article.tags.all())

urls.py增加路由

bash 复制代码
path('add_tag', views.add_tag, name='add_tag'),

访问链接http://127.0.0.1:8082/article/add_tag

刷新中间表可以看到

二、跨表查询

1.查找'test' 标签的文章

新增方法

bash 复制代码
def search(request):
    # 查找名称为 'test' 的标签
    tag = models.Tag.objects.filter(name="test").first()
    if not tag:
        return HttpResponse("Tag not found")
    # 使用相关名称访问相关文章
    # Article模型设置了 related_name,则应该使用这个名称来访问反向关系。例如,如果 related_name 设置为 articles,则应使用 tag.articles.all()。
    # 而如果没有设置 related_name,则应该使用 tag.article_set.all()。
    articles = tag.articles.all()
    # 将结果转换为字符串以便返回
    articles_list = "\n".join([f"Title: {article.title}, Content: {article.content}" for article in articles])
    return HttpResponse(articles_list)

访问链接http://127.0.0.1:8082/article/search

2.查找作者名为 'test' 的文章及标签

方法及路由如下

bash 复制代码
def search_by_author(request):
    # 查找作者名为 'test' 的作者
    author = models.Author.objects.filter(name="test").first()
    
    if not author:
        return HttpResponse("Author not found")
    
    # 查询作者的所有文章,并预取每篇文章的所有标签
    articles = author.article_set.prefetch_related('tags').all()
    
    # 构建文章及其标签的字符串
    articles_list = []
    for article in articles:
        tags = ", ".join(tag.name for tag in article.tags.all())  # 获取文章的所有标签
        articles_list.append(f"Title: {article.title}, Content: {article.content}, Tags: {tags}")
    
    # 将结果转换为字符串并返回
    return HttpResponse("\n".join(articles_list))
bash 复制代码
path('search_by_author', views.search_by_author, name='search_by_author'),

三、跨表删除

方法及路由如下

bash 复制代码
def delete_author_articles(request):
    # 查找名称为 'test' 的作者
    author = models.Author.objects.filter(name="test").first()
    if not author:
        return HttpResponse("Author not found")
    # 获取该作者下的所有文章
    articles = author.article_set.all()
    # 删除这些文章
    articles.delete()
    return HttpResponse("All articles by 'test' have been deleted")
bash 复制代码
path('delete_author_articles', views.delete_author_articles, name='delete_author_articles'),

访问链接http://127.0.0.1:8082/article/delete_author_articles

刷新fa_article及中间表fa_article_tags可以看到数据都被清空了

相关推荐
Paraverse_徐志斌2 小时前
MySQL 线上大表 DDL 如何避免锁表(pt-online-schema-change)
数据库·mysql·ddl·mysql锁·锁表·pt-osc
哈哈幸运3 小时前
MySQL运维三部曲初级篇:从零开始打造稳定高效的数据库环境
linux·运维·数据库·mysql·性能优化
愚公搬代码3 小时前
【愚公系列】《Python网络爬虫从入门到精通》055-Scrapy_Redis分布式爬虫(安装Redis数据库)
数据库·爬虫·python
pwzs3 小时前
深入浅出 MVCC:MySQL 并发背后的多版本世界
数据库·后端·mysql
大熊猫今天吃什么3 小时前
【一天一坑】空数组,使用 allMatch 默认返回true
前端·数据库
双叶8364 小时前
(51单片机)LCD显示数据存储(DS1302时钟模块教学)(LCD1602教程)(独立按键教程)(延时函数教程)(I2C总线认识)(AT24C02认识)
c语言·数据库·单片机·嵌入式硬件·mongodb·51单片机·nosql
XY.散人4 小时前
初识Redis · C++客户端list和hash
数据库·redis·缓存
码上飞扬4 小时前
深入 MySQL 高级查询:JOIN、子查询与窗口函数的实用指南
数据库·mysql
海洋与大气科学5 小时前
【matlab】地图上的小图
开发语言·数据库·matlab
Geek__19925 小时前
Sqlite3交叉编译全过程
jvm·数据库·sqlite