美文网首页
01-Django学习笔记

01-Django学习笔记

作者: 蛋挞先生L | 来源:发表于2018-11-05 20:51 被阅读0次

    Django

    1. 特点

    • 快速开发:Django的宗旨在于帮助开发人员快速从概念到完成应用程序。
    • 安全可靠:Django认真对待安全性,帮助开发人员避免许多常见的安全错误。
    • 超可伸缩性: Web上的一些最繁忙的网站利用了Django快速灵活扩展的能力。

    2. 入门

    MVC 设计模式

    目标:程序的解耦
    在行业内普遍存在的设计模式

    M  ==>  Model       模型    ==> 数据层   ==> 针对数据的操作 ===>转化成对数据库的操作 (sql)  映射关系
    
    V  ==>  view        视图    ==> 展示层  ==> 展示页面(页面中会有数据)  里面加载的是 模板(html文件)
    
    C  ==>  Controller  控制器  ==> 逻辑层  ==> 业务逻辑  根据用户的请求去调用模型,获取数据后交给视图去展示数据
    

    MVT 设计模式

    目标:程序的解耦
    仅限于Django中的设计模式

    M ==> Model 模型(对数据的操作)
    V ==> view  视图(业务逻辑)
    T ==> Template 模板(页面的展示)
    

    路由

    负责请求地址的匹配,并交给指定的视图函数进行处理

    如:www.pyweb.com/yichuan/p/123457/
    前面到com都为域名,后面的yichuan/p/123457/这是就是url地址
    在路由的url函数中可以写正则表达式进行匹配,例如:
    url(r'^address/2003/$', views.year)
    

    3. 项目的搭建

    • 执行命令:django-admin startproject 项目名
    • 系统会创建一系列文件和文件夹,其中项目名下有一个文件夹与项目同名
    • 项目的总目录可以重命名,但是其中的文件尽量不要重命名,否则需要修改配置

    创建应用

    • 命令行:python3 manage.py startapp 应用名
    • 我们需要操作的文件views.pymodels.py

    启动项目 ⭐⭐⭐

    • 在终端中输入命令行:python3 manage.py runserver
    • 之后终端中会返回地址,一般都为本地地址:http://127.0.0.1:8000

    输出一个 Hello World 的过程

    1. 创建应用:python3 manage.py startapp myhome
    2. 在应用文件夹中找到视图函数 views.py
    3. 定义视图函数
    def hello(request):
        return HttpResponse('hello world')
    
    1. 注意:需要导入 HttpResponse:from django.http import HttpResponse

    2. 定义路由规则

      1. 先到根路由urls.py文件中定义规则,交给自定义应用的子路由url(r'^', include('myhome.urls'))
      2. 定义子路由器,在自定义应用中创建一个urls.py文件,并添加路由规则url(r'^', views.hello),其中url函数三个参数,第一个为路由规则,第二个为指定的视图函数
    3. 启动服务,开始访问

    请求、访问过程

    1. 当用户在浏览器中访问url地址时,服务器接收请求
    2. --> 交给根路由进行匹配
    3. --> 交给子路由进行url地址匹配
    4. --> 子路由调用相应的视图函数
    5. --> 视图函数进行执行,开始响应
    

    4. 使用模板

    1. 配置模板引擎

      1. 找到项目配置文件 settings.py
      2. 修改templates的配置项中的DIRS为:'DIRS':[os.path.join(BASE_DIR,'templates')]
    2. 在manage.py文件的同级目录下创建一个templates的文件夹,里面放置模板文件,即html文件

    3. 在视图函数中使用render函数加载模板

    def tmp(request):
        return render(request,'t.html')
    
    # 其中render函数有三个参数,1-请求对象,为固定写法;2-模板路径;3-传入模板的数据(字典类型)
    

    5. 路由规则 ⭐⭐⭐

    基本规则

    1. 路由按照从上至下的顺序执行
    2. 路由中可以使用()来捕获 url 请求中的一部分作为参数来使用,例如
    # 请求路径:http://127.0.0.1:9000/articles/2014/
    
    # 路由规则
    url(r'^articles/([0-9]{4})/$', views.year_archive),
    
    # 视图函数
    def year_archive(request,y):
            print(y)
            return HttpResponse('year_archive')
    

    注意:在有()的正则路由规则中,对应的视图函数中必须用形参来接收()中的传入的参数

    正则表达式命名组

    以上的路由规则中,对视图函数的接收没有命名要求,形参的名字可以随意更改,但是命名组规则要求视图函数中接收参数的形参必须为规定的名称,例如

    # 路由规则
    url(r'^abc/(?P<year>[0-9]{4})/$', views.abc_2003),
    
    # 视图函数
    def abc_2003(request,year):
            print(year)
            return HttpResponse('abc_2003')
    

    默认值参数

    使用两个路由规则,指向同一个视图函数

    # 路由规则
    url(r'^user/list/$', views.userlist),
    url(r'^user/list/(?P<page>[0-9]+)/$', views.userlist),
    
    # 视图函数
    def userlist(request,page=1):
        print(page)
        return HttpResponse('userlist')
    

    url的反向解析 ⭐⭐⭐⭐⭐

    通过路由规则的名(name),动态解析路由的地址

    如果在视图、模板中使用硬编码(直接写死请求地址)的链接,在你url发生改变时,维护是意见非常麻烦的事情

    # 为了能够动态的解析url的规则,可以在定义路由规则时,给路由器起一个名字(name)
    # 路由规则
    url(r'^goods/list/$', views.goodslist,name='glist'),
    
    # 然后可以在视图和模板中通过反向解析动态的获取路由解析地址
    # 视图函数
    def hello(request):
        # 视图函数中进行反向解析,获取url地址,需要提前导入reverse
        # from django.core.urlresolvers import reverse
        r1 = reverse('goods')
        r2 = reverse('order')
        print(r1,r2)
        return render(request, 't.html')
    
    # 模板
    <a href="{% url 'glist' %}">商品列表:反向解析格式</a>
    

    注意:路由规则中如果有参数要求,那么模板中在使用url进行反向解析时,必须给参数

    <a href="{% url 'olist' 100 %}">订单列表:反向解析格式</a>
    

    反向解析是路由中的重中之重,必须要搞清楚!

    6. 模型关系 ⭐⭐⭐⭐

    一对一(人对应身份证)

    定义

    一对一关系指模型的关系时一一对应的,例如:

    • 一个用户对应一条用户详细信息
    • 一个身份证对应一个人
    • 一个微信号对应一个用户

    二者一一对应,如果有一个用户的详细信息,必对应一个用户

    创建模型

    • 在建立模型时建立两个模型,在其中一个模型中加入外键
    • 在模型中使用models.OneToOneField(关联的模型名,是否关联删除)来建立外键,没有外键的为主数据,有外键的为副数据
    # 模型关系 一对一
    
    # 用户模型
    class User(models.Model):
        username = models.CharField(max_length=50)
        age = models.IntegerField()
    
    # 用户详情
    class UserInfo(models.Model):
        # 此语句为创建外键
        uid = models.OneToOneField(User,on_delete=models.CASCADE)
        xueli = models.CharField(max_length=50)
        yuanxiao = models.CharField(max_length=5)
    

    增删查

    1. 增加
      一对一模型进行增加时不需要特殊注意,直接进行增加,Django框架会自动将两个模型创建的数据进行关联
    2. 删除
      一对一模型在进行数据删除时,如果删除的是主数据,则副数据也会被删除;如果副数据被删除,主数据则不会被删除
    3. 查询
      一对一模型在进行数据查询时有两种方法:
      • 通过主数据查找副数据:主数据对象.副数据类名(小写).查询的属性名
      • 通过副数据查找主数据:副数据对象.外键名.查询的属性名
    # 模型关系:一对一
    def one(request):
        # 添加
        # # 创建用户
        data = {'username':'燕小六','age':20}
        user = User.objects.create(**data)
        # 创建详情
        infodata = {'uid':user,'xueli':'本科','yuanxiao':'家里蹲'}
        info = UserInfo.objects.create(**infodata)
    
        # 删除
        # 删除用户时会关联删除对应的详情数据
        user = User.objects.first()
        user.delete()
        # 删除详细信息,用户不会被删除
        ui = UserInfo.objects.first()
        ui.delete()
    
        # 查询
        # 根据用户获取详细信息
        user = User.objects.first()
        print(user.username)
        print(user.userinfo.xueli)
        # # 根据详细信息获取用户信息
        ui = UserInfo.objects.first()
        print(ui.xueli)
        print(ui.uid.username)
    
        return HttpResponse('<h1>模型关系:一对一<h1>')
    

    一对多(商品分类对应分类下的商品) ⭐⭐⭐⭐

    定义

    • 一个商品分类对应多个商品
    • 一个班级对应多个学生
    • 一个国家对应多个城市

    创建模型

    • 在建立模型时建立两个模型,在商品中加入外键
    • 在模型中使用models.ForeignKey(关联的模型名)来建立外键
    # 模型关系:一对多
    # 商品类别
    class Classify(models.Model):
        name = models.CharField(max_length=50)
    
    # 商品
    class Goods(models.Model):
        # 设置外键,第二个参数为可选
        cid = models.ForeignKey(to="Classify", to_field="id")
        title = models.CharField(max_length=50)
        price = models.IntegerField()
    
        def __str__(self):
            return self.title
    

    增删查

    1. 增加
      增加时不需要特殊注意,直接进行增加,Django框架会自动将两个模型创建的数据进行关联
    2. 删除
      如果删除的是商品分类,则分类下的商品也会被删除;如果分类下的商品被删除,商品分类则不会被删除
    3. 查询
      一对一模型在进行数据查询时有两种方法:
      • 获取商品分类下所有商品:商品分类.商品类名(小写)_set.all()
      • 获取商品所属分类:商品对象.外键名.查找的属性
    # 模型关系:一对多
    def two(request):
        # 添加
        # 创建商品分类
        c = Classify.objects.create(**{'name':'手机'})
        # 创建商品
        g1 = Goods.objects.create(**{'cid':c,'title':'小米8','price':'2399'})
        g1 = Goods.objects.create(**{'cid':c,'title':'华为P20','price':'4399'})
        g1 = Goods.objects.create(**{'cid':c,'title':'OPPO Find X','price':'4999'})
    
        # 删除
        c = Classify.objects.last()
        c.delete()
    
        # 查询
        # 根据分类获取下面所有的商品
        c = Classify.objects.first()
        print(c.name)
        print(c.goods_set.all())
        # 根据商品获取其分类
        g = Goods.objects.first()
        print(g.title)
        print(g.cid.name)
        return HttpResponse('模型关系:一对多')
    

    多对多(一本书对应多个标签,一个标签对应多本书) ⭐⭐⭐⭐

    定义

    • 一本书对应多个标签,一个标签对应多本书
    • 一个老师对应多个班级,一个班级对应多个老师

    创建模型

    • 需要用到第三张表,而不是单单在表中添加外键
    • 第三张表用来记录书和标签互相的关系
    • 在模型中使用models.ManyToManyField(关联的模型名)来建立对多对关系,且定义在任意模型中即可
    # 模型关系:多对多
    # 书
    class Books(models.Model):
        title = models.CharField(max_length=50)
    
        def __str__(self):
            return self.title
    
    class Tags(models.Model):
        name = models.CharField(max_length=50)
        # 设置关系语句
        bid = models.ManyToManyField(to="Books")
    
        def __str__(self):
            return self.name
    

    增删查

    1. 增加
      增加时需要进行关系声明,且方式取决于关系语句设置在哪个模板中,以上面代码为例
      • 给书添加标签:书对象.tags_set.set([标签对象1,标签对象2,...])
      • 给标签添加书:标签对象.bid.add(书对象1,书对象2,...)
      • 多对多关系设置方法:
        • .set([对象1,对象2,...]) 添加关系
        • .add(对象1,对象2,...) 添加关系
        • .clear() 清空关系
    2. 删除
      • 无论删除书或标签,表3中相应的关系记录都会关联删除
      • .clear() 清空指定对象的所有关系
    3. 查询
      • 获取一本书的所有标签:书对象.tags_set.all()
      • 获取一个标签下的所有书:标签对象.bid.all()

    7. 模型查询

    1. 查询集

    • 在管理器上调用过滤器方法会返回查询集,查询集表示从数据库中获取的对象集合
    • 查询集经过过滤器筛选后返回新的查询集,因此可以写成链式过滤
    • 惰性执行:创建查询集不会带来任何数据库的访问,直到调用数据时,才会访问数据库
    • 何时对查询集求值:迭代,序列化,与if合用
    • 返回查询集的方法,称为过滤器
    • all(): 获取所有的返回值
    • filter(): 过滤掉不符合条件的值 filter(键1=值1,键2=值2) == filter(键1=值1).filter(键2=值2)
    • exclude(): 获取除了满足条件之外的值
    • order_by(): 分组返回值根据条件进行排序
    • values(): 一个对象构成一个字典,然后构成一个列表返回

    返回单个值

    • get(): 返回单个满足条件的对象
      • 如果未找到则引发模型类.DoesNotExist异常
      • 如果返回多条,会引发"模型类.MultipleObjectsReturned"异常
    • count(): 返回当前查询的总条数
    • first(): 返回第一个对象
    • last(): 返回最后一个对象
    • exists(): 判断查询集中是否有数据,如果有返回True,反之返回False

    限制查询集

    • 查询集返回列表,可以使用下标的方式进行限制,等同于sql中的limit和offset子句
    • 注意:不支持负数索引
    • 使用下标后返回一个新的查询集,不会立即执行查询
    • 如果获取一个对象,直接使用[0],等同于[0:1].get(),但是如果没有数据,[0]引发IndexError异常,[0:1].get()引发DoesNotExist异常
    #这会返回前5个对象 LIMIT 5
    Entry.objects.all()[:5]
    #这将返回第六个到第十个对象 OFFSET 5 LIMIT 5
    Entry.objects.all()[5:10]
    

    2. 字段查询

    • 实现where子名,作为方法filter()、exclude()、get()的参数
    • 语法:属性名称__比较运算符=值
    • 表示两个下划线,左侧是属性名称,右侧是比较类型
    • 对于外键,使用“属性名_id”表示外键的原始值
    • 转义:like语句中使用了%与,匹配数据中的%与,在过滤器中直接写,例如:filter(title__contains="%")=>where title like '%%%',表示查找标题中包含%的

    比较运算符

    1. exact:判断等,区分大小写;如果没有写'比较运算符',表示判断等
    filter(isDelete=False)
    
    1. contains:是否包含,区分大小写
    exclude(btitle__contains='传')
    
    1. startwith\endswith:以value开头或结尾,区分大小写
    exclude(btitle__endswith='传')
    
    1. isnull\isnotnull:判断是否为null
    filter(btitle__isnull=False)
    
    1. 在前面加个i表示不区分大小写,如iexact、icontains、istarswith、iendswith

    2. in:是否包含在范围内

    filter(pk__in=[1, 2, 3, 4, 5])
    
    1. gt、gte、lt、lte:大于、大于等于、小于、小于等于
    filter(id__gt=3)
    
    1. year、month、day、week_day、hour、minute、second:对日期间类型的属性进行运算
    filter(bpub_date__year=1980)
    filter(bpub_date__gt=date(1980, 12, 31))
    

    8.View视图

    1. GET\POST

    一键一值

    # 这种方式当键不存在或多个键时会报错
    request.GET['name']
    # 这种方式None为默认值,如果数据不存在则返回默认值
    request.GET.get('name',None)
    
    request.POST['name']
    request.POST.get('name',None)
    

    一键多值

    # 返回值为一个列表
    request.GET.getlist('name',None)
    request.POST.getlist('name',None)
    

    2. HttpResponse对象

    1. 在django.http模块中定义了HttpResponse对象的API
    2. HttpRequest对象由Django自动创建,HttpResponse对象由程序员创建
    3. 在每一个视图函数中必须返回一个HttpResponse对象,当然也可以是HttpResponse子对象

    3. HttpResponse

    • 不使用模板,直接返回数据
    • 返回数据类型为字符串
    • 如果字符串中是标签,浏览器可以进行解析
    return HttoResponse('你好')
    

    4. render

    • 调用模板返回数据
    • 参数1:request,固定形式
    • 参数2:'模板路径',即html文件的路径
    • 参数3:字典类型的数据,用于传入模板中
    return render(request,'user/edit.html',{'info':'你好'})
    

    5. 子类 HttpResponseRedirect

    • 重定向,服务器端跳转
    • 构造函数的第一个参数用来指定重定向的地址
    • 可以简写为 redirect
    return redirect(reverse('myindex')
    

    6. 子类 JsonResponse

    • 返回json书,一般用于异步请求
    • 帮助用户创建JSON编码的响应
    • JsonResponse的默认类型为application/json
    • 参数1:字典类型数据
    • 参数2:safe=True/False,默认为True,False表示关闭数据安全,参数1可以传入非字典类型
    return JsonResponse([{'list': 'abc'},{'d': 'ac'}],safe=False)
    

    7. set_cookie 方法

    • Cookie 是由 Web 服务器保存在用户浏览器(客户端)上的小文本文件,它可以包含有关用户的信息。
    • 服务器可以利用Cookies包含信息的任意性来筛选并经常性维护这些信息,以判断在HTTP传输中的状态。
    • Cookies最典型的应用是判定注册用户是否已经登录网站
    1. 设置cookie
    # 设置cookie
    def setcok(request):
        # 获取当前的 响应对象
        res = HttpResponse('设置cookie')
        # 使用响应对象进行cookie的设置
        res.set_cookie('a', 'abcd')
        # 返回响应对象
        res.set_cookie('c', 'cdef')
        return res
    
    1. 获取cookie
    # 获取cookie
    def getcok(request):
        cok = request.COOKIES.get('a', None)
        return HttpResponse(cok)
    

    8. set_session 方法

    • sesison方式所有数据存储在服务器端,在客户端cookie中存储唯一的身份标识
    • 当用户进行请求时,判断cookie中的唯一标识符是否与用户请求中携带的唯一标识符相同
    • 认证成功后页面可以调用session中的所有内容
    • 向对于cookie更加安全,信息不容易被截获
    • 存储的内容比cookie更加丰富
    1. 开启session
    • 使用django-admin startproject创建的项目默认启用
    • 禁用会话:删除下面指定的两个值,禁用会话将节省一些性能消耗
    • Django 中session需要依赖数据库,因此需要确认数据库中是否存在 与session相关的 表
    • 在settings.py文件中
    * 向INSTALLED_APPS列表中添加:
    * 'django.contrib.sessions',
    
    * 项MIDDLEWARE_CLASSES列表中添加:
    * 'django.contrib.sessions.middleware.SessionMiddleware',
    
    1. 设置session
    # 设置session
    def setsess(request):
        # 设置session
        request.session['user'] = {'username':'李四','userid':'12314','age':20}
        request.session['vip'] = {'username':'王五','userid':'12314','age':20}
        return HttpResponse('设置session')
    
    1. 获取session
    # 获取session
    def getsess(request):
        res = request.session.get('user',None)
        if res:
            return HttpResponse('欢迎'+res['username'])
        else:
            return HttpResponse('请登录')
    
    1. 删除session
    # 删除session
    def outsess(request):
        # 删除会话中的一个key;注意:删除时,如果不存在,则报错
        # del request.session['user']
    
        # 清除所有会话信息,但不会删除会话记录,会话依然存在
        # request.session.clear()
    
        # 删除当前的会话所有的数据及记录
        # request.session.flush()
        return HttpResponse('退出')
    
    1. session配置
    在 settings.py 文件中进行设置:
    # session 设置
    SESSION_COOKIE_AGE = 60 * 30 # 30分钟
    SESSION_SAVE_EVERY_REQUEST = True #如果SESSION_SAVE_EVERY_REQUEST是True,会话cookie将在每个请求中发送
    SESSION_EXPIRE_AT_BROWSER_CLOSE = True # 关闭浏览器,则COOKIE失效
    
    #来自 <https://docs.djangoproject.com/en/1.11/topics/http/sessions/>
    
    以下设置为:10秒后过期
     # request.session['abc'] = 'abcdef'
     # request.session.set_expiry(10)
    

    Ajax 实例

    四级城市联动 - 思路

    前提:
        创建模型
        填充数据
        配置静态文件
    
    1. 定义路由,获取一级城市数据,返回城市联动的html页面
    2. 在html页面中循环并显示一级城市数据
    3. 定义一个路由,接收ajax请求
    4. 在视图函数中接收页面传回的选项id,回去下一级数据,并返回json格式
    5. 在html的页面中动态绑定change事件,获取id,发送ajax请求
    6. 在ajax中判断是否有返回数据:如果有,返回数据,并动态创建下拉框,添加数据
    注意:
        最后一级没有数据,但是创建选框;解决:在返回数据时进行判断
    
        每次选择元素都创建新的选项框,不会删除原来的选项框
        解决:当选中元素时,移除当前元素之后的所有元素
    

    相关文章

      网友评论

          本文标题:01-Django学习笔记

          本文链接:https://www.haomeiwen.com/subject/wxsexqtx.html