1、Model 一对多 补充

models如下:

class UserType(models.Model):
    caption = models.CharField(max_length=16)

class UserInfo(models.Model):
    username = models.CharField(max_length=32)
    pwd = models.CharField(max_length=32)
    user_type = models.ForeignKey('UserType')

 

通过queryset查询用户为CEO的用户

>>> from app01.models import UserInfo,UserType
>>> q = UserInfo.objects.filter(user_type__caption='CEO')
>>> print(q)
<QuerySet [<UserInfo: UserInfo object>]>
>>> print(q[0])
UserInfo object
>>> print(q[0].username)
james
>>> print(q[0].pwd)
45569
>>> print(q[0].user_type.caption)
CEO

 用values,value_list查询

>>> q = UserInfo.objects.filter(user_type__caption='CEO').values('username','pwd','user_type__caption')
>>> q
<QuerySet [{'pwd': '45569', 'username': 'james', 'user_type__caption': 'CEO'}]>
>>> q[0]
{'pwd': '45569', 'username': 'james', 'user_type__caption': 'CEO'}

 value_list 返回元组可以应用到from的select标签

>>> q = UserInfo.objects.filter(user_type__caption='CEO').values_list('username','pwd','user_type__caption')
>>> q
<QuerySet [('james', '45569', 'CEO')]>
>>> q[0]
('james', '45569', 'CEO')

 

2、model操作 F/Q

F:使用查询条件的值


temp = salary+500
models.UserInfo.objects.filter().update(salary=temp)
update userinfo set salary=salary+500

>>> from django.db.models import F
>>> print(models.UserInfo.objects.values('salary'))
<QuerySet [{'salary': '6500'}, {'salary': '6500'}, {'salary': '6500'}]>
>>> print(models.UserInfo.objects.filter().update(salary=F('salary')+500))
3
>>> print(models.UserInfo.objects.values('salary'))
<QuerySet [{'salary': '7000'}, {'salary': '7000'}, {'salary': '7000'}]>

 



Q:构造搜索条件
1、传参

>>> models.UserInfo.objects.filter(id=3,user='jasonwang')
<QuerySet [<UserInfo: jasonwang>]>
>>> print(models.UserInfo.objects.filter(id=3,user='jasonwang').query)
SELECT "app01_userinfo"."id", "app01_userinfo"."user", "app01_userinfo"."pwd", "app01_userinfo"."user_type_id", "app01_userinfo"."ctime", "app01_userinfo"."uptime", "app01_userinfo"."img", "app01_userinfo"."email", "app01_userinfo"."address", "app01_userinfo"."salary" FROM "app01_userinfo" WHERE ("app01_userinfo"."id" = 3 AND "app01_userinfo"."user" = jasonwang)

 



2、传字典

>>> d = {'id':3,'user':'jasonwang'}
>>> models.UserInfo.objects.filter(**d)
<QuerySet [<UserInfo: jasonwang>]>

<input name='id' />
<input name='name' />
获取用户输入,并构造成字典:
models.UserInfo.objects.filter(**d)
3、传Q对象
models.UserInfo.objects.filter(Q对象)

from django.db.models import Q

# q1 = Q()
# q1.connector = 'OR'
# q1.children.append(('id', 1))
# q1.children.append(('id', 2))
# q1.children.append(('id', 3))

# models.Tb1.objects.filter(q1)

>>> q1.connector = 'OR'
>>> q1.children.append(('id',1))
>>> q1.children.append(('id',2))
>>> q1.children.append(('id',3))
>>> qq = models.UserInfo.objects.filter(q1)
>>> print(qq.query)
SELECT "app01_userinfo"."id", "app01_userinfo"."user", "app01_userinfo"."pwd", "app01_userinfo"."user_type_id", "app01_userinfo"."ctime", "app01_userinfo"."uptime", "app01_userinfo"."img", "app01_userinfo"."email", "app01_userinfo"."address", "app01_userinfo"."salary" FROM "app01_userinfo" WHERE ("app01_userinfo"."id" = 1 OR "app01_userinfo"."id" = 2 OR "app01_userinfo"."id" = 3)

# con = Q()
#
# q1 = Q()
# q1.connector = 'OR'
# q1.children.append(('id', 1))
# q1.children.append(('id', 2))
# q1.children.append(('id', 3))
#
# q2 = Q()
# q2.connector = 'OR'
# q2.children.append(('status', '在线'))
#
# con.add(q1, 'AND')
# con.add(q2, 'AND')
#
# models.Tb1.objects.filter(con)

>>> q1.connector = 'OR'
>>> q1.children.append(('id',1))
>>> q1.children.append(('id',2))
>>> q1.children.append(('id',3))
>>> qq = models.UserInfo.objects.filter(q1)
>>> print(qq.query)
SELECT "app01_userinfo"."id", "app01_userinfo"."user", "app01_userinfo"."pwd", "app01_userinfo"."user_type_id", "app01_userinfo"."ctime", "app01_userinfo"."uptime", "app01_userinfo"."img", "app01_userinfo"."email", "app01_userinfo"."address", "app01_userinfo"."salary" FROM "app01_userinfo" WHERE ("app01_userinfo"."id" = 1 OR "app01_userinfo"."id" = 2 OR "app01_userinfo"."id" = 3)
>>> q2 = Q()
>>> q2.connector = 'OR'
>>> q2.children.append(('address','haidian'))
>>> con = Q()
>>> con.add(q1,'AND')
<Q: (OR: ('id', 1), ('id', 2), ('id', 3))>
>>> con.add(q2,'AND')
<Q: (AND: (OR: ('id', 1), ('id', 2), ('id', 3)), ('address', 'haidian'))>
>>> qq = models.UserInfo.objects.filter(con)
>>> print(qq.query)
SELECT "app01_userinfo"."id", "app01_userinfo"."user", "app01_userinfo"."pwd", "app01_userinfo"."user_type_id", "app01_userinfo"."ctime", "app01_userinfo"."uptime", "app01_userinfo"."img", "app01_userinfo"."email", "app01_userinfo"."address", "app01_userinfo"."salary" FROM "app01_userinfo" WHERE (("app01_userinfo"."id" = 1 OR "app01_userinfo"."id" = 2 OR "app01_userinfo"."id" = 3) AND "app01_userinfo"."address" = haidian)
>>> print(qq)
<QuerySet [<UserInfo: jason>]>
>>> print(qq[0])
jason
>>> 

 

3、model多对多操作

- 创建

a. 方式一:
class B2G(models.Model):
b_id = models.ForeignKey('Boy')
g_id = models.ForeignKey('Girl')

class Boy(models.Model):

username = models.CharField(max_length=16)

class Girl(models.Model):

name = models.CharField(max_length=16)

b. 方式二:
class Boy(models.Model):

username = models.CharField(max_length=16)
# girl_set
class Girl(models.Model):

name = models.CharField(max_length=16)

b = models.ManyToManyField('Boy')


- 操作:
添加:
正向

g1 = models.Girl.objects.get(id=1)

g1.b.add(models.Boy.objects.get(id=1))
g1.b.add(1)

bs = models.Boy.objects.all()
g1.b.add(*bs)
g1.b.add(*[1,2,3])

反向

b1 = models.Boy.objects.get(id=1)
b1.girl_set.add(1)
b1.girl_set.add(models.Girl.objects.all())

b1.girl_set.add(*[1,2,3,4])

 


...
删除:

g1 = models.Girl.objects.get(id=1)
g1.b.clear() # 清空和girl ID=1所关联的所有数据

g1.b.remove(2) 
g1.b.remove(*[1,2])

 


查询:

g1 = models.Girl.objects.get(id=1) # SQL
g1.b.all()    # SQL
g1.b.filter().count()

b1 = models.Boy.objects.get(id=1)
b1.girl_set.all()

models.Girl.objects.all().values('id','name', 'b__username')
models.Boy.objects.all().values('id','username', 'girl__name')

更新:


ORM:
python操作数据库模块:
MySQLdb
pymysql

原生SQL
# from django.db import connection
# cursor = connection.cursor()
# cursor.execute("""SELECT * from tb where name = %s""", ['Lennon'])
# row = cursor.fetchone()

4、中间件

中间件介绍:

中间件顾名思义,是介于request与response处理之间的一道处理过程,相对比较轻量级,并且在全局上改变django的输入与输出。因为改变的是全局,所以需要谨慎实用,用不好会影响到性能。 
每个中间件都会负责一个功能,例如,AuthenticationMiddleware,与sessions处理相关。

激活中间件:

 

需要在settings.py配置文件中,配置MIDDLEWARE_CLASSES:

MIDDLEWARE_CLASSES = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
    # 'django.middleware.cache.FetchFromCacheMiddleware',
]

当然你也可以不试用任何的中间件,这个可以设置为空。

中间件顺序

一般我们我们从浏览器发出一个请求 Request,得到一个响应后的内容 HttpResponse ,这个请求传递到 Django的过程如下,process request 和 process response的执行顺序正好相反,当有请求过来的时候,默认从上倒下执行!然后在返回的时候从下面在返回回去,如下图所示。

Django 补充models操作,中间件, 缓存,信号,分页

也就是说,每一个请求都是先通过中间件中的 process_request 函数,这个函数返回 None 或者 HttpResponse 对象,如果返回前者,继续处理其它中间件,如果返回一个 HttpResponse,就处理中止,返回到网页上。 
中间件不用继承自任何类(可以继承 object ),

自定义一个中间件:

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

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

process_exception 这个方法只有在出现错误的时候才会触发

先写一个自定义中间件,然后在看他的原理和源码,首先把自定义的中间件加到settings文件中:

Django 补充models操作,中间件, 缓存,信号,分页

 

写类:
process_request
process_view
process_exception
process_response

 

 

from django.shortcuts import HttpResponse
from django.utils import deprecation
class M1(deprecation.MiddlewareMixin):
def process_request(self, request):
print('M1.process_request')
# return HttpResponse('滚')

def process_view(self, request, callback, callback_args, callback_kwargs):
print('m1.process_view')

def process_exception(self, request, exception):
print('m1.process_exception')

def process_response(self, request, response):
print('M1.process_response')
return response

def process_template_response(self,request,response):
print('template')


class M2(deprecation.MiddlewareMixin):
def process_request(self, request):
print('M2.process_request')
def process_view(self, request, callback, callback_args, callback_kwargs):
print('m2.process_view')
def process_exception(self, request, exception):
print('m2.process_exception')

def process_response(self, request, response):
print('M2.process_response')
return response

 

django 1.10中自定义中间建需要制定继承的deprecation.MiddlewareMixin类,否则会出现如下报错

mw_instance = middleware(handler)
TypeError: object() takes no parameters


1.10配置文件:
MIDDLEWARE =

MIDDLEWARE = [
    'md.mymiddle.M1',
    'md.mymiddle.M2',
    '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',
]

测试使用url和views

 url(r'^md/',views.md),
def md(request):
    return HttpResponse('ok')

 

查看输出结果:

M1.process_request
M2.process_request
m1.process_view
m2.process_view
M2.process_response
M1.process_response

5 Django的Request/Response处理流程的分析

一、 处理过程的核心概念

如下图所示django的总览图,整体上把握以下django的组成

Django 补充models操作,中间件, 缓存,信号,分页

 

核心在于中间件middleware,django所有的请求、返回都由中间件来完成。

中间件,就是处理HTTP的request和response的,类似插件,比如有Request中间件、view中间件、response中间件、exception中间件等,Middleware都需要在 “project/settings.py” 中 MIDDLEWARE_CLASSES 的定义。大致的程序流程图如下所示:

Django 补充models操作,中间件, 缓存,信号,分页

Django 补充models操作,中间件, 缓存,信号,分页Django 补充models操作,中间件, 缓存,信号,分页

首先,Middleware都需要在 “project/settings.py” 中 MIDDLEWARE_CLASSES 的定义, 一个HTTP请求,将被这里指定的中间件从头到尾处理一遍,暂且称这些需要挨个处理的中间件为处理链,如果链中某个处理器处理后没有返回response,就把请求传递给下一个处理器;如果链中某个处理器返回了response,直接跳出处理链由response中间件处理后返回给客户端,可以称之为短路处理。

上面的两张流程图可以大致描述Django处理request的流程,按照流程图2的标注,可以分为以下几个步骤:

1. 用户通过浏览器请求一个页面

2. 请求到达Request Middlewares,中间件对request做一些预处理或者直接response请求

3. URLConf通过urls.py文件和请求的URL找到相应的View

4. View Middlewares被访问,它同样可以对request做一些处理或者直接返回response

5. 调用View中的函数

6. View中的方法可以选择性的通过Models访问底层的数据

7. 所有的Model-to-DB的交互都是通过manager完成的

8. 如果需要,Views可以使用一个特殊的Context

9. Context被传给Template用来生成页面

a. Template使用Filters和Tags去渲染输出

b. 输出被返回到View

c. HTTPResponse被发送到Response Middlewares

d. 任何Response Middlewares都可以丰富response或者返回一个完全不同的response

e. Response返回到浏览器,呈现给用户

上述流程中最主要的几个部分分别是:Middleware(中间件,包括request, view, exception, response),URLConf(url映射关系),Template(模板系统),下面一一介绍一下。

1、Middleware(中间件)

Middleware并不是Django所独有的东西,在其他的Web框架中也有这种概念。在Django中,Middleware可以渗入处理流程的四个阶段:request,view,response和exception,相应的,在每个Middleware类中都有rocess_request,process_view, process_response 和 process_exception这四个方法。你可以定义其中任意一个活多个方法,这取决于你希望该Middleware作用于哪个处理阶段。每个方法都可以直接返回response对象。

Middleware是在Django BaseHandler的load_middleware方法执行时加载的,加载之后会建立四个列表作为处理器的实例变量:

_request_middleware:process_request方法的列表

_view_middleware:process_view方法的列表

_response_middleware:process_response方法的列表

_exception_middleware:process_exception方法的列表

 Django的中间件是在其配置文件(settings.py)的MIDDLEWARE_CLASSES元组中定义的。在MIDDLEWARE_CLASSES中,中间件组件用字符串表示:指向中间件类名的完整Python路径。

Django项目的安装并不强制要求任何中间件,如果你愿意,MIDDLEWARE_CLASSES可以为空。中间件出现的顺序非常重要:在request和view的处理阶段,Django按照MIDDLEWARE_CLASSES中出现的顺序来应用中间件,而在response和exception异常处理阶段,Django则按逆序来调用它们。也就是说,Django将MIDDLEWARE_CLASSES视为view函数外层的顺序包装子:在request阶段按顺序从上到下穿过,而在response则反过来。以下两张图可以更好地帮助你理解:

Django 补充models操作,中间件, 缓存,信号,分页

Django 补充models操作,中间件, 缓存,信号,分页

2、URLConf(URL映射)

如果处理request的中间件都没有直接返回response,那么Django会去解析用户请求的URL。URLconf就是Django所支撑网站的目录。它的本质是URL模式以及要为该URL模式调用的视图函数之间的映射表。通过这种方式可以告诉Django,对于这个URL调用这段代码,对于那个URL调用那段代码。具体的,在Django项目的配置文件中有ROOT_URLCONF常量,这个常量加上根目录”/”,作为参数来创建django.core.urlresolvers.RegexURLResolver的实例,然后通过它的resolve方法解析用户请求的URL,找到第一个匹配的view。

原版本: 如果process_request中有return, 则所有的process_response执行一遍

6、缓存

由于Django是动态网站,所有每次请求均会去数据进行相应的操作,当程序访问量大时,耗时必然会更加明显,最简单解决方式是使用:缓存,缓存将一个某个views的返回值保存至内存或者memcache中,5分钟内再有人来访问时,则不再去执行view中的操作,而是直接从内存或者Redis中之前缓存的内容拿到,并返回。

举个例子来说:如果访问量比较大的时候,有很多相同的操作比如:有时候请求的数据比如访问同一条数据,或者同一个页面的时候,其实是没必要的。

Django中提供了6种缓存方式:

  • 开发调试
  • 内存
  • 文件
  • 数据库
  • Memcache缓存(python-memcached模块)
  • Memcache缓存(pylibmc模块)

1、配置

a、开发调试

# 此为开始调试用,实际内部不做任何操作
    # 配置:
        CACHES = {
            'default': {
                'BACKEND': 'django.core.cache.backends.dummy.DummyCache',     # 引擎
                'TIMEOUT': 300,                                               # 缓存超时时间(默认300,None表示永不过期,0表示立即过期)
                'OPTIONS':{
                    'MAX_ENTRIES': 300,                                       # 最大缓存个数(默认300)
                    'CULL_FREQUENCY': 3,                                      # 缓存到达最大个数之后,剔除缓存个数的比例,即:1/CULL_FREQUENCY(默认3)
                },
                'KEY_PREFIX': '',                                             # 缓存key的前缀(默认空)
                'VERSION': 1,                                                 # 缓存key的版本(默认1)
                'KEY_FUNCTION' 函数名                                          # 生成key的函数(默认函数会生成为:【前缀:版本:key】)
            }
        }


    # 自定义key
    def default_key_func(key, key_prefix, version):
        """
        Default function to generate keys.

        Constructs the key used by all other methods. By default it prepends
        the `key_prefix'. KEY_FUNCTION can be used to specify an alternate
        function with custom key making behavior.
        """
        return '%s:%s:%s' % (key_prefix, version, key)

    def get_key_func(key_func):
        """
        Function to decide which key function to use.

        Defaults to ``default_key_func``.
        """
        if key_func is not None:
            if callable(key_func):
                return key_func
            else:
                return import_string(key_func)
        return default_key_func
View Code

相关文章:

  • 2021-08-04
  • 2021-12-21
  • 2021-08-20
  • 2021-11-16
  • 2021-07-04
  • 2022-12-23
  • 2021-06-14
猜你喜欢
  • 2021-07-01
  • 2021-09-24
  • 2022-01-08
  • 2021-08-08
  • 2021-08-11
  • 2021-09-06
  • 2022-12-23
相关资源
相似解决方案