zoukankan      html  css  js  c++  java
  • Django基础——Model篇(二)

    一 Model连表关系

         一对多:models.ForeignKey(其他表)
        多对多:models.ManyToManyField(其他表)
        一对一:models.OneToOneField(其他表)
        一般在数据库中创建外键关联时,就有一对多或者多对多,而一对一是Django独有的。

    应用场景:
        一对多:当一张表中创建一行数据时,有一个单选的下拉框(下拉框中内容,可被重复选择)
        例如:创建用户信息时,需要选择一个用户类型:普通用户、金牌用户、铂金用户等。
        
        多对多:在某表中创建一行数据时,有一个可以多选的下拉框
        例如:创建用户信息时,需要为用户选择多个爱好
        
        一对一:在某表中创建一行数据时,有一个单选的下拉框(下拉框中内容只能被选择1次)
        例如:原有含10列数据的一张表保存相关信息,经过一段时间之后,10列无法满足需求,需要为原来的表再添加5列数据

     1 一对多

       一对多表结构是为了解决空间浪费问题,通过一张数据库表去关联另外一张数据库表来解决重复出现的字段,这样在这张表中只会存储相应的ID来代替相应的字段。

                              

        为什么是1对多呢?因为在第2张表里,金牌会员的ID=3,而在第3张表里有好2个3,即表示1对多。

        在Model中生成一对多表结构(models.py文件)

        例1:第1种一对多(默认关联id)

    # 用户类型类
    class UserType(models.Model):
        user_type = models.CharField(max_length=64)
    
    #用户信息类
    class UserInfo(models.Model):
        username = models.CharField(max_length=64)
        email = models.CharField(max_length=32)
        # 外键关联 usertype对应着UserInfo表中的1列数据,他自动关联了UserType类
         usertype = models.ForeignKey(UserType)

        例2:第2种一对多(指定关联字段)

    # 业务线类
    class Business(models.Model):
    #设置为主键 nid
    = models.AutoField(primary_key=True) name = models.CharField(max_length=32) # 主机类,表示主机属于哪一条业务线 class Host(models.Model): hostname = models.CharField(max_length=16) # 括号中的参数可加引号,也可以不加引号,效果一样,to_field参数表示关联哪个字段 business = models.ForeignKey(Business,to_field='nid')

       例3:第3种一对多(多级外键关联)

    #一对多 多级外键关联
    class A(models.Model):
        name = models.CharField(max_length=16)
    
        def __unicode__(self):
            return self.name
    
    class UserGroup(models.Model):
        caption = models.CharField(max_length=32)
        obj_a = models.ForeignKey(A)
    
        def __unicode__(self):
            return self.caption
    
    class User(models.Model):
        username = models.CharField(max_length=32)
        user_group = models.ForeignKey(UserGroup)
        def __unicode__(self):
            return self.hostname

     2 多对多

        在Zabbix监控中会存在用户与用户组的概念,在这里同一个人可以属于多个用户组,同时同一个用户组也可以包括多个人。在这个场景中一对多的表关系结构是不能解决这个问题的,从而引出了多对多的概念。

                                          

        为什么是多对多呢?因为在对于CEO组,有两个人,即1个组包括了多个人;同时对于alex,他分别属于两个不同组,那么认为这种关系就是多对多。

        在Model中生成多对多表结构(models.py文件)

    # model中的多对多
    # 应用场景:用户与用户组(一个用户可以在多个组,同时一个组可以同时存在多个用户)
    class UserGroup(models.Model):
        group_name = models.CharField(max_length=16)
    
    class User(models.Model):
        name = models.CharField(max_length=16)
        email = models.CharField(max_length=16)
        mobile = models.CharField(max_length=16)
        # 两张表建立多对多,django默认会生成一张数据库表来建立两者的关系
        relationship = models.ManyToManyField(UserGroup)

         注:对于多对多,在models.py中我们只写了两个类,即生成两张数据库表,但两张表明显不能很好的表示多对多的关系,在这种情况下Django默认为我们生成另外一张表来建立这种关系,即用3张表来表示用户和用户组之间的关系。

      3 一对一

       一对一不是数据库的连表结构,而是Django独有的,他是在一对多的基础伪造出来的。即在一对多中限定某个指定的字段不能重复,一旦重复数据库报错,这样就相当于构造了一个一对一的连表关系。在上述一对多中,用户级别是可重复的,但在一对一关系中,一个用户级别只能对应一个用户,不允许重复。

       应用场景:假设在一个公司的所有用户中,只有alex和eric可以登录后台管理,那么这个场景就可以使用一对一的连表关系。

                                          

       在Model中生成一对一表结构(models.py文件)

    # model中的一对一,相当于对一对多进行限制后产生的,由Django完成,且是Django独有的
    # 应用场景:在很多用户中只有某些用户能够登录,这时id不能重复,即同一个账号ID不能出现多次
    # 下表为所有的用户信息表
    class User(models.Model):
        name = models.CharField(max_length=16)
        email = models.CharField(max_length=16)
        mobile = models.CharField(max_length=16)
    
    # 下表为能够登录的用户的用户名和密码
    class admim(models.Model):
        username = models.CharField(max_length=64)
        password = models.CharField(max_length=64)
        # django自动完成关系的建立
        user_info = models.OneToOneField(User)

     二 Model连表操作(了不起的双下划线)

     1 一对多连表操作

     实例1:在页面创建用户,同时在页面进行展示

     models.py文件

    #-*- coding:utf-8 -*-
    
    from __future__ import unicode_literals
    from django.db import models
    
    #一对多连表关系
    #用户组表
    class UserGroup(models.Model):
        caption = models.CharField(max_length=32)
        def __unicode__(self):
            return self.caption
    #用户表
    class User(models.Model):
        username = models.CharField(max_length=32)
    #user_group为对象,对应UserGroup中的一行数据 user_group
    = models.ForeignKey(UserGroup) def __unicode__(self): return self.hostname

     forms模块中的foreign.py文件

    #!/usr/bin/env python
    #-*- coding:utf-8 -*-
    __author__ = 'mcp'
    
    from django import forms
    from app01 import models
    
    class UserForm(forms.Form):
        # 创建用户名
        username = forms.CharField()
        
        # 创建用户组的两种方法
        
        # 第1种方法:
        # group = forms.IntegerField(widget=forms.Select())
        
        # 第2种方法:用户组字段名=models.py中User类的用户组字段名+"_id"
        # 因为外键user_group字段在User数据库表中字段名默认变成了"user_group_id",这样做的好处:username和user_group_id直接组成字典
        # 传给Model,因为Model创建数据时是接受字典形式参数的,就是views/foreign.py中的all_data
        user_group_id = forms.IntegerField(widget=forms.Select())
        
        def __init__(self,*args,**kwargs):
            # 执行父类的构造方法
            super(UserForm,self).__init__(*args,**kwargs)
            
            # 配合创建用户组的第1种方法使用,这里同时注意values_list方法的使用
            # self.fields['group'].widget.choices = models.UserGroup.objects.all().values_list('id','caption')
            
            # 配合创建用户组的第2种方法使用
            self.fields['user_group_id'].widget.choices = models.UserGroup.objects.all().values_list('id','caption')

     views模块中foreign.py文件

    #!/usr/bin/env python
    #-*- coding:utf-8 -*-
    __author__ = 'mcp'
    
    from django.shortcuts import HttpResponse,render
    from app01 import models
    from app01.forms import foreign as ForeignForm
    
    # 创建用户组表
    def create_user_group(request):
        # 创建用户组的类型,运行一次后注释,防止多次生成
        # models.UserGroup.objects.create(caption='CEO')
        # models.UserGroup.objects.create(caption='CTO')
        # models.UserGroup.objects.create(caption='COO')
        return HttpResponse('ok')
    
    # 创建用户表
    def create_user(request):
        # 将请求数据作为参数传递给UserForm,生成相应对象
        obj = ForeignForm.UserForm(request.POST)
        # 判断请求类型是否为'POST'类型
        if request.method == 'POST':
            # 进行From表单验证,验证其有效性
            if obj.is_valid():
              # 获取请求数据
                all_data = obj.clean()
                
              # 把获取的数据存储到数据库,有3种方法
                # 第1种方法(对象级别操作):先获取对象
                # group_obj = models.UserGroup.objects.get(id=all_data['group'])
                # 为什么创建数据库表时,第二个参数(关联外键)user_group=group_obj?
                # 这是因为在Model里user_group = models.ForeignKey('UserGroup'),这里user_group实际上是关联了一个对象,
                # 所以在传递参数时要传递相应的对象参数。
                # models.User.objects.create(username=all_data['username'],user_group=group_obj)
    
                # 第2种方法(数据库级别操作,这里注意Django默认给外键字段名加上了"_id")
                # models.User.objects.create(username=all_data['username'],user_group_id=all_data['group'])
                
                # 第3种方法(传字典参数,但是要注意form中已经组成了字典数据)
                models.User.objects.create(**all_data)
               # 打印数据库中所以信息的条数
                print models.User.objects.all().count()
            else:
                # 写上报错提示信息,form表单的验证信息,这里省略了
                pass
                
        # 获取所有的用户信息列表
        user_list = models.User.objects.all()
       return render(request,'foreign/create_user.html',{'obj':obj,'user_list':user_list})

      templates/foreign目录下的create_user.html文件

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
        <form action="/create_user/" method="post">
            <p>用户名:{{ obj.username }}</p>
           {#<p>用户组:{{ obj.user_group }}</p>#}
            <p>用户组:{{ obj.user_group_id }}</p>
            <input type="submit" value="submit"/>
        </form>
    
        <table>
            {% for item in user_list %}
            <tr>
                <td>{{ item.username }}</td>
    {#注意此处的操作,user_group是1个对象(表示数据库中一行数据),而用户组在数据库中是按ID存储的,所以要转换成中文,注意模板中的.号操作#}
    <td>{{ item.user_group.caption }}</td> </tr> {% endfor %} </table> </body> </html>

    运行效果如下图所示:

     实例2:在页面查询用户,同时在页面展示该用户的相关信息

     在实例1的基础上,修改views模块中foreign.py文件即可

    #!/usr/bin/env python
    #-*- coding:utf-8 -*-
    __author__ = 'mcp'
    
    from django.shortcuts import HttpResponse,render
    from app01 import models
    from app01.forms import foreign as ForeignForm
    
    # 创建用户组表
    def create_user_group(request):
        # 创建用户组的类型,运行一次后注释,防止多次生成
        # models.UserGroup.objects.create(caption='CEO')
        # models.UserGroup.objects.create(caption='CTO')
        # models.UserGroup.objects.create(caption='COO')
        return HttpResponse('ok')
    
    # 创建用户表
    def create_user(request):
        # 将请求数据作为参数传递给UserForm,生成相应对象
        obj = ForeignForm.UserForm(request.POST)
        # 判断请求类型是否为'POST'类型
        if request.method == 'POST':
            # 进行From表单验证,验证其有效性
            if obj.is_valid():
              # 获取请求数据
                all_data = obj.clean()
                
              # 把获取的数据存储到数据库,有3种方法
                # 第1种方法(对象级别操作):先获取对象
                # group_obj = models.UserGroup.objects.get(id=all_data['group'])
                # 为什么创建数据库表时,第二个参数(关联外键)user_group=group_obj?
                # 这是因为在Model里user_group = models.ForeignKey('UserGroup'),这里user_group实际上是关联了一个对象,
                # 所以在传递参数时要传递相应的对象参数。
                # models.User.objects.create(username=all_data['username'],user_group=group_obj)
    
                # 第2种方法(数据库级别操作,这里注意Django默认给外键字段名加上了"_id")
                # models.User.objects.create(username=all_data['username'],user_group_id=all_data['group'])
                
                # 第3种方法(传字典参数,但是要注意form中已经组成了字典数据)
                models.User.objects.create(**all_data)
               # 打印数据库中所以信息的条数
                print models.User.objects.all().count()
            else:
                # 写上报错提示信息,form表单的验证信息,这里省略了
                pass
                
        # 根据输入的用户名,查找该用户所在的组
        # 例如URL中输入http://127.0.0.1:8000/create_user/?user=alex,表示获取数据库中username='alex'的相关数据
        # 获取get请求中user的值,例如user='alex',那么下面的val='alex'
        val = request.GET.get('user')
        # 获取数据库中对应字段username='val'的一行数据
        user_list = models.User.objects.filter(username=val)
       
        return render(request,'foreign/create_user.html',{'obj':obj,'user_list':user_list})

     运行效果如下图所示:

    实例3:在页面查询用户组,同时在页面展示该用户组的用户

    在实例1的基础上,修改views模块中foreign.py文件即可

    #!/usr/bin/env python
    #-*- coding:utf-8 -*-
    __author__ = 'mcp'
    
    from django.shortcuts import HttpResponse,render
    from app01 import models
    from app01.forms import foreign as ForeignForm
    
    # 创建用户组表
    def create_user_group(request):
        # 创建用户组的类型,运行一次后注释,防止多次生成
        # models.UserGroup.objects.create(caption='CEO')
        # models.UserGroup.objects.create(caption='CTO')
        # models.UserGroup.objects.create(caption='COO')
        return HttpResponse('ok')
    
    # 创建用户表
    def create_user(request):
        # 将请求数据作为参数传递给UserForm,生成相应对象
        obj = ForeignForm.UserForm(request.POST)
        # 判断请求类型是否为'POST'类型
        if request.method == 'POST':
            # 进行From表单验证,验证其有效性
            if obj.is_valid():
              # 获取请求数据
                all_data = obj.clean()
                
              # 把获取的数据存储到数据库,有3种方法
                # 第1种方法(对象级别操作):先获取对象
                # group_obj = models.UserGroup.objects.get(id=all_data['group'])
                # 为什么创建数据库表时,第二个参数(关联外键)user_group=group_obj?
                # 这是因为在Model里user_group = models.ForeignKey('UserGroup'),这里user_group实际上是关联了一个对象,
                # 所以在传递参数时要传递相应的对象参数。
                # models.User.objects.create(username=all_data['username'],user_group=group_obj)
    
                # 第2种方法(数据库级别操作,这里注意Django默认给外键字段名加上了"_id")
                # models.User.objects.create(username=all_data['username'],user_group_id=all_data['group'])
                
                # 第3种方法(传字典参数,但是要注意form中已经组成了字典数据)
                models.User.objects.create(**all_data)
               # 打印数据库中所以信息的条数
                print models.User.objects.all().count()
            else:
                # 写上报错提示信息,form表单的验证信息,这里省略了
                pass
                
        # 根据输入的用户组,查找该组的所有用户信息
        # http://127.0.0.1:8000/create_user/?usergroup=CEO
        # 获取输入的用户组信息    
        val = request.GET.get('usergroup')
        # 跨表查询,双下划线
        user_list = models.User.objects.filter(user_group__caption=val)
       
       return render(request,'foreign/create_user.html',{'obj':obj,'user_list':user_list})

     运行效果如下图所示:

    实例4:一对多连表关系中的多级关联

      models.py文件

    #/usr/bin/env python
    #-*- coding:utf-8 -*-
    
    from __future__ import unicode_literals
    from django.db import models
    
    # Create your models here.
    #一对多连表关系中的多级关联
    #用户类型表
    class UserType(models.Model):
        type_list = models.CharField(max_length=64,null=True,blank=True)
    
        def __unicode__(self):
            return self.type_list
    
    # 用户组表
    class UserGroup(models.Model):
        caption = models.CharField(max_length=32)
        user_type = models.ForeignKey('UserType')
    
        def __unicode__(self):
            return self.caption
    
    # 用户表
    class User(models.Model):
        username = models.CharField(max_length=32)
        user_group = models.ForeignKey('UserGroup')
    
        def __unicode__(self):
            return self.username

       views模块中foreign.py文件

    #!/usr/bin/env python
    #-*- coding:utf-8 -*-
    __author__ = 'mcp'
    
    from django.shortcuts import HttpResponse,render
    from app01 import models
    from app01.forms import foreign as ForeignForm
    
    #!/usr/bin/env python
    #-*- coding:utf-8 -*-
    __author__ = 'mcp'
    
    from django.shortcuts import HttpResponse,render
    from app01 import models
    from app01.forms import foreign as ForeignForm
    
    def create_user_group(request):
        #添加用户类型
        models.UserType.objects.create(type_list='金牌会员')
        models.UserType.objects.create(type_list='银牌会员')
        models.UserType.objects.create(type_list='普通会员')
        #添加用户组
        models.UserGroup.objects.create(caption='CEO',user_type_id=1)
        models.UserGroup.objects.create(caption='CTO',user_type_id=2)
        models.UserGroup.objects.create(caption='COO',user_type_id=3)
    
        return HttpResponse('OK')
    
    def create_user(request):
        obj = ForeignForm.UserForm(request.POST)
    
        if request.method == 'POST':
            if obj.is_valid():
                all_data = obj.clean()
                #先获取对象,然后把对象作为参数
                group_obj = models.UserGroup.objects.get(id=all_data['user_group'])
                models.User.objects.create(username=all_data['username'],user_group=group_obj)
        # 测试1:获取所有的用户信息表
        # user_list = models.User.objects.all()
    
        #测试2:从URL中获取请求的信息
        val = request.GET.get('usertype')
        # 注意跨表多级查询外键时,双下划线的使用
        user_list = models.User.objects.filter(user_group__user_type__type_list=val)
        return render(request,'foreign/create_user.html',{'obj':obj,'user_list':user_list})

      forms模块中foreign.py文件

    #!/usr/bin/env python
    #-*- coding:utf-8 -*-
    __author__ = 'mcp'
    
    from django import forms
    from app01 import models
    
    class UserForm(forms.Form):
    
        username = forms.CharField()
        user_group = forms.IntegerField(widget=forms.Select())
        user_type = forms.IntegerField(widget=forms.Select())
    
        def __init__(self,*args,**kwargs):
            super(UserForm,self).__init__(*args,**kwargs)
    
            self.fields['user_group'].widget.choices = models.UserGroup.objects.all().values_list('id','caption')
            self.fields['user_type'].widget.choices = models.UserType.objects.all().values_list('id','type_list')

      templates/foreign目录下的create_user.html文件

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
        <form action="/create_user/" method="post">
            <p>用户名:{{ obj.username }}</p>
            <p>用户组:{{ obj.user_group }}</p>
            <p>用户类型{{ obj.user_type }}</p>
            <input type="submit" value="submit"/>
        </form>
    
        <table>
            {% for item in user_list %}
            <tr>
                <td>{{ item.username }}</td>
                <td>{{ item.user_group.caption }}</td>
                <td>{{ item.user_group.user_type.type_list }}</td>
            </tr>
            {% endfor %}
        </table>
    </body>
    </html>

      测试1和测试2运行结果分别如下图所示:(在实例4的多级关联中,实际上用户组合用户类型是已经绑定死了的,不能选择,例如加入用户组是CEO,那么用户类型就是金牌会员,不能选择)

                                                              

    一对多小结:
    1、外键user_group在数据库中是以新字段名称user_group_id(Django自动生成的名称:外键名+'_id')存储的,
       这样将前端的数据存入数据库时,就可以构造字典参数,直接把字典作为参数传给数据库创建函数create;
    2、在实例中,外键user_group为对象,对应着UserGroup中的一行数据;
    3、数据库中获取数据采用"."操作符;
    4、数据库中跨表查询关联外键的字段值采用"__"双下划线操作符(注意双下划线操作符),比如实例中的
       user_list = models.User.objects.filter(user_group__caption=val),它表示查询关联外键user_group
       中caption字段值为val的User表中的相关用户数据

    5、在外键的多级关联中,在数据库中查询数据时,下划线可以连着使用

     参考资料:

          http://www.cnblogs.com/wupeiqi/articles/5246483.html

          http://www.cnblogs.com/luotianshuai/p/5301343.html              

  • 相关阅读:
    【转帖】asp.net mvc与webform区别
    [学习jquery]深入了解jquery(1)jquery对象
    windows ce 4.2/5.0/6.0/windows mobile设备直接连接PC端的SQLserver
    dotNet dispose 和 close的区别
    简易快速理解 ERP
    互联网盈利模式77种创新 [转]
    软件开发的基础知识[1]
    什么是 SHTML
    ASP.NET 2.0:弃用 DataGrid 吧,有新的网格控件了![msdn]
    主页制作五十式[好帖就要转]
  • 原文地址:https://www.cnblogs.com/maociping/p/5338183.html
Copyright © 2011-2022 走看看