一.创建模型

1.模型关系整理

创建一对一的关系:OneToOne("要绑定关系的表名")

创建一对多的关系:ForeignKey("要绑定关系的表名")

创建多对多的关系:ManyToMany("要绑定关系的表名")  会自动创建第三张表

书籍模型: 书籍有书名和出版日期,一本书可能会有多个作者,一个作者也可以写多本书,所以作者和书籍的关系就是多对多的关联关系(many-to-many);

一本书只应该由一个出版商出版,所以出版商和书籍是一对多关联关系(one-to-many)。

一对一、多对一、多对多 ,用book表和publish表自己来想想关系,想想里面的操作,加外键约束和不加外键约束的区别,一对一的外键约束是在一对多的约束上加上唯一约束。

实例:我们来假定下面这些概念,字段和关系

作者模型:一个作者有姓名和年龄。

作者详细模型:把作者的详情放到详情表,包含生日,手机号,家庭住址等信息。作者详情模型和作者模型之间是一对一的关系(one-to-one)

出版商模型:出版商有名称,所在城市以及email。

书籍模型: 书籍有书名和出版日期,一本书可能会有多个作者,一个作者也可以写多本书,所以作者和书籍的关系就是多对多的关联关系(many-to-many);一本书只应该由一个出版商出版,所以出版商和书籍是一对多关联关系(one-to-many)。

下面我们通过图书管理系统,来设计出每张表之间的对应关系。

通过上图关系,来定义一下我们的模型类。

2.模型关系类的编写

from django.db import models

class Book(models.Model):

# nid = models.AutoField(primary_key=True)  # 自增id(可以不写,默认会有自增id)

title = models.CharField(max_length=32)     # 书名

price = models.DecimalField(max_digits=5, decimal_places=2)

# 价格 一共5位,保留两位小数

pub_date = models.DateField()  #出版日期

# 一个出版社有多本书,关联字段要写在多的一方

# 不用命名为publish_id,因为django为我们自动就加上了_id

# foreignkey(表名)建立的一对多关系

publish = models.ForeignKey("Publish", on_delete=models.CASCADE)

authors = models.ManyToManyField("Author")  # 建立的多对多的关系

class Publish(models.Model):

# 不写id的时候数据库会自动给你增加自增id

name = models.CharField(max_length=32)

city = models.CharField(max_length=64)

email = models.EmailField()

class Author(models.Model):

name = models.CharField(max_length=32)

age = models.SmallIntegerField()

au_detail = models.OneToOneField("AuthorDetail", on_delete=models.CASCADE)

class AuthorDetail(models.Model):

gender_choices = (

(0, "女"),

(1, "男"),

(2, "保密"),

)

gender = models.SmallIntegerField(choices=gender_choices)

tel = models.CharField(max_length=32)

addr = models.CharField(max_length=64)

birthday = models.DateField()

3.注意事项

1、 表的名称myapp_modelName,是根据 模型中的元数据自动生成的,也可以覆写为别的名称  

2、id 字段是自动添加的

3、对于外键字段,Django 会在字段名上添加"_id" 来创建数据库中的列名

4、这个例子中的CREATE TABLE SQL 语句使用MySQL 语法格式,要注意的是Django 会根据settings 中指定的数据库类型来使用相应的SQL 语句。

5、定义好模型之后,你需要告诉Django _使用_这些模型。你要做的就是修改配置文件中的INSTALL_APPSZ中设置,在其中添加models.py所在应用的名称。

6、外键字段 ForeignKey 有一个 null=True 的设置(它允许外键接受空值 NULL),你可以赋给它空值 None 。

4.关于字段选项

每个字段有一些特有的参数,例如,CharField需要max_length参数来指定VARCHAR数据库字段的大小。还有一些适用于所有字段的通用参数。 这些参数在文档中有详细定义,这里我们只简单介绍一些最常用的:

1)null

如果为True,Django 将用NULL 来在数据库中存储空值。 默认值是 False.

(1)blank

如果为True,该字段允许不填。默认为False。

要注意,这与 null 不同。null纯粹是数据库范畴的,而 blank 是数据验证范畴的。

如果一个字段的blank=True,表单的验证将允许该字段是空值。如果字段的blank=False,该字段就是必填的。

(2)default

字段的默认值。可以是一个值或者可调用对象。如果可调用 ,每有新对象被创建它都会被调用。

(3)primary_key

如果为True,那么这个字段就是模型的主键。如果你没有指定任何一个字段的primary_key=True,

Django 就会自动添加一个IntegerField字段做为主键,所以除非你想覆盖默认的主键行为,

否则没必要设置任何一个字段的primary_key=True。

(4)unique

如果该值设置为 True, 这个数据字段的值在整张表中必须是唯一的

(5)choices

由二元组组成的一个可迭代对象(例如,列表或元组),用来给字段提供选择项。 如果设置了choices ,

默认的表单将是一个选择框而不是标准的文本框,而且这个选择框的选项就是choices 中的选项。

这是一个关于 choices 列表的例子:

YEAR_IN_SCHOOL_CHOICES = (

('FR', 'Freshman'),

('SO', 'Sophomore'),

('JR', 'Junior'),

('SR', 'Senior'),

('GR', 'Graduate'),

)

每个元组中的第一个元素,是存储在数据库中的值;第二个元素是在管理界面或 ModelChoiceField 中用作显示的内容。

在一个给定的 model 类的实例中,想得到某个 choices 字段的显示值,就调用 get_FOO_display 方法(这里的 FOO 就是 choices 字段的名称 )。例如:

from django.db import models

class Person(models.Model):

SHIRT_SIZES = (

('S', 'Small'),

('M', 'Medium'),

('L', 'Large'),

)

name = models.CharField(max_length=60)

shirt_size = models.CharField(max_length=1, choices=SHIRT_SIZES)

>>> p = Person(name="Fred Flintstone", shirt_size="L")

>>> p.save()

>>> p.shirt_size

'L'

>>> p.get_shirt_size_display()

'Large

一旦你建立好数据模型之后,django会自动生成一套数据库抽象的API,可以让你执行关于表记录的增删改查的操作。

二.操作表记录

1.添加一些简单的数据

(1)publish表

insert into app01_publish(name,city,email) values("华山出版社", "华山", "hs@163.com"), ("明教出版社", "黑木崖", "mj@163.com");

(2)authordatail表

insert into app01_authordetail(gender,tel,addr,birthday) value (1,13432335433,"华山","1994-5-23"),(1,13943454554,"黑木崖","1961-8-13"),(0,13878934322,"黑木崖","1996-5-20");

(3)author表

insert into app01_author(name,age,au_detail_id) value ("令狐冲",25,1),("任我行",58,2),("任盈盈",23,3);

多表存在关联的情况下,插入数据需要先将被关联的表的数据先插入,在插入关联的表的数据。

2.一对多添加记录

# 一对多的添加

# 方式一:如果是这样直接指定publish_id字段去添加值,前提是你的主表里面必须有数据

# 主表:没有被关联的(因为book表是要依赖于publish这个表的)也就是publish表

# 子表:关联的表

# ##一对多新增

# 方式一 传对象的形式

pub_obj = models.Publish.objects.get(pk=1)

book = models.Book.objects.create(title="独孤九剑", price=180, pub_date="2018-10-23", publish=pub_obj)

# 方式二 传对象的id(用的更多)

# new_book = models.Book.objects.create(title="冲灵剑法", price=120, pub_date="2018-08-23", publish_id=pub_obj.pk)

# print(new_book)

3.多对多

# ##多对多新增

# 方式一 传对象的形式

# book_obj = models.Book.objects.get(pk=1)

# print(book_obj)

# ling = models.Author.objects.get(pk=1)

# print(ling)

# ying = models.Author.objects.get(pk=3)

# print(ying)

# book_obj.authors.add(ling, ying)

# 传入的是对象,通过模型会自动转为相应的id,为book_authors新增信息

#

# # 方式二 传对象id

book_obj = models.Book.objects.get(pk=2)

ling = models.Author.objects.get(pk=1)

# print(ling.pk)

book_obj.authors.add(ling.pk)

book_obj.authors.remove()      # 将某个特定的对象从被关联对象集合中去除。    ======   book_obj.authors.remove(*[])

book_obj.authors.clear()       #清空被关联对象集合

book_obj.authors.set()         #先清空再设置

总结:remove和clear的区别

  remove:得吧你要清除的数据筛选出来,然后移除

  clear:不用查,直接就把数据都清空了。

各有应用场景

关联管理器(RelatedManager)

关于关联管理器大前提:

(1)多对多,双向都有

(2)一对多时,对应多的一方才有(出版社的角度)

(3)一对多时,反向才能使用关联管理器

正向按字段名

反向按小写表名+  _set

4.基于对象的跨表查询

"""

正向: 字段名称

---------------->

Book                        Publish

<----------------

反向: 小写表名+_set

"""

(1)一对多查询(Publish 与 Book)

# 正向例子

# 查询主键为1的书籍的出版社所在的城市

book_obj = models.Book.objects.get(pk=1)

print(book_obj.publish.city)

# 反向例子

# 查询华山出版社出版的书籍名

pub_obj = models.Publish.objects.filter(name="华山出版社").first()

# 反向获取到存在这个pub_obj对象的书,在遍历出来

for book in pub_obj.book_set.all():

print(book.title)

(2)一对一查询(Author 和 AuthorDetail)

正向查询(按字段:au_detail)

# 查询令狐冲的电话

author_obj = models.Author.objects.filter(name="令狐冲").first()

print(author_obj.au_detail.tel)

# 反向查询(按表名:author):

# 查询所有住址在黑木崖的作者的姓名

au_detail_obj = models.AuthorDetail.objects.filter(addr="黑木崖")

for au in au_detail_obj:

print(au.author.name)

(3)多对多查询 (Author 与 Book)

# 独孤九剑所有作者的名字以及手机号

book_obj = models.Book.objects.filter(title="独孤九剑").first()

for au in book_obj.authors.all():

print(au.name, au.au_detail.tel)

# 反向查询(按表名:book_set):

# 查询令狐冲出过的所有书籍的名字

au_obj = models.Author.objects.filter(name="令狐冲").first()

for book in au_obj.book_set.all():

print(book.title)

注意:

你可以通过在 ForeignKey() 和ManyToManyField的定义中设置 related_name 的值来覆写 FOO_set 的名称。例如,如果 Book model 中做一下更改:

publish = models.ForeignKey("Publish", on_delete=models.CASCADE, related_name="book_list")

那么接下来就会如我们看到这般:

# 查询 明教出版社出版过的所有书籍

publish=Publish.objects.get(name="明教出版社")

book_list=publish.book_list.all()  # 与明教出版社关联的所有书籍对象集合

5.基于双下划线的跨表查询

Django 还提供了一种直观而高效的方式在查询(lookups)中表示关联关系,它能自动确认 SQL JOIN 联系。要做跨关系查询,就使用两个下划线来链接模型(model)间关联字段的名称,直到最终链接到你想要的model 为止。

正向查询按字段,反向查询按表名小写用来告诉ORM引擎join哪张表

"""

正向: 字段名称__跨表的字段名称

----------------------------->

Book                                    Publish

<-----------------------------

反向: 小写表名__跨表的字段名称

"""

(1)一对多查询

# 练习:  查询华山出版社出版过的所有书籍的名字与价格(一对多)

# 正向查询 按字段:publish

book_title_price1 = models.Book.objects.filter(publish__name="华山出版社").values_list("title", "price")

print(book_title_price1)

# 反向查询 按表名:book

book_title_price2 = models.Publish.objects.filter(name="华山出版社").values_list("book__title", "book__price")

print(book_title_price2)

(2)多对多查询 

# 练习: 查询令狐冲出过的所有书籍的名字(多对多)

# 正向查询 按字段:authors:

book_name = models.Book.objects.filter(authors__name="令狐冲").values("title")

print(book_name)

# 反向查询 按表名:book

book_name = models.Author.objects.filter(name="令狐冲").values("book__title")

print(book_name)

(3)一对一查询

# 查询令狐冲的手机号

au_tel =models.Author.objects.filter(name ="令狐冲").values("au_detail__tel")

print(au_tel)

# 反向查询

au_tel = models.AuthorDetail.objects.filter(author__name="令狐冲").values("tel")

print(au_tel)

(4)进阶练习(连续跨表)

# # 正向查询

bname_aname = models.Book.objects.filter(publish__name="华山出版社").values("title","authors__name")

print(bname_aname)

# 反向查询

bname_aname = models.Publish.objects.filter(name="华山出版社").values("book__title","book__authors__name")

print(bname_aname)

# 练习2: 手机号以132开头的作者出版过的所有书籍名称以及出版社名称

# 正向查询

bname_pname = models.Book.objects.filter(authors__au_detail__tel__startswith="134").values("title", "publish__name")

print(bname_pname)

# 反向查询1

bname_pname = models.Author.objects.filter(au_detail__tel__startswith="134").values("book__title", "book__publish__name")

print(bname_pname)

# 反向查询2

bname_pname = models.AuthorDetail.objects.filter(tel__startswith="134").values("author__book__title", "author__book__publish__name")

print(bname_pname)

Django 学习 之ORM多表操作的更多相关文章

  1. Django框架06 /orm多表操作

    Django框架06 /orm多表操作 目录 Django框架06 /orm多表操作 1. admin相关操作 2. 创建模型 3. 增加 4. 删除 5. 修改 6. 基于对象的跨表查询 7. 基于 ...

  2. Django框架05 /orm单表操作

    Django框架05 /orm单表操作 目录 Django框架05 /orm单表操作 1. orm使用流程 2. orm字段 3. orm参数 4. orm单表简单增/删/改 5. orm单表查询 5 ...

  3. day 46 Django 学习3 数据库单表操作以及反向解析

    前情提要: Django 已经学了不少了, 今天学习链接数据库的操作.以及相关的反向解析等 一:反向解析 1:反向解析模板层 跳转时设定url会随着前面的路由改变而改变         2:反向解析之 ...

  4. Django之模型---ORM 多表操作

    多表操作 创建表模型 from django.db import models # Create your models here. class Author(models.Model): nid = ...

  5. django框架基础-ORM单表操作-长期维护

    ###############    单表操作-添加数据    ################ import os if __name__ == '__main__': os.environ.set ...

  6. Django视图之ORM连表操作一

    1 项目路径结构树 2 models创建类 from django.db import models class UserType(models.Model): ''' 用户类型 ''' title ...

  7. Django之模型---ORM 单表操作

    以上一随笔中创建的book表为例讲解单表操作 添加表记录 方式一 # create方法的返回值book_obj就是插入book表中的python葵花宝典这本书籍纪录对象 book_obj=Book.o ...

  8. python django基础五 ORM多表操作

    首先在创建表的时候看下分析一下 1.作者表和作者详细地址表  一对一关系 理论上谁都能当主表 把Author设置成主表 au=models.OneToOneField(to='AuthorDetail ...

  9. django框架基础-ORM跨表操作-长期维护

    ###############    一对一跨表查询    ################ import os if __name__ == '__main__': os.environ.setde ...

随机推荐

  1. 【Struts 动态表单】DynaActionForm

    RegisterAction package k.action; import org.apache.struts.action.ActionForm; import org.apache.strut ...

  2. 【STM32H7教程】第58章 STM32H7的硬件JPEG应用之图片解码显示

    完整教程下载地址:http://www.armbbs.cn/forum.php?mod=viewthread&tid=86980 第58章       STM32H7的硬件JPEG应用之图片解 ...

  3. Vue-footer始终置底

    需求:当页面高度不足一屏时需要footer固定显示在页面底部,而页面内容超过一屏时需要footer紧跟在页面内容的最后. 思路:通过获取 网页可见区域高度:document.body.clientHe ...

  4. idea垂直分屏

    1.找到分屏功能 搜索keymap(注意大小写): 2.Split Vertically 垂直分屏/Split Horizontally 水平分屏 3.添加快捷方式

  5. Plastic Bottle Manufacturer: Plastic Bottle Packaging Material, Is It Degradable?

    For plastic bottle packaging, the current global market demand is still growing. However, for plasti ...

  6. mysql的一些不常用语句

    今天写项目,用的ThinkPHP,写的时候有点费劲,原因嘛 无非是对框架或者mysql的一些知识的遗忘. 1.为了配合ThinkPHP中的控制器,需要修改数据库中表名,一时想不起来,幸好有百度,问题很 ...

  7. 【代码学习】PYTHON 面向对象

    一.方法重新 #!/usr/bin/python # -*- coding: UTF-8 -*- class Parent: # 定义父类 def myMethod(self): print '调用父 ...

  8. tkinter学习(3)scale尺度条和menu菜单

    1.scale学习(尺度条)1.1 代码: #第1步:导出模块 import tkinter as tk #第2步:定义窗口,及其标题.大小和位置 win = tk.Tk() win.title('s ...

  9. 吴裕雄 PYTHON 神经网络——TENSORFLOW 正则化

    import tensorflow as tf import matplotlib.pyplot as plt import numpy as np data = [] label = [] np.r ...

  10. 吴裕雄 python 神经网络——TensorFlow训练神经网络:花瓣识别

    import os import glob import os.path import numpy as np import tensorflow as tf from tensorflow.pyth ...