01-Django学习笔记

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中判断是否有返回数据:如果有,返回数据,并动态创建下拉框,添加数据
注意:
    最后一级没有数据,但是创建选框;解决:在返回数据时进行判断

    每次选择元素都创建新的选项框,不会删除原来的选项框
    解决:当选中元素时,移除当前元素之后的所有元素
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,937评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,503评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,712评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,668评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,677评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,601评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,975评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,637评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,881评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,621评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,710评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,387评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,971评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,947评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,189评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,805评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,449评论 2 342

推荐阅读更多精彩内容