zoukankan      html  css  js  c++  java
  • python_way day18 html-day4, Django路由,(正则匹配页码,包含自开发分页功能), 前端模板, Model(jDango-ORM) : SQLite,数据库时间字段插入的方法

    python_way day18 html-day4

    1、Django-路由系统 

         - 自开发分页功能

    2、模板语言:之母板的使用

          a、后端输入传输到前端

        b、前端的一些函数 ({% load %})

            c、自定义前端函数

            d、母版嵌套使用( {% extend %}、{% include %} )

    3、SQLite:model(jDango-ORM) 

      数据库时间字段插入的方法


    一、Django-路由系统

    当我们访问django web框架时django给我们提供了一套路由系统,通过不同的url对应不同的函数(django内部循环匹配,只要有匹配上的就去找对应的函数名,匹配就结束了。)

    图示:

        urls   ->  views

    创建django程序:

    project : 
    
      django-admin startproject mysite
    
    cd mysite
    
    app:
    
    python3 manage.py startapp app01
    

    基本的urls配置:

    urls:

    views:

    路由扩展:

    1、访问时可以在url后面追加多个参数:

    urls:

    from django.conf.urls import url
    from django.contrib import admin
    from drawer import views
    
    urlpatterns = [
        url(r'^admin/', admin.site.urls),
        url(r'^login/', views.login),
        url(r'^index/(d+)/', views.index),                      #加一个参数
        url(r'^index1/(d+)/(d+)/', views.index1),              #也可以加两个
        url(r'^index2/(?P<p1>d+)/(?P<p2>d+)/', views.index2),  #接受两个参数,并且使用正则表达式给分组命令的方法为这两个参数命令。这样在接受函数中的参数必须有这连个参数名。
    ]
    

    views:

    def index1(request, nid,nnid):  #取值就用形参,对应位置
        print(nid,nnid)
        return HttpResponse("index1")
    
    def index2(request, p1,p2):    #取值就可以使用定义好的p1和p2
        print(p1,p2)      
        return HttpResponse("index2")  

    2、应用: 

    如果我们有一个页面是论坛,这个版块有200页,按照上面的写法,我们就要写200个函数来处理:这时我们就可以在第一页中使用正则匹配每一页的页码。这样一个函数就可以负责200页了。

    urlpatterns = [
        url(r'^admin/', admin.site.urls),
        url(r'^login/', views.login),
        url(r'^index/(d+)/', views.index),     #<====加一个参数
    ]
    urls
    USERLIST = []
    # [userInfo,userInfo,...]
    
    for i in range(70):    #创建70条假数据
        temp = {"id": i, "username": "user" + str(i), "email": str(i) + "@qq.com"}
        USERLIST.append(temp)    
    
    def index(request, page=1):
        userlist = USERLIST     #所有的用户信息
        page = int(page)        #获取到当前页码
        #1  0  10
        #2 11 20
        start = (page - 1) * 10    #规定每页显示10条数据,用户点1,显示0-10,定义起点
        end = page * 10    #定义用户点击的重点
        userList = userlist[start:end]  #相当于userlist[0:10]的切片效果
        return render(request, "index.html", {"userList": userList})
        
    views.py
     <ul>
            {% for line in userList %}
                <li>{{ line.id }}</li>
                <li>{{ line.username }}</li>
                <li>{{ line.email }}</li>
            {% endfor %}
        </ul>
    这样就可以根据用户点击的页码使用一条urls规则显示不同的数据。
    index.html

    一个带有页码的完整应用

    class PageNum:
        def __init__(self, showPageNum, allPageNum, chosePageNum):
            self.showPageNum = showPageNum
            self.allPageNum = allPageNum
            self.chosePageNum = chosePageNum
    
        def pageNUmList(self):
            pageList = []
            for i in range(self.allPageNum + 1):
                pageList.append(i)              #获取页码的所有值
            if self.allPageNum > self.showPageNum:    #如果总共的页数大于6,证明需要翻页了。
                if self.chosePageNum > 3:             #如果选择的数字大于了3,就要向后面扩展几页
                    pageStart = self.chosePageNum - 2  # 页码的起始页
                    pageEnd = self.chosePageNum + 4    #页码的终止页
                    showPageList = pageList[pageStart:pageEnd]   #从页码的所有值里面截取想要长度的列表
                    return showPageList
                else:
                    showPageList = list(map(lambda x: x+1, pageList[0:6]))
                    return showPageList
            else:                        #如果所有页面没有超过6页
                showPageList = list(map(lambda x: x+1, pageList))
                return showPageList
    
    
    class Pager:
        def __init__(self, all_count, line_number):
            self.all_count = all_count
            self.line_number = line_number
    
        def pageNum(self):
            k1 ,k2 = divmod(self.all_count, self.line_number)
            if k2 == 0:
                return k1
            else:
                return k1 + 1
    public.py
    def index(request, page=1):
        userlist = USERLIST     #所有的用户信息
        page = int(page)        #获取到当前页码
        #1  0  10
        #2 11 20
        start = (page - 1) * 10
        end = page * 10
        userList = userlist[start:end]  #相当于userlist[0:10]的切片效果
    
        page_obj = public.Pager(len(userlist),10)
        page_num = page_obj.pageNum()  #算数总共有多少页码
    
        pageObj = public.PageNum(6, page_num, page)
        page_list = pageObj.pageNUmList()       #算出页码的列表
    
        return render(request, "index.html", {"userList": userList,"pageList": page_list,"page_num":page_num})
    views.py
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>index</title>
        <link rel="stylesheet" href="/statics/bootstrap-3.3.5/dist/css/bootstrap.css" />
    </head>
    <body>
        <ul>
            {% for line in userList %}
                <li>{{ line.id }}</li>
                <li>{{ line.username }}</li>
                <li>{{ line.email }}</li>
            {% endfor %}
        </ul>
        <nav>
            <ul class="pagination">
                <li><a id="before" href="#">&laquo;</a></li>    {#向做箭头#}
                {% for item in pageList %}
                <li><a href="/index/{{ item }}/">{{ item }}</a></li>  {#根据用户点击跳转到想应页面。#}
                {% endfor %}
                <li><a id="after" href="#">&raquo;</a></li>     {#向右箭头#}
            </ul>
        </nav>
        <script src="/statics/js/jquery-3.1.0.min.js"></script>
        <script src="/statics/js/my_js.js"></script>
        <script src="/statics/bootstrap-3.3.5/dist/js/bootstrap.min.js"></script>
        <script>
    {#        $("ul[class=pagination] li a[id=before],ul[class=pagination] li a[id=after]").Touch()#}
            $("ul[class=pagination] li a[id=before]").TouchBefore();
            $("ul[class=pagination] li a[id=after]").TouchAfter({{ page_num }});
        </script>
    </body>
    </html>
    index.html

     

    3、路由的扩展:

    当我们的项目中有多个模块时:

    我们人为增加了一个account的用户的功能,想把所有关于用户的功能放在这里,这是为了便利以及归类

    from django.conf.urls import url, include
    from django.contrib import admin
    
    urlpatterns = [
        url(r'^admin/', admin.site.urls),
        url(r'^account/', include('account.urls')),   #这里将account.url  私用include引入进来
    ]

    account  的  url  

    import os, sys
    sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
    
    from account import  views
    from django.conf.urls import include, url
    from django.contrib import admin
    
    
    urlpatterns = [
        url(r'check$', views.huatuo),
    ]

    此时用户访问:

    127.0.0.1:8000/account/check 就会通过第一层主路由    url(r'^account/', include('account.urls'))  跳转到 account 的urls中,然后再匹配第二层的url  check 就访问到views.huatuo的函数了

      


    二、模板语言:之母板的使用

    1、html 后台返回数值的方式

    后台渲染html页面,并且定义了一个detail_dict 变量,使用字典的形式返回给前端用户。 字典内部定义了不同类型的数据。(字符串,列表,字典)

    后端:
    def test(request,page):
    return render(request,'index.html',{'k1':'v1',"k2":[1,2,3],"k3":{"name":"hanxu","age":18}})

    2、前端获取值的方法

    前端获取字符串,列表,字典

    前端 循环使用
    <body>
    {{ k1 }} //使用key获取一个参数,
    {{ k2.0 }} //使用key . 索引的方式获取列表的值
    {{ k2.name }} //获取自定中的value
    <div>
    {% for item_list in k2 %} //或者使用循环列表的方式获取列表中的值
    <li> {{ item_list }},{{ forloop.counter }},{{ forloop.counter0 }},{{ forloop.frist }},{{ forloop.last }},{{ forloop.revcouter }} </li>
                 //forloop 只能在for循环中使用
                  //forloop.counter 列表中当前的索引,索引从1开始 forloop.counter0 索引从0开始, forloop.frist 查询当前元素是否为第一个,是则return: True,
                  // {{ forloop.last }} 是否为最后一个,是则 return : True
                  // {{ forloop.revcouter }} 索引值倒叙         
        {% endfor %}
    </div>
    </body>
    </html>

      

    前端循环if else 使用


    {% if k1 == 'v1' %}
    <h1>v1</h1>
    {% elif k1 == 'v2' %}
    <h1>v2</h1>
    {% else %}
    <h1>v3</h1>
    {% endif %}

    注 : 在 {% if k1 %} 中的 k1相当于 {{ k1 }} 中获取的值

    3、html内置函数以及自定义函数

    内置函数

    {{ item.event_start|date:"Y-m-d H:i:s"}}  //传到前端的时间格式化
    {{ bio|truncatewords:"30" }}              //只显示字符串前30个字符
    {{ my_list|first|upper }}           //第一个字符变大写
    {{ name|lower }}                          //将传过来的字符变小写
    ... ...

      

    自定义函数:两类方法

    1、filter

    2、simple_tag

    1.filter (支持模板语言中的if条件)

    创建自定义函数的方法:

    1、在app中创建指定文件夹,文件夹名称不能改。  叫: templatetags

    2、创建一个任意的py文件

    3、py编写函数。

    #!/usr/bin/env python
    #coding:utf-8
    from django import template
    from django.utils.safestring import mark_safe
       
    register = template.Library()   #前面返回值的名称必须要 register ,不能改成其他的。
    #############################以上是格式,就要这么导入##########################   

    @register.filter
    def f1(value):
    return value + "666"

    4、html 使用函数

    {% load xx %}    //这里加载 xx 文件
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>temp</title>
    
    </head>
    <body>
        <div>
            {{ k1 | f1 }}   //这里使用 xx函数
        </div>
    </body>
    </html>
    

    setting中增加注册 app

      

    现在就可以看到了  

    自定义函数传参数,filter 只支持一个传递一个参数,如果想传递多个参数就用符号分割,然后在py中做分割获取

    html:

    {% load xx %}    //这里加载 xx 文件
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>temp</title>
    
    </head>
    <body>
        <div>
            {{ k1 | f1:"hanxu" }}   //这里使用 xx函数
        </div>

      <div>
        {% if k1|f1 %} //如果k1使用f1的函数后返回的是true 则执行true这段代码
        <h1> true </h1>
    {% else %}      //如果k1使用f1的函数后返回值是false 则执行false这段代码
        <h1> false </h1>
      </div> </body> </html>

      

    py

    #!/usr/bin/env python
    #coding:utf-8
    from django import template
    from django.utils.safestring import mark_safe
       
    register = template.Library()   #前面返回值的名称必须要 register ,不能改成其他的。
    #############################以上是格式,就要这么导入##########################   
    

    @register.filter def f1(value, arg): return value + "666" + arg


    ###下面是支持if的例子
    @register.filter
    def f3(value):
       if value == "1":
        return True
       return False

      

    2、simple_tag(不支持模板语言中的if条件)

    py后端运行1-3步都一直,只是装饰器不同

    #!/usr/bin/env python
    # _*_ coding : utf-8 _*_
    #@Auter: newboy
    #@Date: 2017/6/22
    
    from django import template
    from django.utils.safestring import mark_safe
    
    register = template.Library()   #前面返回值的名称必须要 register ,不能改成其他的。
    #############################以上是格式,就要这么导入##########################
    
    #想要定义模板语言的函数需要装饰器装饰
    #simple_tag类型函数 @register.simple_tag def my_input(id,arg): result = "<input type='text' id='%s' class='%s' />" %(id,arg,) return mark_safe(result)

    #####这下面是普通使用的例子##### #simple_tag类型函数 @register.simple_tag def f2(s1, s2, s3, s4): return s1+s2+s3+s4

    html前端调用

    {% load xx %}    //这里加载
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>temp</title>
    
    </head>
    <body>
        <div>
            {% f2 1 2 3 4 %}   //这里使用  simple_tag 可以传输任意多个参数 ,直接使用f2函数,但是不能调用后端传来的数值
        </div>
    </body>
    </html>
    

      

    在我们写一些后台管理页面的时候,因为后台的样式,布局基本一致,只有页面右侧数据展示部分不同,我们就为了省去重复的写多个一样的页面就还可以使用模板的母板功能,类似于写一个函数,每次调用这个函数就可以完成相同的工作了。

    母板嵌套:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>home</title>
        <link rel="stylesheet"  href="/statics/assets/bootstrap/css/bootstrap.min.css" />
        <link rel="stylesheet"  href="/statics/assets/bootstrap/css/bootstrap-theme.min.css" />
        <link rel="stylesheet"  href="/statics/assets/css/my_home.css" />
        {%  block css %}{% endblock %}                            #按照惯例,这里写一个css的块,可以提供子板加载自己的css样式
    </head>
    <body >
        <div class="pg-head">
            <div class="a">
                <h4 >CMDB资产管理系统</h4>
            </div>
        </div>
        <div class="pg-body clearfix">
            <div class="body-menu" >
                <ul>
                    <li><a id="msg" href="/home/">服务器信息</a></li>
                    <li><a id="msg_mg" href="/assets/">服务器管理</a></li>
                    <li><a id="user_mg" href="/user/">用户信息管理</a></li>
                </ul>
            </div>
            <div class=" body-inner table-responsive">
                {% block inner %}{% endblock %}                          #母板语言的关键字与格式:{%block%} 里面的inner就是需要替换不同位置的标记,子板就可以加载这个母版,然后
                                                      #把想要放在这个位置的内容写上,并且使用block对应的名字框起来。 </div> </div> <script src="/statics/assets/js/jquery-1.11.1.min.js"></script> <script src="/statics/assets/bootstrap/js/bootstrap.min.js"></script> {% block js %}{% endblock %}                              #这里可以写一个js的替换块,让子板自己使用自己独有的js </body> </html>

    其他html就可以调用这个母板了

    {% extends 'layout.html' %}   #我们需要告诉这个html子板,引用母板的名字,让子板去把layout的html都加载过来。
    
    
    {% block inner %}                        #我们就可以只写这个html不一样的内容,就会放到对应的母版语言中,  inner就对应着母板的inner的位置进行替换
    <h1>数据展示</h1>
    <table class="table table-striped table-bordered ">
        <tr>
            <th>用户名</th>
            <th>邮箱</th>
            <th>密码</th>
        </tr>
        {% for line in data %}
            <tr>
                <td>{{ line.user }}</td>
                <td>{{ line.email }}</td>
                <td>{{ line.password }}</td>
          </tr>
        {% endfor %}
    </table>
    <table class="table table-striped table-bordered ">
        <tr>
            <th>用户名</th>
            <th>邮箱</th>
            <th>密码</th>
        </tr>
        {% for line in data %}            
            <tr>
                <td>{{ line.user }}</td>
                <td>{{ line.email }}</td>
                <td>{{ line.password }}</td>
          </tr>
        {% endfor %}
    </table>
    
    <div class="pg">
        <a>1</a>
        <a>2</a>
        <a>3</a>
    </div>
    {% endblock %}
    
    {% block js %}                           #增加自己这个页面需要的html页面
        <script>
            $("#user_mg").parent().addClass("active");     #找到id为user_mg的标签,添加上active这个样式
        </script>
    {% endblock %}
    

       

    重复使用相同的一个代码块怎么可以简便一些。

    就比如说上图,这几块都是一样的,可能页面中有很多地方都会有这样相同规格的代码块。

    再比如在页面有多个下图的输入框,这时我能可能就要写多个这个div 的块,里面包着很多input标签。

          

    在母版语言中有一个简便的方法:

    1、随便起一个名字的html文件,

    2、html中 使用include 引入这个html 全名

     这样页面上就实现了重复使用相同代码块的功能

    效果和之前的一样。


    三、model (ORM)

    django中遵循 Code Frist 的原则,即:根据代码中定义的类来自动生成数据库表。

    1.创建(增,删,改,查) 数据库表

     a、位置:app.models.py 写类

     b、python manage.py makemigrations

          python manage.py migrate

      创建表

      1、基本结构

    from django.db import models
       
    class userinfo(models.Model):
       nid = models.AutoField(primary_key=True) #如果不创建这条,自动会生成一个隐含的id列,如果创建了并设置成主键,
                                  #这样就不会创建隐含的id列了。 name = models.CharField(max_length=30)    #string类型 email = models.EmailField()           #也是字符串类型,帮助admin做输入验证 memo = models.TextField()            #text类型
      
    #email对数据库本身就是个字符串类型,没有任何区别,这是帮助admin做数据验证的。 

    admin中设置email时会提示有错误

    sqlate数据更多字段

    1、models.AutoField(primary_key=True)  自增列 = int(11)
      如果没有的话,默认会生成一个名称为 id 的列,如果要显示的自定义一个自增列,将这列设置为主键 primary_key=True。不写这列在建表的时候会自己创建。
    2、models.CharField  字符串字段
      必须 max_length 参数
    3、models.BooleanField  布尔类型=tinyint(1)
      不能为空,Blank=True
    4、models.ComaSeparatedIntegerField  用逗号分割的数字=varchar
      继承CharField,所以必须 max_lenght 参数,input(12,344,555,)
    5、models.DateField  日期类型 date
      对于参数,auto_now = True 则每次更新都会更新这个时间;auto_now_add 则只是第一次创建添加,之后的更新不再改变。
    6、models.DateTimeField  日期类型 datetime
      同DateField的参数
    7、models.Decimal  十进制小数类型 = decimal
      必须指定整数位max_digits和小数位decimal_places
    8、models.EmailField  字符串类型(正则表达式邮箱,admin中验证邮箱格式) =varchar
      对字符串进行正则表达式
    9、models.FloatField  浮点类型 = double
    10、models.IntegerField  整形
    11、models.BigIntegerField  长整形
      integer_field_ranges = {
        'SmallIntegerField': (-32768, 32767),
        'IntegerField': (-2147483648, 2147483647),
        'BigIntegerField': (-9223372036854775808, 9223372036854775807),
        'PositiveSmallIntegerField': (0, 32767),
        'PositiveIntegerField': (0, 2147483647),
      }
    12、models.IPAddressField  字符串类型(ip4正则表达式),以后可能会被GenericIPAddressField代替
    13、models.GenericIPAddressField  字符串类型(ip4和ip6是可选的)
      参数protocol可以是:both、ipv4、ipv6
      验证时,会根据设置报错
    14、models.NullBooleanField  允许为空的布尔类型
    15、models.PositiveIntegerFiel  正Integer
    16、models.PositiveSmallIntegerField  正smallInteger
    17、models.SlugField  减号、下划线、字母、数字
    18、models.SmallIntegerField  数字
      数据库中的字段有:tinyint、smallint、int、bigint
    19、models.TextField  字符串=longtext
    20、models.TimeField  时间 HH:MM[:ss[.uuuuuu]]
    21、models.URLField  字符串,地址正则表达式
    22、models.BinaryField  二进制
    23、models.ImageField   图片      #保存时还是以字符串保存,文件路径,在dgango admin 中自动提供保存图片的功能
    24、models.FilePathField 文件         #保存时还是以字符串保存,文件路径,在dgango admin 中自动提供上传文件的功能
    1null=True
      数据库中字段是否可以为空
    2、blank=True
      django的 Admin 中添加数据时是否可允许空值
    3、primary_key = False
      主键,对AutoField设置主键后,就会代替原来的自增 id 列
    4、auto_now 和 auto_now_add
      auto_now   自动创建---无论添加或修改,都是当前操作的时间
      auto_now_add  自动创建---永远是创建时的时间
    5、choices
    GENDER_CHOICE = (
            (u'M', u'Male'),
            (u'F', u'Female'),
        )
    gender = models.CharField(max_length=2,choices = GENDER_CHOICE)
    6、max_length
    7default  默认值
    8、verbose_name  Admin中字段的显示名称
    9、name|db_column  数据库中的字段名称
    10unique=True  不允许重复
    11、db_index = True  数据库索引
    12、editable=True  在Admin里是否可编辑
    13、error_messages=None  错误提示
    14、auto_created=False  自动创建
    15、help_text  在Admin中提示帮助信息
    16、validators=[]
    17、upload-to
    更多参数
    class HostInfo(models.Model):
        id = models.AutoField(primary_key=True)
        ip = models.GenericIPAddressField(protocol='ipv4')
        port = models.PositiveIntegerField
        root_pwd = models.CharField(max_length=32)
        buytime = models.DateTimeField
        ctime = models.DateTimeField(auto_now=True,auto_now_add=True)   #创建及修改时间
        hosttype_choices = (     #首先先定义好对应值
            (0,"内网"),
            (1,"阿里"),
            (1,"IDC"),
        )
        hosttype= models.PositiveIntegerField(choices=hosttype_choices) #然后再使用。这样省去了连表操作的资源消耗
    choices使用方法

    备注:

      1、在已经创建过数据库后,如果对数据库修改,就会影响已经存在的值,如新增字段,原有的行新增字段如何处理呢?

          方法一:我们可以给设置一个  models.ImageField(default=0),就是默认值为0,但是这样做还有问题,如果这个字段是个外键,正巧外键这张表也是

          刚刚新创建的,这张外键表中没有0这个nid

          方法二:上面的情况如果遇到时我们还可以把这个参数设置为models.ForeignKey(null=True,blank=True)

           null:是这个字段可以为空

          blank:是在Django-admin中可以不用填写

      2、如果我们想把所有已经创建的表给删除,我们需要怎么做?

         在我们创建过表以后,想把所有的表都不要了,我们就需要将目录 migrations目录中的所有文件都删除,

         然后再执行 python3 manage.py makemigrations python3 manage migrate

      

    2、Django admin使用

    a.在admin.py中设置:

    from django.contrib import admin
    from cmdb import models
    # Register your models here.
    
    #注册所创建的表
    admin.site.register(models.UserInfo,models.CloudHost) #想要使用写的class生成表,或者在后台admin中使用,需要在这里注册就要在admin中注册,

    开启django admin功能

    b.在urls中设置admin的路由

    urlpatterns = [
        url(r'^admin/', admin.site.urls), #这里是默认的处理,先不用
        url(r'^index/', views.index),   #用户访问的url是^index/ 的就给路由到views.index的这个函数
        ... ...
    ]
    

    c、创建超级管理员用户

    Terminal:
    python3 manage.py createsuperuser
    注册用户名: xxxx
    注册密码: xxxx

    d、就可以访问后台了

    /admin/  

     

     3、多表操作

    • 一对多,models.ForeignKey(ColorDic)
    • 一对一,models.OneToOneField(OneModel)
    • 多对多,authors = models.ManyToManyField(Author)

    a.一对多


    class HostType(models.Model): id = models.AutoField(primary_key=True) hosttype = models.CharField(max_length=32)



    class HostInfo(models.Model): id = models.AutoField(primary_key=True) ip = models.GenericIPAddressField(protocol='ipv4') port = models.PositiveIntegerField root_pwd = models.CharField(max_length=32) status = models.BooleanField(blank=True,) #blank=True,Django/admin后台在添加数据的时候不做可以为空的验证 #设置外键约束,外键的表是HostType HostType = models.ForeignKey(HostType) #如果这个HostInfo表是新原来就有的,这个字段是新创建的,原来生成过的数据这一列是没有的。
    !!!或者: HostType = models.ForeignKey("HostType"),这么写的好处是 HostType这个类的位置就不用必须卸载自己这个类的上面了
    #我们在更新这个表的时候会有报错,那么处理方式: #HostType = models.ForeignKey(HostType, null=True) 让原来没有这列的数据允许为空 #HostType = models.ForeignKey(HostType, default=1) 或者让这个默认值唯一,但是如果HostType也是新床架你的没有数据,这样改也是会报错的

    注:已经生成表的基础上,对原来有数据的表进行修改,或者增加一个表对原表做外键会报错.

    例如这里下图红圈中的数据原先没有,在后来增加的

    报错内容:

    因为django 无法判断原有数据如何处理 ,此时的处理方法

     1.

    user_type = models.ForeignKey(UserType,default=1)
    但是此时我们的UserType表也是新创建的,没有数据,1是一个非法字段,不适合这个方法

     2.

    user_type = models.ForeignKey(UserType,null=True,black=True)
    null=True 表示数据库中的字段可以为空
    blank=True 表示django admin 中的这个字段不做必填写验证

     b、多对多

    1、自动创建第三张表

    class Boy(models.Model):
        name = models.CharField(max_length=32)
    
    class Girl(models.Model):
        name = models.CharField(max_length=32)
        f = models.ManyToManyField(Boy)  #这样第三张表就自动创建了 表明就是Boy_Girl
      #操作时就使用f这个字段来操作第三章表

      

    2、自己创建第三张表

    class Boy(models.Model):
        name = models.CharField(max_length=32)
    
    class Girl(models.Model):
        name = models.CharField(max_length=32)
        
    class B2G(models.Model):        #使用这个字段操作第三章表
        boy = models.ForeignKey("Boy")
        girl = models.ForeignKey("Girl")
    

      

    c、一对一

    class HostInfo(models.Model):
        id = models.AutoField(primary_key=True)
        ip = models.GenericIPAddressField(protocol='ipv4')
        port = models.PositiveIntegerField
        root_pwd = models.CharField(max_length=32)
        status = models.BooleanField(blank=True,) 
    #设置外键约束,一对一的表是HostType hosttype = models.OneToOneField("HostType",null=True,blank=True) #这样就创建了一对一的关系表, #如果hostttype:host1 --> ali , host2就不能再对应 ali这个HostType了。 class HostType(models.Model): nid = models.PositiveIntegerField hosttype = models.CharField(max_length=32) def __str__(self): return self.hosttype

      

     4、操作数据库

    a、基本操作

    # 增
        #
        # models.Tb1.objects.create(c1='xx', c2='oo')  增加一条数据,可以接受字典类型数据 **kwargs
    
        # obj = models.Tb1(c1='xx', c2='oo')
        # obj.save()
    
        # 查
        #
        # models.Tb1.objects.get(id=123)         # 获取单条数据,不存在则报错(不建议)
        # models.Tb1.objects.all()               # 获取全部
        # models.Tb1.objects.filter(name='seven') # 获取指定条件的数据
    
        # 删
        #
        # models.Tb1.objects.filter(name='seven').delete() # 删除指定条件的数据
    
        # 改
        # models.Tb1.objects.filter(name='seven').update(gender='0')  # 将指定条件的数据更新,均支持 **kwargs
        # obj = models.Tb1.objects.get(id=1)
        # obj.c1 = '111'
        # obj.save()                                                 # 修改单条数据
    sqlite基本操作

    value  & value_list

    obj = models.Tb1.objects.filter(name='seven').valus('id','email')
       #obj是一个queryset对象 这是个列表里面放着所有Tb1表中所有name=‘seven’的数据行的对象[obj1,obj2,...],
       #后面加上.valus就是从这些对象中找到所有的id此时这个obj里面就变成了:
        #[{'id':1,"email":"888@qq.com"},{'id':2},{"email":"999@qq.com"}...]
    obj = models.Tb1.objects.filter(name='seven').valus_list('id','email')
             [(1,"888@qq.com"),(2,"email":"999@qq.com"),...]
    查询的高级用法
    def test_sqlite(request):
        if request.method == "POST":
            user = request.POST.get("user",None)
            value = request.POST.get("value",None)
            print(user,value)
     
         values = models.New_Text.objects.all().values("title","content")
         value_list = models.New_Text.objects.all().values_list("title","content")
         print(values)
            print(value_list)
    return render(request,"text_sql.html")
    
    结果
    values  : [{'title': '十一国庆去哪里', 'content': '武汉,还是青岛'}, {'title': '十一国庆去哪里', 'content': '武汉,还是青岛'}, {'title': '十一国庆去哪里', 'content': '武汉,还是青岛'}]
    value_list : [('十一国庆去哪里', '武汉,还是青岛'), ('十一国庆去哪里', '武汉,还是青岛'), ('十一国庆去哪里', '武汉,还是青岛')]

      

    b、进阶操作(了不起的双下划线)

    利用双下划线将字段和对应的操作连接起来

    # 获取个数
        #
        # models.Tb1.objects.filter(name='seven').count()
    
        # 大于,小于
        #
        # models.Tb1.objects.filter(id__gt=1)              # 获取id大于1的值
        # models.Tb1.objects.filter(id__lt=10)             # 获取id小于10的值
        # models.Tb1.objects.filter(id__lt=10, id__gt=1)   # 获取id大于1 且 小于10的值
    
        # in
        #
        # models.Tb1.objects.filter(id__in=[11, 22, 33])   # 获取id等于11、22、33的数据
        # models.Tb1.objects.exclude(id__in=[11, 22, 33])  # not in
    
        # contains
        #
        # models.Tb1.objects.filter(name__contains="ven")
        # models.Tb1.objects.filter(name__icontains="ven") # icontains大小写不敏感
        # models.Tb1.objects.exclude(name__icontains="ven")
    
        # range
        #
        # models.Tb1.objects.filter(id__range=[1, 2])   # 范围bettwen and
    
        # 其他类似
        #
        # startswith,istartswith, endswith, iendswith,
    
        # order by
        #
        # models.Tb1.objects.filter(name='seven').order_by('id')    # asc
        # models.Tb1.objects.filter(name='seven').order_by('-id')   # desc
    
        # limit 、offset
        #
        # models.Tb1.objects.all()[10:20]
    
        # group by
        from django.db.models import Count, Min, Max, Sum
        # models.Tb1.objects.filter(c1=1).values('id').annotate(c=Count('num'))
        # SELECT "app01_tb1"."id", COUNT("app01_tb1"."num") AS "c" FROM "app01_tb1" WHERE "app01_tb1"."c1" = 1 GROUP BY "app01_tb1"."id"
    
    进阶操作
    

    obj.query 就可以把sqlate对应的sql语句查询出来  

    c、连表操作: (了不起的双下划线)

    利用双下划线和 _set 将表之间的操作连接起来 

    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
    
    表结构实例
    

      

    model进阶用法:

    • 创建:
    class News_Type(models.Model):
        caption = models.CharField(max_length=32)
    #国内新闻,国际新闻,宇宙新闻
    
    
    
    class New_Text(models.Model):
        title = models.CharField(max_length=32)
        content  = models.CharField(max_length=32)
        newstype = models.ForeignKey(News_Type)
    表结构

     创建 New_Text 表数据的时候 newstype字段需要制定类型

    传统创建的方法
    models.New_Text.objects.create(title="十一国庆去哪里",content="武汉,还是青岛",newstype=UserType.objects.get(id=2))
    

    但是这么操作需要2个数据库操作才能完成。

    有一个方法可以一次数据库操作就能完成

     我们通过查看表结构可以发现,newstype字段后面有一个_id

    models.New_Text.objects.create(title="十一国庆去哪里",content="武汉,还是青岛",newstype_id=2)

    我们就可以使用newstype_id这个字段了。这个 newstype_id=2 就对应着  News_Type表中id=2的哪一样queryset对象

    • 查询(跨表操作)
    两次sql操作的方法:

    1、先拿到国内新闻的id type_id = models.New_Type.object.get(caption="国内新闻").id
    2、然后再通过新闻的id去New_Text表中获取到对应国内新闻的这些新闻 news = New_Text.objects.filter(newstype=type_id) 或者 news = New_Text.objects.filter(newstype_id=type_id)
    一次sql操作的跨表操作方法:利用双下划线
    new_info_obj2 = models.New_Text.objects.filter(newstype__caption="国内新闻")  #这里这个newstype__caption是django帮我们进行的连表操作

    newstype就是对指的 New_Type表中queryset对象,这个对象的__caption一列 = “国内新闻”

    new_info_obj2:
    [<New_Text: New_Text object>, <New_Text: New_Text object>, <New_Text: New_Text object>]

    如果我们想要其中的内容

    class Click(models.Model):
       name = models.CharField(max_length=32)

    class News_Type(models.Model): caption = models.CharField(max_length=32) c = models.ForeignKey(Click) class New_Text(models.Model): title = models.CharField(max_length=32) content = models.CharField(max_length=32) newstype = models.ForeignKey(News_Type)

    title或者 content或者newstye这些:

       print(new_info_obj2)
       print(new_info_obj2[0].title)
       print(new_info_obj2[0].content)
       print(new_info_obj2[0].newstype.id)
       print(new_info_obj2[0].newstype)
       : News_Type object
       print(new_info_obj2[0].newstype.caption)
      : 国内新闻
       new_info_obj2_value = models.New_Text.objects.filter(newstype__caption="国内新闻").values("newstype__id") #在values中也是可以跨表的
      print(new_info_obj_value)
       [{'newstype__id': 1}, {'newstype__id': 1}, {'newstype__id': 1}] 

    跨2张表也是使用双下划线

    new_info_obj2_value = models.New_Text.objects.filter(newstype__c__name="xx")
    这样就是可以找到Click

    关于sqlite   models.DateTimeField() 存放格式的要求

    def time_to_obj(struc_time,TZ=None):
        """
        将struc结构化时间转化为时间对象,TZ为时区,例子:TZ = pytz.timezone('Asia/Shanghai')
        """
        #先将结构化时间转化成时间戳
        nowtime = time.mktime(struc_time)
        # 将当前时间的时间戳,存入数据库中
        zone = datetime.datetime.fromtimestamp(nowtime,TZ)
        return zone
      
       1、其实就是需要将时间戳转化成时间对象,为什么我们用了结构化时间转化呢?
       因为time.localtime()方法,直接就获得了当前时间的strctime格式的当前时间,所以我上面就转化了一下
       2、时区问题,如果你的nowtime直接传入了一个UTC时间,就需要TZ这个参数去设置一下时区,默认 fromtimestam 这个字段的TZ形参位置是None,但是我们写上了也得定义一下,就定以了None


    时区倒入pytz这个自带库就可以了
    TZ = pytz.timezone('Asia/Shanghai')

      

  • 相关阅读:
    浅析Scrapy框架运行的基本流程
    排序和搜索
    设计模式:桥接模式及代码示例、桥接模式在jdbc中的体现、注意事项
    设计模式:适配器模式(类适配器、对象适配器、接口适配器)
    设计模式:建造者模式及在jdk中的体现,建造者模式和工厂模式区别
    java的线程、创建线程的 3 种方式、静态代理模式、Lambda表达式简化线程
    设计模式:原型模式介绍 && 原型模式的深拷贝问题
    设计模式:工厂设计模式介绍及3种写法(简单工厂、工厂方法、抽象工厂)
    设计模式:单例模式介绍及8种写法(饿汉式、懒汉式、Double-Check、静态内部类、枚举)
    设计模式七大原则及代码示例
  • 原文地址:https://www.cnblogs.com/python-way/p/5844206.html
Copyright © 2011-2022 走看看