• Django之ORM-model模型关系


    Django1.8.2中文文档:Django1.8.2中文文档

    模型类关系

    1)一对多关系
    例:图书类-英雄类
    models.ForeignKey() 定义在多的类中。

    2)多对多关系
    例:新闻类-新闻类型类 体育新闻 国际新闻
    models.ManyToManyField() 定义在哪个类中都可以。

    3)一对一关系
    例:员工基本信息类-员工详细信息类. 员工工号
    models.OneToOneField定义在哪个类中都可以。

    多对多示例

    # 新闻类型类
    class NewsType(models.Model):
        # 类型名
        type_name = models.CharField(max_length=20)
        # 关系属性,代表类型下面的信息
        type_news = models.ManyToManyField('NewsInfo')
    
    # 新闻类
    class NewsInfo(models.Model):
        # 新闻标题
        title = models.CharField(max_length=128)
        # 发布时间
        pub_date = models.DateTimeField(auto_now_add=True)
        # 信息内容
        content = models.TextField()
        # 关系属性, 代表信息所属的类型
        # news_type = models.ManyToManyField('NewsType')
    多对多示例
    # 员工基本信息类
    class EmployeeBasicInfo(models.Model):
        # 姓名
        name = models.CharField(max_length=20)
        # 性别
        gender = models.BooleanField(default=False)
        # 年龄
        age = models.IntegerField()
        # 关系属性,代表员工的详细信息
        employee_detail = models.OneToOneField('EmployeeDetailInfo')
    
    # 员工详细信息类
    class EmployeeDetailInfo(models.Model):
        # 联系地址
        addr = models.CharField(max_length=256)
        # 教育经历
        # 关系属性,代表员工基本信息
        # employee_basic = models.OneToOneField('EmployeeBasicInfo')
    一对一关系示例

    重点关注一对多的关系;

    模型-关联查询

    关联查询-一对多

    查询和对象关联的数据

    在一对多关系中,一对应的类我们把它叫做一类,多对应的那个类我们把它叫做多类,我们把多类中定义的建立关联的类属性叫做关联属性。
    例:查询id为1的图书关联的英雄的信息。

    b=BookInfo.objects.get(id=1)
    b.heroinfo_set.all()
    通过模型类查询:
    HeroInfo.objects.filter(hbook__id=1)

    例:查询id为1的英雄关联的图书信息。

    h = HeroInfo.objects.get(id=1)
    h.hbook
    通过模型类查询:
    BookInfo.objects.filter(heroinfo__id=1)

    格式:

    由一类的对象查询多类的时候:
      一类的对象.多类名小写_set.all() #查询所用数据
    由多类的对象查询一类的时候:
      多类的对象.关联属性 #查询多类的对象对应的一类的对象
    由多类的对象查询一类对象的id时候:
      多类的对象. 关联属性_id

    通过模型类实现关联查询

    关联查询
    1.通过模型类实现关联查询时,要查哪个表中的数据,就需要通过哪个类来查。
    2.写关联查询条件的时候,如果类中没有关系属性,条件需要些对应类的名,如果类中有关系属性,直接写关系属性。

    例:查询图书信息,要求图书关联的英雄的描述包含'八'。

    BookInfo.objects.filter(heroinfo__hcomment__contains='')

    例:查询图书信息,要求图书中的英雄的id大于3.

    BookInfo.objects.filter(heroinfo__id__gt=3)

    例:查询书名为“天龙八部”的所有英雄。

    HeroInfo.objects.filter(hbook__btitle='天龙八部')

    通过多类的条件查询一类的数据:
      一类名.objects.filter(多类名小写__多类属性名__条件名)
    通过一类的条件查询多类的数据:
      多类名.objects.filter(关联属性__一类属性名__条件名)

    模型-插入和删除

    插入、更新和删除
    调用一个模型类对象的save方法的时候就可以实现对模型类对应数据表的插入和更新。
    调用一个模型类对象的delete方法的时候就可以实现对模型类对应数据表数据的删除。
    插入示例:

    # 1.创建bookinfo对象
    b = models.BookInfo()
    b.btitle = "流星蝴蝶剑"
    b.bpub_date = date(1990, 1, 1)
    # 2.保存进数据库
    b.save()

    删除示例:

    # 1.获取书籍对象
    book = models.BookInfo.objects.get(id=bid)
    # 2.删除书籍
    book.delete()

    模型-自关联

    自关联是一种特殊的一对多的关系。
    案例:显示广州市的上级地区和下级地区。
    地区表:id, atitle, aParent_id;
    mysql终端中批量执行sql语句:source areas.sql;

    自关联案例

    models.py

    class AreaInfo(models.Model):
        """地区模型类"""
        # 地区名称
        atitle = models.CharField(max_length=20)
        # 关系属性,代表当前地区的父级地区
        aParent = models.ForeignKey("self", null=True, blank=True)
    E:PycharmPycharm_savecp15	est2>cd booktest
    
    E:PycharmPycharm_savecp15	est2ooktest>mysql -uroot -p
    Enter password: ****
    Welcome to the MySQL monitor.  Commands end with ; or g.
    Type 'help;' or 'h' for help. Type 'c' to clear the current input statement.
    
    mysql> use test1000;
    Database changed
    mysql> source area.sql

    area.html

    <h1>地区</h1>
    <p>{{ area }}</p>
    
    <h1>父级地区</h1>
    <p>{{ parent }}</p>
    
    <h1>子级地区</h1>
    <ul>
        {% for child in children %}
            <li>{{ child }}</li>
        {% endfor %}
    </ul>

    Views.py

    def areas(request):
        '''获取广州市的上级地区和下级地区'''
        # 1.获取广州市的信息
        area = AreaInfo.objects.get(atitle='广州市')
        # 2.查询广州市的上级地区
        parent = area.aParent
        # 3.查询广州市的下级地址
        children = area.areainfo_set.all()
        # 使用模板
        return render(request, 'booktest/areas.html', {'area': area, 'parent': parent, 'children': children})

    Urls.py

    from django.conf.urls import url
    from booktest import views
    
    urlpatterns = [
        url(r'^areas/$', views.areas),  # 自关联案例
    ]

    应注意浏览器中的url后面的’/’。

    模型-模型管理器

    什么是管理器?

    BookInfo.objects.all()->objects是一个什么东西呢?
    答:objects是Django帮我自动生成的管理器对象,通过这个管理器可以实现对数据的查询
    objects是models.Manger类的一个对象。自定义管理器之后Django不再帮我们生成默认的objects管理器。

    自定义管理器

    可以在BookInfo下自定义一个 book = models.Manager()
    这时就不能使用 BookInfo.objects.xxx了,而是BookInfo.book.xxx,但这样并没有什么用。
    我们一般这样用:

    • 1)自定义一个管理器类,这个类继承models.Manger类。
    • 2)再在具体的模型类里定义一个自定义管理器类的对象。

    自定义管理器类的应用场景

    1)改变查询的结果集。
    比如调用BookInfo.books.all()返回的是没有删除的图书的数据。
    2)添加额外的方法。
    管理器类中定义一个方法帮我们操作模型类对应的数据表。
    使用self.model()就可以创建一个跟自定义管理器对应的模型类对象。

    自定义管理器示例

    自定义管理器代码

    class BookInfoManager(models.Manager):
        '''图书模型管理器类'''
    
        # 1.改变原有查询的结果集
        def all(self):
            # 1.调用父类的all方法,获取所有数据
            books = super().all()  # QuerySet
            # 2.对books中的数据进行过滤
            books = books.filter(isDelete=False)
            # 返回books
            return books
    
        # 2.封装方法,操作模型类对应的数据表(增删改查)
        def create_book(self, btitle, bpub_date):
            '''添加一本图书'''
            # 1.创建一个图书对象
            # 获取self所在的模型类
            model_class = self.model
            book = model_class()
            # book = models.BookInfo()
            book.btitle = btitle
            book.bpub_date = bpub_date
            # 2.添加进数据库
            book.save()
            # 3.返回book
            return book
    
    
    # 一类
    # booktest2_bookinfo
    class BookInfo(models.Model):
        '''图书模型类'''
        # 图书名称
        btitle = models.CharField(max_length=20, db_column='title')
        # 图书名字唯一
        # btitle = models.CharField(max_length=20, unique=True, db_index=True)
        # 价格,最大位数为10,小数为2
        # bprice = models.DecimalField(max_digits=10, decimal_places=2)
        # 出版日期
        bpub_date = models.DateField()
        # bpub_date = models.DateField(auto_now_add=True) # 创建时间
        # bpub_date = models.DateField(auto_now=True) # 更新时间
        # 阅读量
        bread = models.IntegerField(default=0)
        # 评论量
        bcomment = models.IntegerField(default=0)
        # 删除标记
        isDelete = models.BooleanField(default=False)
    
        # book = models.Manager() # 自定一个Manager类对象,管理器对象
        objects = BookInfoManager()  # 自定义一个BookInfoManager类的对象
    
        # @classmethod
        # def create_book(cls, btitle, bpub_date):
        #     '''添加一本图书'''
        #     # 创建一个cls类的对象
        #     obj = cls()
        #     obj.btitle = btitle
        #     obj.bpub_date = bpub_date
        #     # 添加进数据库
        #     obj.save()
        #     # 返回obj
        #     return obj
    自定义管理器代码

    自定义管理器的使用:
    1.

    BookInfo.objects.all() # objects是管理器中的objects,返回的是一个isDelete=0的值;

    2.

    from booktest.models import BookInfo
    BookInfo.objects.create_book('test2', '1991-1-1')

    其实在models.Manager里面已经封装了create方法,使用示例如下:
    BookInfo.objects.create(btitlt='test3', bpub_date='1991-1-1')

    应注意如果定义的图书模型类名换了比如class BookInfo,这个时候BookInfoManager中的book = BookInfo()也要改成
    book = BookInfo1(),这样会很麻烦,但幸好,Manager里面有考虑到这一点,

    # 获取self所在的模型类
    model_class = self.model
    book = model_class()
    
    # 上面两句相当于最后一句。
    #  book = BookInfo()

     小结:

    主旨:模型管理器类和模型类是通过在模型类中定义objects = BookInfoManager(),在模型管理器类中通过
    model_class = self.model; book = model_class() 来建立关系的。

    自定义模型管理器类方法获取默认收货地址

    定义地址模型管理器类

    class AddressManager(models.Manager):
        """地址管理器类"""
        def get_default_address(self, user):
            """返回默认的地址"""
            # self.model:获取self对象所在的模型类
            try:
                address = self.get(user=user, is_default=True)
            except self.model.DoesNotExist:
                # 不存在默认收货地址
                address = None
            return address
    地址模型管理器类

    地址模型类中引用地址模型管理器类的objects

    class Address(BaseModel):
        '''地址模型类'''
        user = models.ForeignKey('User', verbose_name='所属账户')
        receiver = models.CharField(max_length=20, verbose_name='收件人')
        addr = models.CharField(max_length=256, verbose_name='收件地址')
        zip_code = models.CharField(max_length=6, null=True, verbose_name='邮政编码')
        phone = models.CharField(max_length=11, verbose_name='联系电话')
        is_default = models.BooleanField(default=False, verbose_name='是否默认')
    
        # 自定义一个模型管理器对象
        objects = AddressManager()
    引用地址模型管理器类

    在CBV中使用自定义模型管理器类中的方法

    class AddressView(LoginRequiredMixin, View):
        """用户中心-订单页"""
        def get(self, request):
            """返回用户中心信息页面"""
            # 获取用户的默认收货地址
            user = request.user
            # try:
            #     address = Address.objects.get(user=user, is_default=True)
            # except Address.DoesNotExist:
            #     address = None
            # 使用自定义地址模型类管理器对象的获取默认收货地址方法
            address = Address.objects.get_default_address(user)
            # print("address:", address)
            return render(request, "user_center_site.html", {"page": "address", "address": address})
    CBV中使用自定义模型管理器类中的方法

    模型-元选项

    Django默认生成的表名:应用名小写_模型类名小写。

    元选项:需要在模型类中定义一个元类Meta,在里面定义一个类属性db_table就可以指定表名。

    如果改了应用名,而表名有不会自动更改,这个时候,就会出问题;
    为了解决这个问题,我们要让模型类的表名不依赖于应用名;
    使用 元选项,指定表名。

    class BookInfo(models.Model):
        '''图书模型类'''
        btitle = models.CharField(max_length=20, db_column='title')
        bpub_date = models.DateField()
        bread = models.IntegerField(default=0)
        bcomment = models.IntegerField(default=0)
        isDelete = models.BooleanField(default=False)
        
        objects = BookInfoManager()  # 自定义一个BookInfoManager类的对象
      
       # 使用元选项 class Meta: db_table = 'bookinfo' # 指定模型类对应表名
  • 相关阅读:
    11 [异常]-try...except
    3-4 网络编程 练习题
    31 选课系统
    3-3 面向对象 本章总结
    3-2 面向对象中级练习题
    3-1 面向对象练习题
    11 [面向对象]-面向对象的软件开发
    10 [面向对象]-元类
    App集成极光推送开发流程[关键步骤]
    App集成极光推送步骤
  • 原文地址:https://www.cnblogs.com/yifchan/p/python-1-26.html
Copyright © 2020-2023  润新知