Django

Django框架简介

Django 是一个由 Python 写成的开放源代码的 Web 应用框架。因其使Web 开发任务,快速和容易b被广泛使用。

执行流程

 

 

  • URL ( urls.py )  ----请求调度,当有缓存页面的时候直接返回内容。存储函数和路径的对应关系
  • 视图函数( view.py ) ----执行所请求的操作,通常包括读写数据库。 存放与路径对应的函数
  • 模型( models.py ) ---- 定义了 Python 中的数据并与之交互。通常包含在一个关系数据库( MySQL、PostgreSQL SQLite 等),其他数据存储是可能的( XML、文本文件、LDAP、等)。请求执行任务后,视图返回一个 HTTP 响应对象(通常是经过数据处理的一个模板)。可选的:视图可以保存一个版本的 HTTP 响应对象,返回携带一个时间戳,来告诉浏览器这个视图的更新时间。
  • 模板(templates)----通常返回 HTML 页面。Django 模板语言提供了 HTML 的语法及逻辑。

基本配置

基本命令

# 查看django版本
 python -m django --version

# 创建项目,名为mysite
 django-admin startproject django名字

# 启动django
 python manage.py runserver            #默认127.0.0.1:8000
 python manage.py runserver 8080
 python manage.py runserver 0.0.0.0:8000

# 创建应用程序,确保和 manage.py 是同一目录
 python manage.py startapp app名字# admin创建管理员用户
 python manage.py createsuperuser

在启动Django时首先要对其进行必要的配置

模板 

# 在settings里修改,放html文件

TEMPLATE_DIRS = (
        os.path.join(BASE_DIR,'templates'),
    )

 静态文件

# 在settings里修改添加,放css,js等文件

STATICFILES_DIRS = (
        os.path.join(BASE_DIR,'static'),
    )

路由系统

URL配置(URLconf)就像Django 所支撑网站的目录。它的本质是URL与要为该URL调用的视图函数之间的映射表。

from django.conf.urls import url
from app import views

urlpatterns = [
         url(r'^login/$',views.login)
         url(
r'^login/(\w+)/(\d+)', views.login)
                #此时views中的login函数需要写三个参数login(request,args1,args2),捕获的值作为位置参数传给视图函数。
         url(r'^login/(?P<name>\w+)/(?P<pwd>\d+)', views.login),
                #此时views中的login函数需要写三个参数login(request,name,pwd),捕获的值作为关键字参数而不是位置参数传递给视图函数,且参数名就是命名
                                                  分组赋值的变量名。
] 

  • 要捕获从URL中的值,用括号括起来进行分组,会当参数传入 views 视图。
  • 每个捕获的参数发送到视图作为普通的 Python 字符串,无论什么样的匹配正则表达式匹配。

  • 分组和命名分组不可一起使用,否则只会捕获命名分组的值


 url反向解析(根据为url起名字反向查找url地址)

  主要作用就是解决代码僵硬,修改代码工程量大等问题。

 

不带参数

  urls.py
  首先给要跳转的url起名字   url(^login,views.login,name=login)

  views.py
  导入reverse
  from django.urls import reverse
  url=reverse('login')
  return redirect(url)

  complate/html
  {% url 'login'%}


位置参数
  urls.py
  首先给要跳转的url起名字   url(^login/(\d+),views.login,name=login)
  
  views.py
  导入reverse
  from django.urls import reverse
  def login(request,参数名)
    url=reverse('login',args=(参数,))
  
  complate/html
  
{% url 'login' 参数 %}

关键参数
  
urls.py
  首先给要跳转的url起名
  url(^login/(?P<key>\d+),views.login,name=login)
  
  views.py
  
导入reverse
  from django.urls import reverse
  def login(request,key)  
    url=reverse('login',kwargs={key:"参数"})
  
  complate/html
  {% url 'login' key=参数 %}

 

namespace

  即使不同的APP使用相同的URL名称,URL的命名空间模式也可以让你唯一反转命名的URL。

project中的urls.py

from django.conf.urls import url, include
 
urlpatterns = [
    url(r'^app1/', include('app1.urls', namespace='app1')),
    url(r'^app2/', include('app2.urls', namespace='app2')),
]

app1中的urls.py

复制代码
from django.conf.urls import url
from app1 import views
 
app_name = 'app1'
urlpatterns = [
    url(r'^(?P<num1>\d+)/$', views.func, name='func')
]
复制代码

app2中的urls.py

复制代码
from django.conf.urls import url
from app2 import views
 
app_name = 'app2'
urlpatterns = [
    url(r'^(?P<num2>\d+)/$', views.func, name='func')
]
复制代码

现在,我的两个app中 url名称重复了,我反转URL的时候就可以通过命名空间的名称得到我当前的URL。

语法:

'命名空间名称:URL名称'

模板中使用:

{% url 'app1:func' num1=11 %}

views中的函数中使用

url = reverse('app01:func', kwargs={'num1':11})

 这样即使app中URL的命名相同,我也可以反转得到正确的URL了。

视图系统

一个视图函数(类),简称视图,是一个简单的Python 函数(类),它接受Web请求并且返回Web响应。

响应可以是一张网页的HTML内容,一个重定向,一个404错误,一个XML文档,或者一张图片。

Django使用请求和响应对象来通过系统传递状态。

当浏览器向服务端请求一个页面时,Django创建一个HttpRequest对象,该对象包含关于请求的元数据。然后,Django加载相应的视图,将这个HttpRequest对象作为第一个参数传递给视图函数。

每个视图负责返回一个HttpResponse对象。

Request方式

  • path_info     返回用户访问url,不包括域名
  • method        请求中使用的HTTP方法的字符串表示,全大写表示。
  • GET              包含所有HTTP  GET参数的类字典对象
  • POST           包含所有HTTP POST参数的类字典对象

Response方式

render()
  结合一个给定的模板和一个给定的上下文字典,并返回一个渲染后的 HttpResponse 对象。
render(request, template_name, context=None, content_type=None, status=None, using=None)
  • request: 用于生成响应的请求对象。
  • template_name :一个模板的使用或模板序列名称全称
  • content:一组字典的值添加到模板中,常用于模板中替换
  • content_type:生成的文档要使用的MIME类型。默认为 DEFAULT_CONTENT_TYPE 设置的值。默认为'text/html'
  • status:响应的状态码。默认为200。
  • using: 用于加载模板的模板引擎的名称。 
redirect()
redirect(to, permanent=False, *args, **kwargs)
  默认返回一个临时重定向,通过 permanent=True 设置永久重定向
  
HttpResponse()

     默认返回字符串

 

FBV和CBV类型

FBV

def add_class(request):
    if request.method == "POST":
        class_name = request.POST.get("class_name")
        models.Classes.objects.create(name=class_name)
        return redirect("/class_list/")
    return render(request, "add_class.html")
注:给FBV添加装饰器
  FBV添加装饰器和常规函数添加装饰器是一样的,在被装饰函数前加(@装饰器函数名)

CBV

from django.views import View
class AddClass(View):

    def get(self, request):
        return render(request, "add_class.html")

    def post(self, request):
        class_name = request.POST.get("class_name")
        models.Classes.objects.create(name=class_name)
        return redirect("/class_list/")

注:给CBV添加装饰器
from django.utils.decorators import method_decorator
@method_decorator(装饰器函数名) 加在要装饰的类方法上

 

模板(Template)系统

在Django中模板包含所需的 HTML 输出静态部分以及动态内容插入。

模板内容

  • {{ }} 用于变量相关的替换
  • {% %}  用于逻辑相关的替换
  • {% for item in item_list %}  <a>{{ item }}</a>  {% endfor %}
  • date 日期格式化

    {{ value|date:"Y-m-d H:i:s"}}
forloop.counter 当前循环的索引值(从1开始)
forloop.counter0 当前循环的索引值(从0开始)
forloop.revcounter 当前循环的倒序索引值(从1开始)
forloop.revcounter0 当前循环的倒序索引值(从0开始)
forloop.first 当前循环是不是第一次循环(布尔值)
forloop.last 当前循环是不是最后一次循环(布尔值)
forloop.parentloop 本层循环的外层循环
 

 

 

 

 

 

 

 

  • {% if *** %}  {% elif %}  {% else %}  {% endif %}
  • {{ 字符串|truncatewords:"30" }}如果字符串字符多于指定的字符数量,那么会被截断。截断的字符串将以可翻译的省略号序列(“...”)结尾。组件
  • 可以将常用的页面内容如导航条,页尾信息等组件保存在单独的文件中,然后在需要使用的地方按如下语法导入即可。{% include 'navbar.html' %}

 

母板

通过在母板中使用{% block xxx %}  {% endblock %}替换母板中相应的内容。

在子页面中在页面最上方使用下面的语法来继承母板。
{% extends '母板文件.html' %}

{% block xxx %}
要替换的内容
{% endblock %}

 

静态文件导入

html文件中导入,通过占位符提高函数的解耦性
{% load static %} 
<script src="{% static "bootstrap/js/bootstrap.js"%}"></script>
作用与下面相同
<script src="/static/bootstrap/js/bootstrap.js"></script>

 

跨站请求伪造

django为用户实现防止跨站请求伪造的功能,通过中间件 django.middleware.csrf.CsrfViewMiddleware 来完成。
而对于django中设置防跨站请求伪造功能有分为全局和局部。

全局:

  中间件 django.middleware.csrf.CsrfViewMiddleware

局部:
  @csrf_protect,为当前函数强制设置防跨站请求伪造功能,即便settings中没有设置全局中间件。
  @csrf_exempt,取消当前函数防跨站请求伪造功能,即便settings中设置了全局中间件。
  注:from django.views.decorators.csrf import csrf_exempt,csrf_protect

解决方法:

在页面的form表单里面写上{% csrf_token %}
原理在于当请求通过get方法获取url时,网页内会根据请求生成验证码,而如果是通过拼接路径打开url时,则不会产生,来达到保护网站的作用。

自定义filter

自定义过滤器只是带有一个或两个参数的Python函数:

  • 变量(输入)的值 - -不一定是一个字符串
  • 参数的值 - 这可以有一个默认值,或完全省略

例如,在过滤器{{var | foo:“bar”}}中,过滤器foo将传递变量var和参数“bar”

 

自定义filter代码文件摆放位置:

 
app/
    __init__.py
    models.py
    templatetags/  # 在app下面新建一个package package
        __init__.py
        app_filters.py  # 建一个存放自定义filter的文件
    views.py
 

编写自定义filter

复制代码
from django import template
register = template.Library()


@register.filter(name="cut")
def func(value, arg):
    return value.replace(arg, "")
复制代码

使用自定义filter

{# 先导入我们自定义filter那个py文件 #}
{% load app01_filters %}

{# 使用我们自定义的filter #}
{{ abc|func:123 }}

 

模型(model)系统 

Django 模型是与数据库相关的,与数据库相关的代码一般写在 models.py 中,Django 支持 sqlite3, MySQL, PostgreSQL等数据库,只需要在settings.py中配置即可,不用更改models.py中的代码,丰富的API极大的方便了使用。

对象关系映射(Object Relational Mapping,简称ORM)模式是一种为了解决面向对象与关系数据库存在的互不匹配的现象的技术。

简单的说,ORM是通过使用描述对象和数据库之间映射的元数据,将程序中的对象自动持久化到关系数据库中。

配置数据库

# 由于Django内部连接MySQL时使用的是MySQLdb模块,而python3中还无此模块,所以需要使用pymysql来代替
  
# 如下设置放置的与project同名的配置的 __init__.py文件中 
import pymysql
pymysql.install_as_MySQLdb() 


# 在settings 中修改DATABASES 
DATABASES = {
    'default': {
    'ENGINE': 'django.db.backends.mysql',
    'NAME':'数据库名',
    'USER': 'root',
    'PASSWORD': 'xxx',
    'HOST': '',
    'PORT': '',
    }
}
在创建完model类后,通过执行下面的两条语句,进行模型和数据表之间的映射。
# 记录创造模型变化迁移
 python manage.py makemigrations

# 执行应用模型变化到数据库
 python manage.py migrate

在Django中model是你数据的单一、明确的信息来源。它包含了你存储的数据的重要字段和行为。通常,一个模型(model)映射到一个数据库表,

  • 每个模型都是一个Python类,它是django.db.models.Model的子类。
  • 模型的每个属性都代表一个数据库字段。
  • 模型的对象代表一个数据表的数据行

基本操作

#
models.Tb1.objects.create(c1='xx', c2='oo')  # 增加一条数据,可以接受字典类型数据 **kwargs

obj = models.Tb1(c1='xx', c2='oo')
obj.save()

#
models.Tb1.objects.get()          # 获取单条数据,不存在则报错(不建议)
models.Tb1.objects.getlist() # 获取多条数据
models.Tb1.objects.all() # 获取全部
models.Tb1.objects.filter(name='seven') # 获取指定条件的数据
#
models.Tb1.objects.filter(name='nick').delete() # 删除指定条件的数据

# 改models.Tb1.objects.filter(name='nick').update(gender='0')  # 将指定条件的数据更新,均支持 **kwargs
# 修改单条数据
obj = models.Tb1.objects.get(id=1)
obj.c1 = '111'
obj.save()                                                      
# 修改多条数据 常用与多对多的表中
obj.set()

 

在models.py文件中创建类映射表时,以下为一些字段参数。 

1、models.AutoField  自增列 = 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 参数
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  字符串类型(正则表达式邮箱) =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正则表达式)
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   图片
24、models.FilePathField 文件
字段
1、null=True
  数据库中字段是否可以为空
2、blank=True
  django的 Admin 中添加数据时是否可允许空值
3、primary_key = False
  主键,对AutoField设置主键后,就会代替原来的自增 id 列
4、auto_now 和 auto_now_add
  auto_now   自动创建---无论添加或修改,都是当前操作的时间
  auto_now_add  自动创建---永远是创建时的时间
5、help_text  在Admin中提示帮助信息
6、max_length
7、default  默认值
8、verbose_name  Admin中字段的显示名称
9、name|db_column  数据库中的字段名称
10、unique=True  不允许重复
11、db_index = True  数据库索引
12、editable=True  在Admin里是否可编辑
13、error_messages=None  错误提示
14、auto_created=False  自动创建
参数

 

 ORM查询的方法

<1> all():                 查询所有结果
 
<2> filter(**kwargs):      它包含了与所给筛选条件相匹配的对象
 
<3> get(**kwargs):         返回与所给筛选条件相匹配的对象,返回结果有且只有一个,如果符合筛选条件的对象超过一个或者没有都会抛出错误。
 
<4> exclude(**kwargs):     它包含了与所给筛选条件不匹配的对象
 
<5> values(*field):        返回一个ValueQuerySet——一个特殊的QuerySet,运行后得到的并不是一系列model的实例化对象,而是一个可迭代的字典序列
 
<6> values_list(*field):   它与values()非常相似,它返回的是一个元组序列,values返回的是一个字典序列
 
<7> order_by(*field):      对查询结果排序
 
<8> reverse():             对查询结果反向排序,请注意reverse()通常只能在具有已定义顺序的QuerySet上调用(在model类的Meta中指定ordering或调用order_by()方法)。
 
<9> distinct():            从返回结果中剔除重复纪录(如果你查询跨越多个表,可能在计算QuerySet时得到重复的结果。
 
<10> count():              返回数据库中匹配查询(QuerySet)的对象数量<11> first():              返回第一条记录
 
<12> last():               返回最后一条记录
 
<13> exists():             如果QuerySet包含数据,就返回True,否则返回False

<14>models.Tb1.objects.filter(id__lt=10, id__gt=1)      获取id大于1 且 小于10的值
 
<15>models.Tb1.objects.filter(id__in=[1,2,3])           获取id等于1,2,3的值

<16>models.Tb1.objects.exclude(id__in=[1, 2, 3]) 获取id不等于1,2,3的值 <17>models.Tb1.objects.filter(name__contains="ab") 获取name字段包含"ab"的
<18>models.Tb1.objects.filter(name__icontains="ab") icontains大小写不敏感
<19>models.Class.objects.filter(first_day__year=2018) 获取年

<20>F查询:同一张表的不同列作比较
  from django.db.models import F
  models.Tb1.objects.filter(字段1__num__lt=F('字段2__num'))    #查询字段1数量小于字段2数量的对象
<21>Q查询:多个条件做查询(相当于或)
  models.Book.Tb1.filter(Q(authors__name="张三")|Q(authors__name="李四"))   #查询作者名是张三或李四的书籍

 

 聚合查询和分组查询

聚合查询

aggregate()QuerySet 的一个终止子句,意思是说,它返回一个包含一些键值对的字典。

键的名称是聚合值的标识符,值是计算出来的聚合值。键的名称是按照字段和聚合函数的名称自动生成出来的。

示例:

>>> models.Book.objects.all().aggregate(Avg("price"))
{'price__avg': 13.233333}

如果你想要为聚合值指定一个名称,可以向聚合子句提供它。

>>> models.Book.objects.aggregate(average_price=Avg('price'))
{'average_price': 13.233333}

如果你希望生成不止一个聚合,你可以向aggregate()子句中添加另一个参数。所以,如果你也想知道所有图书价格的最大值和最小值,可以这样查询:

>>> models.Book.objects.all().aggregate(Avg("price"), Max("price"), Min("price"))
{'price__avg': 13.233333, 'price__max': Decimal('19.90'), 'price__min': Decimal('9.90')}

分组查询

为调用的QuerySet中每一个对象都生成一个独立的统计值。

示例1:统计每一本书的作者个数

复制代码
>>> book_list = models.Book.objects.all().annotate(author_num=Count("author"))
>>> for obj in book_list:
...     print(obj.author_num)
...
2
1
1
复制代码

示例2:统计出每个出版社买的最便宜的书的价格

>>> publisher_list = models.Publisher.objects.annotate(min_price=Min("book__price"))
>>> for obj in publisher_list:
...     print(obj.min_price)
...     
9.90
19.90

方法二:

>>> models.Book.objects.values("publisher__name").annotate(min_price=Min("price"))
<QuerySet [{'publisher__name': '沙河出版社', 'min_price': Decimal('9.90')}, {'publisher__name': '人民出版社', 'min_price': Decimal('19.90')}]>

示例3:统计不止一个作者的图书

>>> models.Book.objects.annotate(author_num=Count("author")).filter(author_num__gt=1)
<QuerySet [<Book: 番茄物语>]>

示例4:根据一本图书作者数量的多少对查询集 QuerySet进行排序

>>> models.Book.objects.annotate(author_num=Count("author")).order_by("author_num")
<QuerySet [<Book: 香蕉物语>, <Book: 橘子物语>, <Book: 番茄物语>]>

 

 

关系字段

ForeignKey

  外键类型在ORM中用来表示外键关联关系,一般把ForeignKey字段设置在 '一对多'中'多'的一方。

ManyToManyField

    用于表示多对多的关联关系。在数据库中通过第三张表来建立关联关系。

 

class Book(models.Model):
    name=models.CharField(max_length=32)
    publish_time=models.DateField(auto_now_add=False)
    publisher = models.ForeignKey('Publisher')

class Editor(models.Model):
    name=models.CharField(max_length=32)
    nation=models.CharField(max_length=32)
    book=models.ManyToManyField('Book')    #这里通过第三张表将Editor和Book进行关联。

 

但是这里有一个问题就是,第三张表里只能有三个字段即id 、book_id 和editor_id,想要添加其他字段是不被允许的,这里就需要利用中介模型。

 

中介模型:

  通过自己新建第三张表,此时就需要通过through来指定第三张表的表名。

class Book(models.Model):
    name=models.CharField(max_length=32)
    publish_time=models.DateField(auto_now_add=False)
    publisher = models.ForeignKey('Publisher')

class Editor(models.Model):
    name=models.CharField(max_length=32)
    nation=models.CharField(max_length=32)
    book=models.ManyToManyField('Book',through="Editor_book"through_fields=('field1','field2')) #through表示要关联的表,through_field表示要关联的字段

class Editor_book(models.Model):
  
id = models.AutoField(primary_key=True)
  book=models.ForeignKey(to="Book")
  editor=models.ForeighKey(to="Editor")
  
注:在常规的ManyToManyField中对表进行增删改等可以使用
如: editor_obj=models.Editor.objects.filter(id=2).first()
editor_obj.book.add/set/remove()
但是在中介模型是不允许的,只支持
Editor_book.objects.create(book_id=1,author_id=1)
 

OneToOneField

通常用于把一些不常用的字段放在另一张表中。

 

class Book(models.Model):

    name=models.CharField(max_length=32)
    publish_time=models.DateField(auto_now_add=False)
    publisher = models.ForeignKey('Publisher')
    book_detail=models.OneToOneField(to="Book_Detail")    

class Book_Detail(models.Model):
    id= models.AutoField(primary_key=True)
    price=models.IntegerField()

 

 

to 后接设置要关联的表

to_field

后接设置要关联的字段
related_name

反向操作时,使用的字段名,用于代替原反向查询时的'表_set'。

related_query_name

反向操作时,使用的字段名,用于代替原反向查询时的表名
on_delete

当删除关联表中的数据时,当前表与其关联的行的行为。详细参数见下文

symmetrical

 仅用于多对多自关联时,指定内部是否创建反向操作的字段。默认为True。

db_table

 在ManyToMany关联中默认创建第三张表时的表名称

 

 

 

 

 

 

 

 

 

 

 

 

 

on_delete

  当删除关联表中的数据时,当前表与其关联的行的行为。

  models.CASCADE
  删除关联数据,与之关联也删除

  models.DO_NOTHING
  删除关联数据,引发错误IntegrityError

  models.PROTECT
  删除关联数据,引发错误ProtectedError

  models.SET_NULL
  删除关联数据,与之关联的值设置为null(前提FK字段需要设置为可空)

  models.SET_DEFAULT
  删除关联数据,与之关联的值设置为默认值(前提FK字段需要设置默认值)

  models.SET

  删除关联数据,

  a. 与之关联的值设置为指定值,设置:models.SET(值)

  b. 与之关联的值设置为可执行对象的返回值,设置:models.SET(可执行对象)

 

 字段查询


class Factory(models.Model):
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=32)
addr = models.CharField(max_length=32)


class Car(models.Model): name = models.CharField(max_length=32) factory = models.ForeignKey(to="Factory", related_name="car_name")

正向查找

#对象查找对象

obj_car=models.Car.objects.first() obj_car.factory.all()

#利用字段查找对象

models.Car.objects.first().factory.all()
#利用字段查找对象属性

 models.Car.objects.values("factory__name")

 

反向查找

#传统的反向对象查找

obj_factory=models.Factory.objects.first() obj_car.car_set.all()

#利用对象反向查找对象属性
obj_factory=models.Factory.objects.first()
car_list=obj_car.car_set.all()
for i in car_list:
  print(i.name)

#利用字段反向查找

models.Factory.objects.first().car_name.all()

#利用字段反向查找对象属性

  models.Factory.objects.values("haha__name")

 

元信息

  元信息是关于信息的信息,用于描述信息的结构、语义、用途和用法等

    # 定义元信息
            class Meta:
                ordering = ("price", )  # 默认按照价格排序
                db_table = "car"        # 指定在数据库中创建表的表名
                unique_together = ("name", "price")  # 多字段联合唯一

在pyhthon脚本中运行Django

import os
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "项目名.settings")
import django
django.setup()
            
# 引用Django内部的变量

 cookie和session

cookie

Http协议是无状态的,也就导致服务器无法分辨是谁浏览了网页。为了维持用户在网站的状态,比如登陆、购物车等,出现了先后出现了四种技术,分别是隐藏表单域、URL重写、cookie、session。

cookie具体指的是一段小信息,它是服务器发送出来存储在浏览器上的一组组键值对,下次访问服务器时浏览器会自动携带这些键值对,以便服务器提取有用信息。

获取cookie

request.COOKIES['key']
request.get_signed_cookie(key, default=RAISE_ERROR, salt='', max_age=None)
    参数:
        default: 默认值
           salt: 加密盐
        max_age: 后台控制过期时间

创建cookie

rep = HttpResponse(...) 或 rep = render(request, ...) 或rep= redirect("//")
 
rep.set_cookie(key,value,...)
rep.set_signed_cookie(key,value,salt='加密盐',...)
    参数:
        key,              键
        value='',         值
        max_age=None,     超时时间
        expires=None,     超时时间(IE requires expires, so set it if hasn't been already.)
        path='/',         Cookie生效的路径,/ 表示根路径,特殊的:跟路径的cookie可以被任何url的页面访问
        domain=None,      Cookie生效的域名
        secure=False,     https传输
        httponly=False    只能http协议传输,无法被JavaScript获取(不是绝对,底层抓包可以获取到也可以被覆盖)

 

session

  session的作用和cookie差不多,也是用来解决Http协议不能维持状态的问题。但是session只存储在服务器端的,不会在网络中进行传输,所以较cookie来说,session相对安全一些。但是session是依赖cookie的,当用户访问某一站点时,服务器会为这个用户产生唯一的session_id,并把这个session_id以cookie的形式发送到客户端,以后的客户端的所有请求都会自动携带这个cookie(前提是浏览器支持并且没有禁用cookie)。

获取session
request.session.get['key']
设置session
request.session['key']='value'
request.session.default(key,value)#如果key存在则不添加
删除session
del request.session['key']
 
# 获取用户session的随机字符串
request.session.session_key

# 将所有Session失效日期小于当前日期的数据删除
request.session.clear_expired()

# 检查 用户session的随机字符串 在数据库中是否 request.session.exists("session_key") # 删除当前用户的所有Session数据 request.session.delete()
#设置有效时长 request.session.set_expiry(value) * 如果value是个整数,session会在些秒数后失效。 * 如果value是个datatime或timedelta,session就会在这个时间后失效。 * 如果value是0,用户关闭浏览器session就会失效。 * 如果value是None,session会依赖全局session失效策略。

 

jQuery AJAX

  通过在后台与服务器进行少量数据交换,AJAX 可以使网页实现异步更新。这意味着可以在不重新加载整个网页的情况下,对网页的某部分进行更新。传统的网页(不使用 AJAX)如果需要更新内容,必须重载整个网页页面。

jQuery.ajax(...)
    部分参数:
            url:请求地址
           type:请求方式,GET、POST
        headers:请求头
           data:要发送的数据
    contentType:即将发送信息至服务器的内容编码类型(默认: "application/x-www-form-urlencoded; charset=UTF-8")
          async:是否异步
        timeout:设置请求超时时间(毫秒)

     beforeSend:发送请求前执行的函数(全局)
       complete:完成之后执行的回调函数(全局)
        success:成功之后执行的回调函数(全局)
          error:失败之后执行的回调函数(全局)

        accepts:通过请求头发送给服务器,告诉服务器当前客户端课接受的数据类型
       dataType:将服务器端返回的数据转换成指定类型
                  "xml": 将服务器端返回的内容转换成xml格式
                  "text": 将服务器端返回的内容转换成普通文本格式
                  "html": 将服务器端返回的内容转换成普通文本格式,在插入DOM时,如果包含js标签,会尝试去执行
                  "script": 尝试将返回值当作JavaScript去执行,然后再将服务器端返回的内容转换成普通文本格式
                  "json": 将服务器端返回的内容转换成相应的JavaScript对象      
              JSON.stringify()将javascript值转换成json字符串,JSON.parse()将json字符转换成javascript值
           "jsonp": JSONP 格式 使用 JSONP 形式调用函数时,如 "myurl?callback=?" jQuery 将自动替换 ? 为正确的函数名,以执行回调函数,
    如果不指定,jQuery 将自动根据HTTP包MIME信息返回相应类型

   
     converters: 转换器,将服务器端的内容根据指定的dataType转换类型,并传值给success回调函数

ajax请求设置csrf_token
(1)可以从在要发送的data中写入
"csrfmiddlewaretoken",$("[name='csrfmiddlewaretoken']").val()
(2)直接导入文件
function csrfSafeMethod(method) {
  // these HTTP methods do not require CSRF protection
  return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}

$.ajaxSetup({
  beforeSend: function (xhr, settings) {
    if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
      xhr.setRequestHeader("X-CSRFToken", csrftoken);
    }
  }
});
csrf_token

使用时只需要将上述代码写入JS文件,放入静态文件,在html中通过<script></script>导入即可

 

 

 

form

django中的Form一般有两种功能:

 

  • 输入html
  • 验证用户输入
from django import forms
from django.forms import widgets
from django.core.exceptions import ValidationError
# from django.core.validators import RegexValidator
import re
def phone_check(value):
    phone_re=re.compile(r'(13[0-9]|15[0-9]|17[7-9]]|18[0-9])[0-9]{8}$')
    if not phone_re.match(value):
        raise ValidationError("输入的手机号有误")
# Create your views here.
class RegisterLogin(forms.Form):
    username=forms.CharField(min_length=4,max_length=12,label="用户名",
                             error_messages={
                                 "required":"输入不能为空",
                                 "invalid":"格式错误",
                                 "min_length":"用户名输入最少4位"
                             },
                             widget=forms.widgets.TextInput()
                             )
    pwd=forms.CharField(min_length=4,max_length=20,label="密码",
                        error_messages={
                            "required": "输入不能为空",
                            "invalid": "格式错误",
                            "min_length": "密码输入最少4位"},
                        widget=forms.widgets.PasswordInput()    
                        )

    gender=forms.ChoiceField(
        choices=((1,""),(2,""),(3,"保密")),
        label="性别",
        initial=3,
        widget=forms.widgets.RadioSelect()     
    )
    hobby=forms.MultipleChoiceField(
        choices=((1,"篮球"),(2,"网游"),(3,"睡觉"),(4,"跑步")),
        label="爱好",
        initial=[1,2],
        widget=forms.widgets.SelectMultiple()
    )
    phone=forms.CharField(validators=[phone_check,],
                             error_messages={
                                 "required":"输入不能为空",
                                "invalid": "格式错误",
                             },
                             widget=forms.widgets.TextInput(attrs={"class":"form-control", "placeholde":'手机号码'}))
form
from app_form .form import RegisterLogin
from django.shortcuts import render,HttpResponse
from app01 import models
def register(request):
    error_msg=""
    register_obj=RegisterLogin()   #实例化对象
    if request.method =='POST':
        register_obj = RegisterLogin(request.POST) #把POST提交的数据传到form表单里
        if register_obj.is_valid(): #调用实例化对象做校验
        models.Info.objects.create(user=username,pwd=pwd,gender=gender,hobby=hobby,phone=phone)
            models.Info.objects.create(**register_obj.cleaned_data)
    return render(request,"register.html",{"register_obj":register_obj})
View Code

 在form中可以使用局部钩子和全局钩子对客户输入的值进行校验

局部钩子:  

  def clean_要校验的字段(self):

    校验一个值

 def clean_username(self):    
    #     获取用户输入的值
        user=self.cleaned_data.get("username")
    #     和数据库中的对比
        ret =models.UserInfo.objects.filter(username=user)
        if not ret:
            return user                               #返回该字段通过校验的的值 
     else:
       raise ValidationError(
"用户名已存在") #这个错误会被is_valid捕获

全局钩子:

    校验多个值

  def clean(self):
      pwd = self.cleaned_data.get("password")
      pwd_repeat=self.cleaned_data.get("password_repeat")
      if pwd == pwd_repeat:
          return self.cleaned_data                  #如果通过校验则返回所有通过的值
      else:
          raise ValidationError("两次输入的密码不一致")

用户认证

auth模块是Django提供的标准权限管理系统,可以提供用户身份认证, 用户组管理,并且可以和admin模块配合使用.

在INSTALLED_APPS中添加'django.contrib.auth'使用该APP, auth模块默认启用.

model

from django.contrib.auth.models import User

# 数据库中该表名为auth_user.



若想对auth_user的字段进行扩展
from django.contrib.auth.models import AbstractUser

class UserInfo(AbstractUser): #创建一个类继承AbstractUser,之后表名姜葱auth_user变成你定义的类名
  id = models.AutoField(primary_key=True)
  telephone=models.CharField(max_length=11,unique=True)
  blog = models.OneToOneField(to="Blog",null=True)

新建用户

user = User.objects.create_user(username, email, password) 
user.save()

# 这里创建必须用create_user() # 密码不存储用户密码明文而是存储一个Hash值

认证用户

from django.contrib.auth import authenticate

user = authenticate(username=username, password=password)

# 认证用户的密码是否有效, 若有效则返回代表该用户的user对象, 若无效则返回None.
# 该方法不检查is_active标志位.

修改密码

user.set_password(new_password)

# 以下实例为先认证通过后才可以修改密码
user = auth.authenticate(username=username, password=old_password)
if user is not None:
    user.set_password(new_password)
    user.save()

登录

from django.contrib.auth import login

# login向session中添加SESSION_KEY, 便于对用户进行跟踪:
'login(request, user)'

# login不进行认证,也不检查is_active标志位
user = authenticate(username=username, password=password)
if user is not None:
    if user.is_active:
        login(request, user)

退出登录

# logout会移除request中的user信息, 并刷新session

from django.contrib.auth import logout

def logout_view(request):
    logout(request)

 

中间件(middleware)

中间件是一个用来处理Django的请求和响应的框架级别的钩子。它是一个轻量、低级别的插件系统,用于在全局范围内改变Django的输入和输出。每个中间件组件都负责做一些特定的功能。

中间配置在django同名文件的setttings中

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
   'test.
MiddleWareDemo' ] #自定义中间件

 

中间件中可以定义五个方法,分别是:

  • process_request(self,request)
  • process_view(self, request, callback, callback_args, callback_kwargs)
  • process_template_response(self,request,response)
  • process_exception(self, request, exception)
  • process_response(self, request, response)

以上方法的返回值可以是None和HttpResonse对象,如果是None,则继续按照django定义的规则向下执行,如果是HttpResonse对象,则直接将该对象返回给用户。

我们可以通过自定义中间件实现特定的功能,定义中间件其实就是创建一个类,创建几个方法,django根据特定的情况去执行这些方法。

*自定义中间件*

from
django.utils.deprecation import MiddlewareMixin class MiddleWareDemo(MiddlewareMixin):   def process_request(self):
    print("request")
  def process_view(self):
  def process_response(self,response):

process_request(正序)

  process_request有一个参数,就是request,这个request和视图函数中的request是一样的。

它的返回值可以是None也可以是HttpResponse对象。返回值是None的话,按正常流程继续走,交给下一个中间件处理,如果是HttpResponse对象,Django将不执行视图函数,而将相应对象返回给浏览器。

  • 中间件的process_request方法是在执行视图函数之前执行的。
  • 当配置多个中间件时,会按照MIDDLEWARE中的注册顺序,也就是列表的索引值,从前到后依次执行的。
  • 不同中间件之间传递的request都是同一个对象

 

process_view(正序) 

process_view(self, request, view_func, view_args, view_kwargs)

该方法有四个参数

request是HttpRequest对象。

view_func是Django即将使用的视图函数。 (它是实际的函数对象,而不是函数的名称作为字符串。)

view_args是将传递给视图的位置参数的列表.

view_kwargs是将传递给视图的关键字参数的字典。 view_args和view_kwargs都不包含第一个视图参数(request)。

Django会在调用视图函数之前调用process_view方法。

它应该返回None或一个HttpResponse对象。 如果返回None,Django将继续处理这个请求,执行任何其他中间件的process_view方法,然后在执行相应的视图。 如果它返回一个HttpResponse对象,Django不会调用适当的视图函数。 它将执行中间件的process_response方法并将应用到该HttpResponse并返回结果。

 

process_exception(倒序)

process_exception(self, request, exception)

该方法两个参数:

一个HttpRequest对象

一个exception是视图函数异常产生的Exception对象。

这个方法只有在视图函数中出现异常了才执行,它返回的值可以是一个None也可以是一个HttpResponse对象。如果是HttpResponse对象,Django将调用模板和中间件中的process_response方法,并返回给浏览器,否则将默认处理异常。如果返回一个None,则交给下一个中间件的process_exception方法来处理异常。它的执行顺序也是按照中间件注册顺序的倒序执行。

 

process_response(倒序)

它有两个参数,

一个是request,一个是response,request就是上述例子中一样的对象,response是视图函数返回的HttpResponse对象。该方法的返回值也必须是HttpResponse对象。process_response方法是在视图函数之后执行的,是最后一个执行的。

 

process_template_response(倒序)

 

process_template_response(self, request, response)

它的参数,一个HttpRequest对象,response是TemplateResponse对象(由视图函数或者中间件产生)。

process_template_response是在视图函数执行完成后立即执行,但是它有一个前提条件,那就是视图函数返回的对象有一个render()方法(或者表明该对象是一个TemplateResponse对象或等价方法)。

posted @ 2018-03-29 16:27  排骨南  阅读(335)  评论(0编辑  收藏  举报