Py006-01-16关系型orm模型

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

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

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

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

  4. 书籍模型: 书籍有书名和出版日期

    • 一本书只应该有一个出版商出版,所以出版商和书籍是一对多关联关系(one-to-many)
  5. 书籍作者关系表

    • 一本书可能会有多个作者,一个作者也可以写多本书,所以作者和书籍的关系就是多对多的关联关系(many-to-many);
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      # 出版社表
      create table publish(
      nid int primary key auto_increment,
      name varchar(32),
      city varchar(32),
      email varchar(32)
      );

      # 书籍表
      create table book(
      nid int primary key auto_increment,
      title varchar(32),
      publishDate date,
      price decimal(6,2),
      publish_id int,
      foreign key(publish_id) references publish(nid)
      );

      # 作者详情表
      create table authorDetail(
      nid int primary key auto_increment,
      birthday date ,
      telephone int,
      addr varchar(32)
      );

      # 作者表
      create table author(
      nid int primary key auto_increment,
      name varchar(32),
      age int,
      ad_id int unique,
      foreign key(ad_id) references authorDetail(nid)
      );

      # 书籍作者关系表
      create table book_authors(
      nid int primary key auto_increment,
      book_id int,
      author_id int,
      foreign key(book_id) references book(nid),
      foreign key(author_id) references author(nid)
      );

orm模型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
from django.db import models

# 作者表
class Author(models.Model):
nid = models.AutoField(primary_key=True)
name=models.CharField( max_length=32)
age=models.IntegerField()
# 一对一 OneToOneField相当于指定 外间关联时设置 unique
'''
ad_id int unique,
foreign key(ad_id) references authorDetail(nid)
'''
authordetail=models.OneToOneField(to="AuthorDetail",to_field="nid",on_delete=models.CASCADE)

# 作者详情表
class AuthorDetail(models.Model):
nid = models.AutoField(primary_key=True)
birthday=models.DateField()
telephone=models.BigIntegerField()
addr=models.CharField( max_length=64)

# 出版社表
class Publish(models.Model):
nid = models.AutoField(primary_key=True)
name=models.CharField( max_length=32)
city=models.CharField( max_length=32)
email=models.EmailField()

'''
Book ---- Publish 一对多
'''
class Book(models.Model):
nid = models.AutoField(primary_key=True)
title = models.CharField( max_length=32)
publishDate=models.DateField()
price=models.DecimalField(max_digits=5,decimal_places=2)



# 一对多关系 一本书对应多个出版社
publish=models.ForeignKey(to="Publish",to_field="nid",on_delete=models.CASCADE,)
'''
publish_id int,
foreign key(publish_id) references publish(nid)

'''

#多对多
authors =models.ManyToManyField(to="Author")

'''
# 书籍作者关系表
create table book_authors(
nid int primary key auto_increment,
book_id int,
author_id int,
foreign key(book_id) references book(nid),
foreign key(author_id) references author(nid)
);
'''

# 多对多关系时 不需要这个模型类 django会依据 authors =models.ManyToManyField(to="Author")帮我们生成这张表
# class Book2Author(models.Model):
#
# nid = models.AutoField(primary_key=True)
# book=models.ForeignKey(to="Book")
# author=models.ForeignKey(to="Author")

生成表如下:





注意事项:

  • 表的名称myapp_modelName,是根据 模型中的元数据自动生成的,也可以覆写为别的名称  
  • id 字段是自动添加的
  • 对于外键字段,Django 会在字段名上添加”_id” 来创建数据库中的列名
  • 这个例子中的CREATE TABLE SQL 语句使用PostgreSQL 语法格式,要注意的是Django 会根据settings 中指定的数据库类型来使用相应的SQL 语句。
  • 定义好模型之后,你需要告诉Django_使用_这些模型。你要做的就是修改配置文件中的INSTALL_APPSZ中设置,在其中添加models.py所在应用的名称。
  • 外键字段 ForeignKey 有一个 null=True 的设置(它允许外键接受空值 NULL),你可以赋给它空值 None 。
  • 请务必设置on_delete=models.CASCADE(及联删除)否则会在django2报错on_delete。
  • 注意为什么authordetail=models.OneToOneField(to=”AuthorDetail”…)中AuthorDetail加引号
    如果AuthorDetail声明在Author前 可以不加但是如果定义在Author后就只能加引号来解决

添加表记录

操作前先简单的录入一些数据:

publish表

1
2
3
4
5
6
+-----+-----------------+--------+---------------+
| nid | name | city | email |
+-----+-----------------+--------+---------------+
| 1 | 苹果出版社 | 北京 | 10000@qq.com |
| 2 | 橘子出版社 | 天津 | 20000@126.com |
+-----+-----------------+--------+---------------+

author表

1
2
3
4
5
6
+-----+------+-----+-----------------+
| nid | name | age | authordetail_id |
+-----+------+-----+-----------------+
| 1 | alex | 33 | 1 |
| 2 | hjx | 18 | 2 |
+-----+------+-----+-----------------+

authordetail表

1
2
3
4
5
6
+-----+------------+-----------+--------+
| nid | birthday | telephone | addr |
+-----+------------+-----------+--------+
| 1 | 1983-01-01 | 110 | 北京 |
| 2 | 2000-10-15 | 119 | 天津 |
+-----+------------+-----------+--------+

python代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
from django.shortcuts import render

# Create your views here.

from app01.models import Book,Publish,Author,AuthorDetail

def index(request):
# 出版社记录
Publish.objects.create(name='苹果出版社',city='北京',email='10000@qq.com')
Publish.objects.create(name='橘子出版社', city='天津', email='20000@126.com')

# 作者详情记录
AuthorDetail.objects.create(birthday='1983-01-01',telephone=110,addr='北京')
AuthorDetail.objects.create(birthday='2000-10-15', telephone=119, addr='天津')
# 作者记录
Author.objects.create(name='alex',age=33,authordetail_id=1)
Author.objects.create(name='hjx', age=18, authordetail_id=2)

return render(request,'index.html')

一对多

1
2
3
4
5
6
7
8
9
10
11
12
方式1:
publish_obj=Publish.objects.get(nid=1)
book_obj=Book.objects.create(title="金瓶梅",publishDate="2012-12-12",price=100,publish=publish_obj)

方式2:
book_obj=Book.objects.create(title="金瓶梅",publishDate="2012-12-12",price=100,publish_id=1)


--------------------
查询金瓶梅对应出版社的邮箱
book_obj = Book.objects.filter(title='金瓶梅').first()
email = book_obj.publish.email
核心:book_obj.publish与book_obj.publish_id是什么?
1
2
3
4
5
+-----+-----------+-------------+--------+------------+
| nid | title | publishDate | price | publish_id |
+-----+-----------+-------------+--------+------------+
| 1 | 金瓶梅 | 2012-12-12 | 100.00 | 1 |
+-----+-----------+-------------+--------+------------+

多对多

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 当前生成的书籍对象
book_obj = Book.objects.create(title="追风筝的人", price=200, publishDate="2012-11-12", publish_id=1)
# 为书籍绑定的做作者对象
hjx = Author.objects.filter(name="hjx").first() # 在Author表中主键为2的纪录
alex = Author.objects.filter(name="alex").first() # 在Author表中主键为1的纪录

# 绑定多对多关系,即向关系表book_authors中添加纪录
book_obj.authors.add(hjx, alex) # 将某些特定的 model 对象添加到被关联对象集合中。
======= book_obj.authors.add(*[])
'''
还可以这样 1,2代表作者的主键
book_obj.authors.add(1, 2)
还可以写出解包的形式
book_obj.authors.add(*[1,2])
'''
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
book表
+-----+-----------------+-------------+--------+------------+
| nid | title | publishDate | price | publish_id |
+-----+-----------------+-------------+--------+------------+
| 1 | 金瓶梅 | 2012-12-12 | 100.00 | 1 |
| 2 | 追风筝的人 | 2012-11-12 | 200.00 | 1 |
+-----+-----------------+-------------+--------+------------+

book_authors表
+----+---------+-----------+
| id | book_id | author_id |
+----+---------+-----------+
| 1 | 2 | 1 |
| 2 | 2 | 2 |
+----+---------+-----------+

核心:book_obj.authors.all()是什么?

多对多关系其它常用API:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
book_obj.authors.remove()      # 将某个特定的对象从被关联对象集合中去除。    ======   book_obj.authors.remove(*[])
book_obj.authors.clear() #清空被关联对象集合
book_obj.authors.set() #先清空再设置 
book_obj.authors.all() #获取所有与这本书关联的作者对象的集合 queryset

'''
----------------操作实例
# 解除多多关系
book=Book.objects.filter(nid=2).first()
book.authors.remove(1) # 解除 主键为1的出版社
book.authors.remove(1,2) # 解除 主键为1,2的出版社
book.authors.remove(*[1,2]) # 解除 主键为1,2的出版社
book.authors.clear() # 解除所有关系


# 获取id为2d的书的所有关联作者集合
book.authors.all() # [obj1,obj2,...] queryset
'''

more