[django] ORM连表操作

21 篇文章 0 订阅

文章链接:wupeiqi

连表

class UserProfile(models.Model):
    user_info = models.OneToOneField('UserInfo')
    username = models.CharField(max_length=64)
    password = models.CharField(max_length=64)

    def __unicode__(self):
        return self.username


class UserInfo(models.Model):
    user_type_choice = (
        (0, u'普通用户'),
        (1, u'高级用户'),
    )
    user_type = models.IntegerField(choices=user_type_choice)
    name = models.CharField(max_length=32)
    email = models.CharField(max_length=32)
    address = models.CharField(max_length=128)

    def __unicode__(self):
        return self.name

class UserGroup(models.Model):

    caption = models.CharField(max_length=64)
    user_info = models.ManyToManyField('UserInfo')

    def __unicode__(self):
        return self.caption


class Host(models.Model):
    hostname = models.CharField(max_length=64)
    ip = models.GenericIPAddressField()
    user_group = models.ForeignKey('UserGroup')

    def __unicode__(self):
        return self.hostname

一对多:models.ForeignKey(其他表)
多对多:models.ManyToManyField(其他表)
一对一:models.OneToOneField(其他表)

应用场景:

一对多:当一张表中创建一行数据时,有一个单选的下拉框(可以被重复选择)
例如:创建用户信息时候,需要选择一个用户类型【普通用户】【金牌用户】【铂金用户】等。

多对多:在某表中创建一行数据是,有一个可以多选的下拉框
例如:创建用户信息,需要为用户指定多个爱好

一对一:在某表中创建一行数据时,有一个单选的下拉框(下拉框中的内容被用过一次就消失了
例如:原有含10列数据的一张表保存相关信息,经过一段时间之后,10列无法满足需求,需要为原来的表再添加5列数据

一对一 OneToOneField(ForeignKey)

例:
# 一个用户关联唯一的blog
class UserInfo(AbstractUser):
	blog = models.OneToOneField(to="Blog", to_field="nid", null=True, on_delete=models.DO_NOTHING)

###### 对于一对一 ######
# 1. 一对一其实就是 一对多 + 唯一索引
# 2.当两个类之间有继承关系时,默认会创建一个一对一字段
# 如下会在A表中额外增加一个c_ptr_id列且唯一:
class C(models.Model):
    nid = models.AutoField(primary_key=True)
    part = models.CharField(max_length=12)

class A(C):
    id = models.AutoField(primary_key=True)
    code = models.CharField(max_length=1)

一对多关系表设计
在“多”方设置外键(foreign key),关联父表(主表)的主键。

class School(models.Model):
    school_name = models.CharField(max_length=20)
    school_address = models.CharField(max_length=50)

class Student(models.Model):
    name = models.CharField(max_length=10)
    sex = models.CharField(max_length=10)
    score = models.FloatField()
    # Django2.0 必须添加on_delete=models.CASCADE,级联删除
    school = models.ForeignKey(to="School", on_delete=models.CASCADE)

#添加学校记录:
school1 = School(school_name='清华大学',school_address='北京')
school1.save()
或者
School.objects.create(school_name='南开大学',school_address='天津')

#添加学生记录(要进行关联学校记录)
#通过学校的实例化对象关联
stu4 = Student(name="李红",sex='女',score=82,school=school1)
stu4.save()

#通过学生的外键列名关联学校的id
stu4 = Student(name="李红",sex='女',score=82,school_id=24)
stu4.save()

#查询学校编号为23或25的学生记录。
Student.objects.filter(school_id__in =(23,25))

#查询学号大于9的学生记录
results = Student.objects.filter(id__gt =9)  # 查询出的是QuerySet对象
for stu in results:
 print(stu.name)

多对多 ManyToManyField(RelatedField)

"多对多"关系表设计:
通过设置“中间表”来关联两个“多”表。中间表中至少有两个外键字段,分别关联于两个“多”表(其他两个表)的主键。
在Django的models.py中需要完成三个模型:

方式一:自行创建第三张表

class Book(models.Model):
    title = models.CharField(max_length=32, verbose_name="书名")

class Author(models.Model):
    name = models.CharField(max_length=32, verbose_name="作者姓名")

# 自己创建第三张表,分别通过外键关联书和作者
class Author2Book(models.Model):
    author = models.ForeignKey(to="Author")
    book = models.ForeignKey(to="Book")

    class Meta:
        unique_together = ("author", "book")

方法二:通过ManyToManyField自动创建第三张表

class Book(models.Model):
    title = models.CharField(max_length=32, verbose_name="书名")

# 通过ORM自带的ManyToManyField自动创建第三张表
class Author(models.Model):
    name = models.CharField(max_length=32, verbose_name="作者姓名")
    books = models.ManyToManyField(to="Book", related_name="authors")

方式三:设置ManyTomanyField并指定自行创建的第三张表

class Book(models.Model):
    title = models.CharField(max_length=32, verbose_name="书名")

# 自己创建第三张表,并通过ManyToManyField指定关联
class Author(models.Model):
    name = models.CharField(max_length=32, verbose_name="作者姓名")
    books = models.ManyToManyField(to="Book", through="Author2Book", through_fields=("author", "book"))
    # through_fields接受一个2元组('field1','field2'):
    # 其中field1是定义ManyToManyField的模型外键的名(author),field2是关联目标模型(book)的外键名。

class Author2Book(models.Model):
    author = models.ForeignKey(to="Author")
    book = models.ForeignKey(to="Book")

    class Meta:
        unique_together = ("author", "book")

注意:
当我们需要在第三张关系表中存储额外的字段时,就要使用第三种方式。
但是当我们使用第三种方式创建多对多关联关系时,就无法使用set、add、remove、clear方法来管理多对多的关系了,需要通过第三张表的model来管理多对多关系。

class RelatedManager

"关联管理器"是在一对多或者多对多的关联上下文中使用的管理器。
它存在于下面两种情况:
外键关系的反向查询、多对多关联关系
简单来说就是当 点后面的对象 可能存在多个的时候就可以使用以下的方法。
方法:
create()
创建一个新的对象,保存对象,并将它添加到关联对象集之中,返回新创建的对象。

import datetime
models.Author.objects.first().book_set.create(title="番茄物语", publish_date=datetime.date.today())

add()
把指定的model对象添加到关联对象集中。
添加对象

author_objs = models.Author.objects.filter(id__lt=3)
models.Book.objects.first().authors.add(*author_objs)
添加id
models.Book.objects.first().authors.add(*[1, 2])

set()
更新model对象的关联对象。

book_obj = models.Book.objects.first()
book_obj.authors.set([2, 3])
remove()

# 从关联对象集中移除执行的model对象
book_obj = models.Book.objects.first()
book_obj.authors.remove(3)
clear()

# 从关联对象集中移除一切对象。
book_obj = models.Book.objects.first()
book_obj.authors.clear()

注意:
对于ForeignKey对象,clear()和remove()方法仅在null=True时存在。

举个例子:
ForeignKey字段没设置null=True时,没有clear()和remove()方法:

class Book(models.Model):
    title = models.CharField(max_length=32)
    publisher = models.ForeignKey(to=Publisher)

models.Publisher.objects.first().book_set.clear()

Traceback (most recent call last):
  File "<input>", line 1, in <module>
AttributeError: 'RelatedManager' object has no attribute 'clear'
当ForeignKey字段设置null=True时,

class Book(models.Model):
    name = models.CharField(max_length=32)
    publisher = models.ForeignKey(to=Class, null=True)
此时就有clear()和remove()方法:
models.Publisher.objects.first().book_set.clear()

注意:
对于所有类型的关联字段,add()、create()、remove()和clear(),set()都会马上更新数据库。换句话说,在关联的任何一端,都不需要再调用save()方法。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Moke丶青

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值