不同模型类关系的ORM操作

一对多模型类关系

  • 新建两个应用:User、Article

  • User\model.py

    from django.db import models
    
    # 定义用户模型
    class User(models.Model):
        username = models.CharField(max_length=100)
    
  • Article\models.py

    from django.db import models
    from users.models import User
    
    # 定义分类模型
    class Category(models.Model):
        name = models.CharField(max_length=100)
    
    # 定义文章模型
    class Article(models.Model):
        title = models.CharField(max_length=100)
        content = models.TextField()
    	# 分类外键
        category = models.ForeignKey('Category',on_delete=models.CASCADE)
        # 作者外键
        author = models.ForeignKey(User,on_delete=models.CASCADE,null=True)
    

    一对多的外键,定义在多的一方:一个分类有多个文章,外键定义在文章模型。

  • 数据库迁移

    >>> python manage.py makemigrations
    >>> python manage.py migrate
    
  • 添加数据:Python Console

    >>> from users.models import User
    >>> from article.models import Article, Category
    # 新建用户
    >>> Jack = User(username="Jack")
    >>> Jack.save()
    # 新建分类
    >>> python = Category(name="python")
    >>> python.save()
    # 新建文章
    >>> art = Article(
    title='Django实战',
    content='Django',
    category=Category.objects.first(),
    author=User.objects.first()
    )
    >>> art.save()
    # 获取文章模型数据
    >>> Article.objects.first()
    <Article: Article object (1)>
    >>> a = Article.objects.first()
    >>> a.title
    'Django实战'
    
  • 当业务需要获取某一分类模型(Category)下的所有文章,则:Python Console

    # 获取id为1的分类模型
    >>> category = Category.objects.get(pk=1)
    # 获取该分类下的所有文章(<引用模型的模型名转化为小写_set>)
    >>> articles = category.article_set.all()
    >>> articles
    <QuerySet [<Article: Article object (1)>]>
    

    一对多模型关系中,会自动生成一个字段在"一"的一方:

    该字段命名:<引用模型的模型名转化为小写_set>,

    该字段可以根据模型类外键中的related_name参数进行自定义,如下:

    category = models.ForeignKey('Category',related_name="articles")

    注意:赋值了related_name参数,默认的xx_set字段将不能使用。

  • 还有一种不常见的添加数据方式:Python Console

    >>> category = models.Category.objects.get(pk=1)
    >>> article = Article(title='test',content='test')
    >>> article.author = User.objects.first()
    >>> # aritcle.save()   
    >>> category.article_set.add(article)
    >>> category.save()
    

    当运行上面代码的时候,就会报错如下:

    <Article: Article object (None)> instance isn't saved.Use bulk=False or save the object first.

    大概意思就是artilce这个这个实例还没有被保存,需要先进行保存。

    所以先执行如上注释处:acticle.save(),此时又分为两种情况:

    1. 如果设置了catagory值可以为空,正常保存
    2. 如果设置了catagory值不可以为空,将会报错,此时就陷入了死循环中,需要借助bulk参数。如下:
    >>> category = models.Category.objects.get(pk=1)
    >>> article = Article(title='test',content='test')
    >>> article.author = User.objects.first()
    >>> category.article_set.add(article, bulk=True)
    

    使用了bulk参数,Django会自动保存所有实例。

一对一模型类关系

应用场景:

在实际网站中,可能需要保存用户的许多信息,但是有些信息是不经常用的。如果把所有信息都存放到一张表中可能会影响查询效率,因此可以把用户的一些不常用的信息存放到另外一张表中我们叫做UserExtension。用户表User与该表UserExtension就是典型的一对一了。

  • User\model.py

    from django.db import models
    
    # 用户模型
    class User(models.Model):
        username = models.CharField(max_length=200)
    # 用户信息模型
    class UserExtension(models.Model):
        school = models.CharField(max_length=100)
        user = models.OneToOneField('User',on_delete=models.CASCADE)
    
  • 数据库迁移

    >>> python manage.py makemigrations
    >>> python manage.py migrate
    
  • 添加数据:Python Console

    >>> from users.models import User, UserExtension
    >>> user = User.objects.first()
    >>> ex = UserExtension(school='yizhong')
    >>> ex.user = user
    >>> ex.save()
    >>> user.userextension.school
    'yizhong'
    

    一对一模型关系中,字段定义在任何一方即可,会自动生成一个字段

    该字段可以根据模型类外键中的related_name参数进行自定义,如下:

    user = models.OneToOneField('User',related_name='extension')

    注意:赋值了related_name参数,默认的字段将不能使用。

多对多模型类关系

应用场景:

比如文章和标签的关系。一篇文章可以有多个标签,一个标签可以被多个文章所引用。因此标签和文章的关系是典型的多对多的关系。

实现方式:

Django为这种多对多的实现提供了专门的Field。叫做ManyToManyField

  • Article\models.py

    class Tag(models.Model):
        name = models.CharField(max_length=100)
        # 定义多对多字段
        articles = models.ManyToManyField('Article')
    
    class Article(models.Model):
        title = models.CharField(max_length=100)
        content = models.TextField()
        category = models.ForeignKey('Category', on_delete=models.CASCADE)
        author = models.ForeignKey(User, on_delete=models.CASCADE, null=True)
    

    多对多字段在两个模型中随便一个添加外键即可。

  • 数据库迁移

    >>> python manage.py makemigrations
    >>> python manage.py migrate
    

    打开navicat查看映射进去的数据表,因为我们创建了一个模型Tag,数据库会新增一张表article_tag,但还发现新增了一张表article_tag_articles,该表的结构如下:

    三个字段,一个是id主键,另外两个都是外键,一个参考article_article这个表,另外一个参考article_tag这个表,该表是Django默认生成的,以此实现多对多关系。

  • 添加数据

    >>> from books.models import Tag
    >>> art = Article.objects.first()
    >>> tag = Tag(name="hot")
    >>> art.tag_set.add(tag)
    # 报错如下:
    

    ValueError: Cannot add "<Tag: Tag object (None)>": instance is on database "default", value is on database "None"

    大意是没有办法对Article添加这个标签,因为Tag标签里面还没有信息,也就是我们还没有对Tag中的信息进行保存。这个时候我们可以使用一下bluk参数,如下:

    >>> from books.models import Tag
    >>> art = Article.objects.first()
    >>> tag = Tag(name="hot")
    >>> art.tag_set.add(tag,bluk=False)
    # 报错如下:
    

    TypeError: add() got an unexpected keyword argument 'bluk'

    没有bluk这个参数。

    注意:一对多的时候可以使用bluk,多对多没有这个bluk参数。

    所以需要先保存标签实例对象:

    >>> from books.models import Tag
    >>> art = Article.objects.first()
    >>> tag = Tag(name="hot")
    >>> tag.save()
    >>> art.tag_set.add(tag)
    >>> art.tag_set.all()
    >>> <QuerySet [<Tag: Tag object (1)>]>
    >>> t = art.tag_set.first()
    >>> t.name
    'hot'
    # 如此,保存成功。
    

    tag_set这个属性,同上可以根据related_name这个参数来自定义。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值