六、Django ORM关联模型

本章节将介绍ORM中的关联模型,以下测试基于book管理

一、创建关联模型

创建app01并注册

编辑全局settings.py文件,如下:

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'app01.apps.App01Config',    ###添加app01的配置
]


配置数据库连接

编辑全局settings.py文件,如下:

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'Django',
        'USER': 'root',
        'PASSWORD': '123456',
        'HOST': 'locahost',
        'PORT': '3306',

    }
}

创建关联模型

编辑app01下的models.py文件,如下:

from django.db import models

class Book(models.Model):
    title = models.CharField(max_length=32)
    price = models.DecimalField(max_digits=8, decimal_places=2)  # 999999.99,浮点型8位数,小数点2位
    publishDate = models.DateField()

    # 一对多的关联属性,创建关联字段
    publish = models.ForeignKey("Publish", on_delete=models.CASCADE)   ###表中会添加一个publish_id字段,并设置级联删除

    # 多对多的关联属性,创建关系表
    authors = models.ManyToManyField("Author", db_table="book2author")  # 多对多的时候,一般通过第三方表来实现,如果不命名的话,会自动创建一个book_authors的表

class Publish(models.Model):
    name = models.CharField(max_length=32)
    addr = models.CharField(max_length=32)
    email = models.CharField(max_length=32)

class Author(models.Model):
    name = models.CharField(max_length=32)
    age = models.SmallIntegerField()
    ###设置一对一的关联属性
    ad = models.OneToOneField("AuthorDetail", on_delete=models.CASCADE)   ##添加ForeignKey时需设置级联删除。

class AuthorDetail(models.Model):
    tel = models.IntegerField()
    addr = models.CharField(max_length=32)


具体解释如下:

  • 一对多
在一对多的关系中,需要使用models.ForeignKey在表示“多”的模型中定义一个外键字段,定义时需要指定表示“一”的模型类名。models.ForeignKey常用参数:
-	to:该属性的第一个参数,表示外键指向的模型类的类名
-	on_delete:表示外键指向的数据不存在时,本条数据该如何处理。
    -	CASCADE:级联操作,如果外键对应的在另一张表中的数据被删除了,那么本条数据也会被跟着删除。
    -	PROTECT:外键数据受保护,即只要本条数据还存在,则外键对应的在另一张表中的数据是无法被删除的。
    -	SET_NULL:删除时设置为空,如果外键对应的在另一张表中的数据被删除了,那么本条数据中的这个外键值就设置为空。
    -	SET_DEFUALT:设置为默认值,如果外键对应的在另一张表中的数据被删除了,那么本条数据中的这个外键值就设置为指定的默认值,但前提是此字段有指定的默认值。
    -	SET(obj/func):设置默认值,如果外键对应的在另一张表中的数据被删除了,那么本条数据中的这个外键值就设置为指定的值obj或者指定函数或方法func的返回值。
    -	DO_NOTHING:不做任何操作,一切只看数据库本身的约束。
-	related_name: 一般用于反向查询,表示“多”的模型中定义外键后,Django会在表示“一”的模型中自动生成一个表示“多”的模型类名_set属性,如果不想使用这种默认的命名方式,就可以使用此参数指定自己需要的名称了。 -	  db_constraint:默认为True,指有外键约束,如果只想设置关联数据,取消外键约束,设置为Flase即可。

参考related.py文件,如下定义的ForeignKey方法:

def __init__(self, to, related_name=None, related_query_name=None,
                 limit_choices_to=None, symmetrical=None, through=None,
                 through_fields=None, db_constraint=True, db_table=None,
                 swappable=True, **kwargs):
        try:
            to._meta
        except AttributeError:
            assert isinstance(to, str), (
                "%s(%r) is invalid. First parameter to ManyToManyField must be "
                "either a model, a model name, or the string %r" %
                (self.__class__.__name__, to, RECURSIVE_RELATIONSHIP_CONSTANT)
            )
  • 多对多
使用models.ManyToManyField指定即可(定义多对多关系时,Django会在数据库中自动生成一个关联两张表的中间表,但是在Django中不用我们自己去定义),同样的,也会在另一个模型中自动生成一个形如类名_set的属性。
  • 一对一
使用models.OneToOneField指定即可,定义方法和参数使用与models.ForeignKey类似(因为models.OneToOneField就是通过models.ForeignKey来实现的,只不过是添加了一个“唯一”的约束),不同之处在于,在另一个外键对应的模型中自动生成的属性为类名的小写形式,当然,你不想用默认生成的属性,也可以通过related_name参数来指定。

添加数据

在models.py文件中添加如下内容:

AuthorDetail.objects.create(tel=122121212,addr="北京")
AuthorDetail.objects.create(tel=212121212,addr="南京")
AuthorDetail.objects.create(tel=313131313,addr="上海")
Publish.objects.create(name="北京出版社",addr="昌平",email="122122")
Publish.objects.create(name="南京出版社",addr="中山路",email="212122")
Publish.objects.create(name="上海出版社",addr="浦东",email="313313133")

执行数据库迁移

python manage.py makemigrations    ###生成迁移文件
python manage.py migrate           ###同步数据库

二、关联模型操作

一对多增删改查

  • 创建路由
    编辑全局配置文件urls.py文件,如下:
from django.contrib import admin
from django.urls import path
from app01 import views as app1
urlpatterns = [
   path('admin/', admin.site.urls),
   path('index',app1.addbook),

]
  • 增加
from django.shortcuts import render,HttpResponse,redirect
from app01.models import Book,Publish,Author,AuthorDetail
def addbook(request):
    ##向book表中添加一条数据
    ##获取出版社名称
    publish = Publish.objects.get(name="北京出版社")
    ##方法一
    book = Book.objects.create(title="西游记",price=100,publishDate="2022-12-2",publish=publish)
    ###方法二
    book = Book.objects.create(title="红楼梦", price=200, publishDate="2021-11-2", publish_id=5)
    book = Book.objects.create(title="水浒传", price=180, publishDate="2020-10-2", publish_id=6)
    
    ###打印相关内容
    print(book1.title)      ###book对象中title已经复制到内存中
    print(book1.publish)    ###打印结果为一个对象
    print(book1.publish.name)   ###Django关联模型中会利用publish_id获得publish(get方式)的模型类对象
    print(book1.publish_id)   ##得到的就是当前book记录的publish_id,
    
    return HttpResponse("成功")

运行django程序,界面登录,查看数据库添加成功
在这里插入图片描述
在这里插入图片描述

  • 删除
from django.shortcuts import render,HttpResponse,redirect
from app01.models import Book,Publish,Author,AuthorDetail
def addbook(request):
    ##将book表中删除一条数据
    Book.objects.filter(title="西游记").delete()   ##直接删除即可
    
    return HttpResponse("成功")

在这里插入图片描述

  • 更新
from django.shortcuts import render,HttpResponse,redirect
from app01.models import Book,Publish,Author,AuthorDetail
def addbook(request):
    ##更新表中的数据
    Book.objects.filter(title="红楼梦").update(name="三国演义")   ##直接更新
    
    return HttpResponse("成功")

在这里插入图片描述

  • 查看
from django.shortcuts import render,HttpResponse,redirect
from app01.models import Book,Publish,Author,AuthorDetail
def addbook(request):
    ##查看表中的数据
    book = Book.objects.filter(name="三国演义") ##和之前讲的一样,就不再次赘述
    print(book)
    
    return HttpResponse("成功")

多对多增删改查

  • 增加
from django.shortcuts import render,HttpResponse,redirect
from app01.models import Book,Publish,Author,AuthorDetail
def addbook(request):
    ##为book书籍添加作者
    ##方法一
    ##获取book信息
    book = Book.objects.get(title="水浒传")
    author1 = Author.objects.get("小华")
    author2 = Author.objects.get(name="小明")
    book.authors.add(author1, author2)
    
    ##方法二
    book = Book.objects.get(title="水浒传")
    book.authors.add(1, 2)      ###可以直接跟authorID
    ##方法三
    book = Book.objects.get(title="水浒传")
    author_list = [1,2]    ###将作者定义为列表
    book.authors.add(*author_list)    ##将列表中的数据传进去
    
    return HttpResponse("成功")

运行django程序,查看第三张关联表,如下:
在这里插入图片描述

  • 删除
from django.shortcuts import render,HttpResponse,redirect
from app01.models import Book,Publish,Author,AuthorDetail
def addbook(request):
    ###删除书的作者
    book = Book.objects.get(title="水浒传")
    book.authors.remove(2)   ###删除指定作者对象
    ####
    book.authors.clear()    ###删除该book下关联的所有作者对象
    
    return HttpResponse("成功")
  • 修改
from django.shortcuts import render,HttpResponse,redirect
from app01.models import Book,Publish,Author,AuthorDetail
def addbook(request):
    ###更新书的作者
    book = Book.objects.get(title="水浒传")
    book.authors.set([6,])   ###先clear删除后add添加
    return HttpResponse("成功")

运行django程序,查看结果
在这里插入图片描述
也可以看到sql的运行过程,是先根据bookIDapp01_author表中查出来该book对应的author的信息,在进行delete删除,之后进行insert添加,如下:
在这里插入图片描述

  • 查看
from django.shortcuts import render,HttpResponse,redirect
from app01.models import Book,Publish,Author,AuthorDetail
def addbook(request):
    ###查询书的作者
    book = Book.objects.get(title="水浒传")
    author_list = book.authors.all().values("name","age")
    print(author_list)
    return HttpResponse("成功")

运行django程序,结果如下:
在这里插入图片描述

一对一增删改查

此处不多讲,只演示如何添加数据

from django.shortcuts import render,HttpResponse,redirect
from app01.models import Book,Publish,Author,AuthorDetail
def addbook(request):
   ##添加一条作者信息
   author = Author.objects.create(name="小华",age=40,ad_id=3)
   
   return HttpResponse("成功")

在这里插入图片描述

反向查询

前面介绍的都是基于book查看author,下面来介绍如何基于author查看book
上面说到创建多对多关联模型的时候,添加了related_name="books"参数,后面的名字可以随意定义
具体步骤如下:
from django.shortcuts import render,HttpResponse,redirect
from app01.models import Book,Publish,Author,AuthorDetail
def addbook(request):
    ###反向查询
    ###通过作者查出对应的书籍
    authtor = Author.objects.get(pk=6)   ###获取author的信息
    print(authtor.books.all().values("title"))    ###通过author调用books对象获取book信息
    return HttpResponse("成功")


大致原理如下:

1: 通过定义的related_name得知是和哪张表是多对多的关系
2: 然后通过第三张关联表的authorID获取所有的book信息
3:通过获取的book对象来查找具体的哪个属性的信息

运行django程序,结果如下:
在这里插入图片描述
查看数据库中的数据,结果一致,如下:
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/weixin_40579389/article/details/124962360