Python Automation Development Learning 22-Django

session

The previous section has already talked about the use of cookies for user authentication, but
the disadvantages of cookies
: sensitive information is not suitable to be placed in cookies, and sensitive information can only be placed on the server side.
Advantages: store some user data scattered on each client, Relieve the pressure on the server
. Cookie is a key-value pair saved on the user's browser, and Session is a key-value pair saved on the server.
Session relies on Cookie, Cookie saves a random string, and obtains the content of the server-side Session with this random string.
Use Session to optimize user login : After the user logs in, a random string is generated and sent to the client through a cookie to save. The server side maintains a dictionary, the key of the dictionary is this randomly generated string, and the value of the dictionary is another dictionary, which stores the sensitive information of various users on the server side.
Django's sessiong is saved in the database by default, so to use the session, you need to execute two commands to generate the database first:

python manage.py makemigrations
python manage.py migrate

Even if you do not write any table, some tables will be generated by default, among which the django_session table stores session information.

operate

The key-value pairs are stored in the session, so the operation is the same as the dictionary. Just write a login page and use the following handler to operate:

USER_INFO = {
    'test': {'pass': "test123"},
    'user': {'pass': "user123"},
}

def login(request):
    if request.method == "GET":
        return render(request, 'login.html')
    elif request.method == 'POST':
        user = request.POST.get('user')
        pwd = request.POST.get('pwd')
        user_obj = USER_INFO.get(user)
        if user_obj and user_obj.get('pass') == pwd:
            # 1.生成随机字符串
            # 2.写到用户浏览器Cookie
            # 3.把随机字符串作为key保存到session中
            # 4.设置对应的value
            # 理论上是要完成上面4个步骤
            # 但是都封装好了,用的时候只需要1步,就能完成上面的操作,下面是设置session的值
            request.session['username'] = user
            request.session['is_login'] = True
            return redirect('/welcome/')
        else:
            return render(request, 'login.html')

def welcome(request):
    # 获取session的值
    if request.session.get('is_login'):
        return HttpResponse('Welcome %s' % request.session['username'])
    else:
        return HttpResponse('登录失败')

log in page:

<form action="/login/" method="POST">
    <p><input type="text" name="user" placeholder="用户名"></p>
    <p><input type="password" name="pwd" placeholder="密码"></p>
    <p><input type="submit" value="登录"></p>
</form>

The operation of setting data and the operation of obtaining data are used above. For other methods of operation, see the contents organized below.
Get, set, delete data in the session:

  • request.session['k1']: Get the value, if the key does not exist, an error will be reported
  • request.session.get('k1',None): Get the value, if the key does not exist, get the default value. The default value is None by default
  • request.session['k1'] = 123:Settings
  • request.session.setdefault('k1',123): Set the default value, that is, if the key has a value, it will not change, and if there is no value, it will be set to the value of the second parameter
  • del request.session['k1']: delete value

Operations on all key, value, key-value pairs:

  1. request.session.keys()
  2. request.session.values()
  3. request.session.items()
  4. request.session.iterkeys()
  5. request.session.itervalues()
  6. request.session.iteritems()

The difference between iterkeys and keys, iterkeys returns an iterator, while keys returns a list.
other:

  • request.session.session_key: Get the random string of the current user. But generally this is not needed, but it can be obtained
  • request.session.clear_expired(): Delete all data whose session expiration date is less than the current date. For expired sessions, the database does not have an automatic clearing mechanism. But there is a cache system
  • request.session.exists("session_key"): Checks if the random string as parameter exists in the database. It is generally not used, because this judgment is already included when the value is obtained, and None will be returned.
  • request.session.delete("session_key"): delete all data of the Session of the parameter
  • request.session.clear(): Delete all session data of the current user. Compared with the delete method, delete needs to provide session_key. The clear method will first get the key of the current user, and then delete

request.session.set_expiry(value): Set the timeout time

  • If value is an integer, the session will expire after some number of seconds.
  • If value is a datatime or timedelta, the session will expire after this time.
  • If the value is 0, the user closes the browser session will be invalid.
  • If value is None, the session will rely on the global session invalidation policy.

The following content is in the file Lib/site-packages/django/conf/global_settings.py, which is the default configuration. To modify, just set a value in our settings.py:

############
# SESSIONS #
############

# Cache to store session data if using the cache session backend.
SESSION_CACHE_ALIAS = 'default'
# Cookie name. This can be whatever you want.
SESSION_COOKIE_NAME = 'sessionid'  # Session的cookie保存在浏览器上时的key,即:sessionid=随机字符串
# Age of cookie, in seconds (default: 2 weeks).
SESSION_COOKIE_AGE = 60 * 60 * 24 * 7 * 2  # Session的cookie失效日期,这里默认的是2周
# A string like "example.com", or None for standard domain cookie.
SESSION_COOKIE_DOMAIN = None  # Session的cookie保存的域名
# Whether the session cookie should be secure (https:// only).
SESSION_COOKIE_SECURE = False  # 是否Session的cookie只支持http传输
# The path of the session cookie.
SESSION_COOKIE_PATH = '/'  # Session的cookie保存的路径
# Whether to use the non-RFC standard httpOnly flag (IE, FF3+, others)
SESSION_COOKIE_HTTPONLY = True  # 是否Session的cookie只支持http传输
# Whether to save the session data on every request.
SESSION_SAVE_EVERY_REQUEST = False  # 是否每次请求都保存Session,默认修改之后才保存
# Whether a user's session cookie expires when the Web browser is closed.
SESSION_EXPIRE_AT_BROWSER_CLOSE = False  # 是否关闭浏览器使得Session过期
# The module to store session data
SESSION_ENGINE = 'django.contrib.sessions.backends.db'  # 默认引擎
# Directory to store session files if using the file session module. If None,
# the backend will use a sensible default.
SESSION_FILE_PATH = None  # 缓存文件路径,如果为None,则使用tempfile模块获取一个临时地址
# class to serialize session data
SESSION_SERIALIZER = 'django.contrib.sessions.serializers.JSONSerializer'

CSRF (Cross Site Request Forgery)

After the client initiates a GET request for the first time, it not only returns the page, but also returns a string of encrypted strings. When the client submits the data again, it needs to submit the string received before, so that the CSRF on the server side will verify the string and confirm that the received data is submitted by the client that initiated the request before.
There is no hidden danger of CSRF. If there is no CSRF, the data submitted by the normal client is submitted to the currently visited website. But it can also be submitted to other sites (you can submit to anywhere). Although you can submit it in the past, in this way, you do not have the encrypted string given to you by the target website, so after opening CSRF, this part of the request is directly intercepted.

Enable CSRF

Django implements the function of preventing cross-site request forgery for users, which is done through the middleware django.middleware.csrf.CsrfViewMiddleware. The anti-cross-site request forgery function in django is divided into global and local.
Globally , the MIDDLEWARE (middleware) in the settings.py file is a list, and the following line was commented out before:

'django.middleware.csrf.CsrfViewMiddleware',

Local
import module: from django.views.decorators.csrf import csrf_exempt,csrf_protect
@csrf_exempt: Forces anti-cross-site request forgery for the current function, even if no global middleware is set in settings.
@csrf_protect: Cancel the anti-cross-site request forgery function of the current function, even if the global middleware is set in the settings.

Application-Form submission

Where is the string obtained from the first request, and how to add the obtained string when submitting the form to pass CSRF verification. Make a simple login page, as shown in the previous section, then go to the settings.py file to open the CSRF that has been commented out before, and submit it as follows:

<form action="/login/" method="POST">
    {# 加上下面的标签就可以了 #}
    {% csrf_token %}
    <p><input type="text" name="username" placeholder="用户名"></p>
    <p><input type="password" name="password" placeholder="密码"></p>
    <p><input type="submit" value="登录"></p>
</form>

If the form does not have a csrf_token, a 403 error will be returned. Looking at the source code in the client form tag here, you can find that the system has generated a hidden input tag for us.

<input name="csrfmiddlewaretoken" type="hidden" value="I9pZVK6UYWgHHPfUQxju79pWu65xOrb793mpWXON1n4HgeTGzheJ78HHQBgu6cB8">

Application-Ajax submission

To submit by Ajax, you need to get the csrf string first. After the client receives the string from the server, it is saved in the cookie, so you can get it in the cookie. When submitting, you should also bring this csrf string and add a request header: headers: {'X-CSRFtoken': csrftoken},.
In the original page, add the button for Ajax request and bind the event. If the verification fails to reload the page, if the verification passes, use the location.hrefpage jump:

<body>
<form action="/login/" method="POST">
    {% csrf_token %}
    <p><input type="text" name="user" placeholder="用户名"></p>
    <p><input type="password" name="pwd" placeholder="密码"></p>
    <p>
        <input type="submit" value="登录">
        <input id="btn" type="button" value="Ajax提交">
    </p>
</form>
<script src="/static/js/jquery-1.12.4.js"></script>
<script src="/static/js/jquery.cookie.js"></script>
<script>
    $(function () {
        $('#btn').click(function () {
            var csrftoken = $.cookie('csrftoken');
            var user = $("input[name='user']").val();
            var pwd = $("input[name='pwd']").val();
            $.ajax({
                url: '/login/',
                type: 'POST',
                data: {'user': user, 'pwd': pwd, 'ajax': true},
                headers: {'X-CSRFtoken': csrftoken},
                success: function (arg) {
                    if(arg === 'OK'){
                        location.href = '/welcome/'
                    }else{
                        location.reload()
                    }
                }
            })
        })
    })
</script>
</body>

The handler function is also added on the basis of the original. is_ajax = request.POST.get('ajax')Determine whether it is a request submitted by ajax. Finally, different results are returned when returning, and everything else remains unchanged:

def login(request):
    if request.method == "GET":
        return render(request, 'login.html')
    elif request.method == 'POST':
        user = request.POST.get('user')
        pwd = request.POST.get('pwd')
        is_ajax = request.POST.get('ajax')
        user_obj = USER_INFO.get(user)
        if user_obj and user_obj.get('pass') == pwd:
            # 1.生成随机字符串
            # 2.写到用户浏览器Cookie
            # 3.把随机字符串作为key保存到session中
            # 4.设置对应的value
            # 但是只需要一步,就能完成上面的操作,下面是设置session的值
            request.session['username'] = user
            request.session['is_login'] = True
            print(request.session)
            return HttpResponse('OK') if is_ajax else redirect('/welcome/')
        else:
            print('error')
            return HttpResponse('error') if is_ajax else render(request, 'login.html')

Set the csrf of ajax uniformly. If there are multiple ajax requests in the page, you can set it uniformly. Or, for example, in the previous exercise, the ajax request without csrf has been written, and now don't go to it to change it, use the following method to add it uniformly. That is, before ajax is sent, set the request header plus the key X-CSRFtoken and set the value:

<script>
    $(function () {
        $.ajaxSetup({
            beforeSend: function (xhr, settings) {
                // xhr 就是 XHLHttpRequest 是一个对象
                xhr.setRequestHeader('X-CSRFtoken', $.cookie('csrftoken'))  // 设置请求头
            }
        });
        $('#btn').click(function () {
            // var csrftoken = $.cookie('csrftoken');
            var user = $("input[name='user']").val();
            var pwd = $("input[name='pwd']").val();
            $.ajax({
                url: '/login/',
                type: 'POST',
                data: {'user': user, 'pwd': pwd, 'ajax': true},
                // headers: {'X-CSRFtoken': csrftoken},
                success: function (arg) {
                    if(arg === 'OK'){
                        location.href = '/welcome/'
                    }else{
                        location.reload()
                    }
                }
            })
        })
    })
</script>

The above code needs to be optimized again. Only POST requests need to add csrf, and GET requests do not need to be added. But in the above code, csrf will be added in front of all ajax requests in the request header, and another judgment must be made here. In addition to POST and GET, there are several other requests, and make judgments together:

<script>
    function csrfSafeMethod(method) {
        // 下面的这几类HTTP请求是不需要加CSRF验证的,这个是官网的一个例子的用法
        return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
    }
    $(function () {
        $.ajaxSetup({
            beforeSend: function (xhr, settings) {
                // xhr 就是 XHLHttpRequest 是一个对象
                // settings 里就是下面的$.ajax({})大括号里的内容,这里要获取type检查是否需要加csrf
                if (!csrfSafeMethod(settings.type) && !this.crossDomain){
                    // 满足上面的条件才需要设置请求头
                    xhr.setRequestHeader('X-CSRFtoken', $.cookie('csrftoken'))  // 设置请求头
                }

            }
        });
        $('#btn').click(function () {
            // var csrftoken = $.cookie('csrftoken');
            var user = $("input[name='user']").val();
            var pwd = $("input[name='pwd']").val();
            $.ajax({
                url: '/login/',
                type: 'POST',
                data: {'user': user, 'pwd': pwd, 'ajax': true},
                // headers: {'X-CSRFtoken': csrftoken},
                success: function (arg) {
                    if(arg === 'OK'){
                        location.href = '/welcome/'
                    }else{
                        location.reload()
                    }
                }
            })
        })
    })
</script>

middleware

In the settings.py file, there is a list of various middleware, including the csrf mentioned above. Here is the content of the middleware in the original settings.py file:

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',
]

The user initiates a request, and before the request reaches the Views, the middleware must be written through this. These middleware are a class, and after that, the method in these middleware classes, the process_request method, is called. The return of the request must first pass through these middleware, call the process_response method, and then send it to the user.
Other names In other web frameworks, there are also middleware, but the names may be called: Pipeline, HttpHandler.

custom middleware

Take the middleware of csrf as an example, the string quoted in the code is: 'django.middleware.csrf.CsrfViewMiddleware'. This is the path and class name.
This file and class can be found in python modules. There is a class class CsrfViewMiddleware(MiddlewareMixin):in the file \Lib\site-packages\django\middleware\csrf.py, which has process_request method and process_response method. And you can see that this class inherits the MiddlewareMixin class. Looking at the parent class, you can see that the above two methods are called in this class.
To write your own middleware, you need to define a class that inherits MiddlewareMixin. And write the process_request method and the process_response method in the class.
Create a Middle folder under the project to store the custom middleware, and create the m1.py file:

from django.utils.deprecation import MiddlewareMixin

class Row1(MiddlewareMixin):
    def process_request(self, request):
        print('ROW1_reuquest')

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

class Row2(MiddlewareMixin):
    def process_request(self, request):
        print('ROW2_reuquest')

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

The two classes written above are two middleware. Then go to setting.py and register your middleware:

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',
    'Middle.m1.Row1',
    'Middle.m1.Row2',
]

Now visit your previous page again, you can see the middleware print information, and you can see the order of triggering:

ROW1_reuquest
ROW2_reuquest
[11/Apr/2018 11:24:04] "GET /login/ HTTP/1.1" 200 492
ROW2_response
ROW1_response

The request method is triggered first, and the middleware written in the front is triggered first. Then there is the GET request. Finally trigger the response method.
Application scenarios of middleware: Through middleware, a unified operation can be performed on all requests, such as blacklist filtering.
The following methods can be defined in the middleware:

  • process_request(self, request) : process the request first
  • process_view(self, request, callback, callback_args, callback_kwargs) : Execute after process_request is all executed, or from top to bottom
  • process_template_response(self, request, response) : If there is a render method in the returned object of views, it will be executed
  • process_exception(self, request, exception) : Triggered when an exception occurs in views. exception is the exception information
  • process_response(self, request, response) : After the result is returned, it will be processed before the client receives the response

There are only 2 commonly used ones, let’s learn about the others

cache

Since Django is a dynamic website, each request will go to the data for corresponding operations. When the program has a large number of visits, the time-consuming will inevitably become more obvious. The easiest solution is to use the cache. Cache is to save the return value of a view to memory or memcache. When someone accesses it again within 5 minutes (default setting), it will no longer execute the function in the views, but directly from memory or Redis. The content is taken and returned.
Django provides 6 caching methods:

  • Development and debugging
  • RAM
  • document
  • database
  • Memcache cache (python-memcached module)
  • Memcache cache (pylibmc module)

configure

Development and debugging and the default configuration
do not actually do anything internally, but are used for debugging. Only the first engine must be set, the others have default configuration (the above are also set by default), if you don't write it, use the default settings, or write the settings you want to modify. The configuration of other caching methods is the same, just change the engine and add a 'LOCATION' to store the cache:

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

The default 'KEY_FUNCTION' is the default_key_func function in the Lib\site-packages\django\core\cache\backends\base.py file, which generates a string containing the three variables key_prefix, version, and key. Here we can use our own written functions to generate the styles we want:

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

    Construct the key used by all other methods. By default, prepend
    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)

RAM

# 此缓存将内容保存至内存的变量中
# 配置:
CACHES = {
    'default': {
        'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
        'LOCATION': 'unique-snowflake',  # 这个必须是全局唯一的变量名,实际就是在内存中维护一个字典,这个是变量名
    }
}

document

# 此缓存将内容保存至文件
# 配置:
CACHES = {
    'default': {
        'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache',
        'LOCATION': '/var/tmp/django_cache',  # 缓存文件的路径
    }
}

database

# 此缓存将内容保存至数据库
# 配置:
CACHES = {
    'default': {
        'BACKEND': 'django.core.cache.backends.db.DatabaseCache',
        'LOCATION': 'my_cache_table',  # 数据库表,这里是表名,使用前先要创建表,命令在下面
    }
}
# 注意:使用前先执行创建表命令 python manage.py createcachetable

Memcache cache (python-memcached module)

# 此缓存使用python-memcached模块连接memcache
CACHES = {
    'default': {
        'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
        'LOCATION': '127.0.0.1:11211',  # ip地址和端口
    }
}
# 或者是连接本地文件
CACHES = {
    'default': {
        'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
        'LOCATION': 'unix:/tmp/memcached.sock',
    }
}
# 或者是使用分布式的memcache
CACHES = {
    'default': {
        'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
        'LOCATION': [
            '172.19.26.240:11211',
            '172.19.26.242:11211',
        ]
    }
}
# 或者是使用分布式的memcache,还可以带权重(权重是memcache做的)
CACHES = {
    'default': {
        'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
        'LOCATION': [
            ('172.19.26.240:11211', 2),
            ('172.19.26.242:11211', 3),
        ]
    }
}

The Memcache cache (pylibmc module)
is similar to the above, but a different python module is used, so the engine needs to be changed.

# 此缓存使用pylibmc模块连接memcache
CACHES = {
    'default': {
        'BACKEND': 'django.core.cache.backends.memcached.PyLibMCCache',
        'LOCATION': '127.0.0.1:11211',
    }
}
CACHES = {
    'default': {
        'BACKEND': 'django.core.cache.backends.memcached.PyLibMCCache',
        'LOCATION': '/tmp/memcached.sock',
    }
}
CACHES = {
    'default': {
        'BACKEND': 'django.core.cache.backends.memcached.PyLibMCCache',
        'LOCATION': [
            '172.19.26.240:11211',
            '172.19.26.242:11211',
        ]
    }
}
# 权重也是有的

application

Prepare the test environment for testing
in the form of files. Create a cache folder under the project to store the cache files. The configuration is as follows:

CACHES = {
    'default': {
        'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache',
        'LOCATION': os.path.join(BASE_DIR, 'cache'),  # 缓存文件的路径
    }
}

Then write a handler that displays the current timestamp:

def cache(request):
    import time
    ctime = time.time()
    return render(request, 'cache.html', {'ctime': ctime})

The page just displays the timestamp:

<body>
<h1>{{ ctime }}</h1>
<h1>{{ ctime }}</h1>
</body>

Now visiting the page will see a timestamp, and refreshing the page timestamp will also refresh, indicating that there is no cache. Because we just configured the cache above, it has not been applied yet.

The site-wide application cache
is too rough, and there are more detailed settings below.
To apply caching to all requests, this function is suitable for middleware. In the middleware, two middlewares need to be written to
check the cache . When a user request is received, the cache will be searched first, and if it hits, the cached content will be returned directly. This middleware should be placed in a later position, and only after passing a series of validated middleware can data be returned to the user.
When writing to the cache , when returning the content that was not cached before to the user, the content needs to be written to the cache, then the cache will be available next time. This middleware should be placed in the front position, and after processing through a series of other middleware, the final returned content is cached.

MIDDLEWARE = [
    'django.middleware.cache.UpdateCacheMiddleware',
    # 其他中间件...
    'django.middleware.cache.FetchFromCacheMiddleware',
]

View application cache 1: add a decorator before the handler function

from django.views.decorators.cache import cache_page
@cache_page(10)  # timeout必填,单位秒
def func(request):
    pass

View Application Cache 2: Modify urls.py

from django.views.decorators.cache import cache_page
urlpatterns = [
    path('admin/', admin.site.urls),
    path('cache/', cache_page(5)(views.cache)),
]

Partial view caching:
It is declared in the template language, which content in the page is to be cached

<body>
{#要应用缓存,先load一下cache#}
{% load cache %}
<h1>{{ ctime }}</h1>
{#然后在需要应用缓存的内容的前后加上标签#}
{#下面的c1是自定义的key,这里缓存的值的key貌似无法根据配置自动生成#}
{% cache 5 c1 %}
<h1>{{ ctime }}</h1>
{% endcache %}
</body>

First load the cache, then wrap it with tags before and after the cached content is to be applied. Here you need to define the timeout time and key.
There are still many local application scenarios. Only the content that does not change frequently in the page is cached, and the content that changes frequently is not cached.

Signal

"Signal dispatch" is provided in Django for decoupling when the framework performs operations . In layman's terms, when some action occurs, the signal allows a specific sender to alert some receivers.

Django built-in signals

  • Model signals
    • pre_init : triggers automatically before django's modal executes its constructor
    • post_init : automatically triggered after django's modal executes its constructor
    • pre_save : automatically triggered before the modal object of django is saved
    • post_save : automatically triggered after the modal object of django is saved
    • pre_delete : triggers automatically before django's modal object is deleted
    • post_delete : automatically triggered after the modal object of django is deleted
    • m2m_changed : It is automatically triggered before and after the operation of the third table (add, remove, clear) using the m2m field in django's modal
    • class_prepared : When the program starts, the modal class in the registered app is detected, and for each class, it is automatically triggered
  • Management signals
    • pre_migrate : triggers automatically before executing the migrate command
    • post_migrate : After the migrate command is executed, it is automatically triggered
  • Request/response signals
    • request_started : triggers automatically before the request arrives
    • request_finished : automatically triggered after the request ends
    • got_request_exception : Automatically trigger after request exception
  • Test signals
    • setting_changed : Triggered automatically when the configuration file is modified using the test test
    • template_rendered : Triggered automatically when the template is rendered using the test test
  • Database Wrappers
    • connection_created : automatically triggered when a database connection is created

Before using it, import the corresponding module:

from django.db.models.signals import pre_init, post_init
from django.db.models.signals import pre_save, post_save
from django.db.models.signals import pre_delete, post_delete
from django.db.models.signals import m2m_changed
from django.db.models.signals import class_prepared

from django.db.models.signals import pre_migrate, post_migrate

from django.core.signals import request_started
from django.core.signals import request_finished
from django.core.signals import got_request_exception

from django.test.signals import setting_changed
from django.test.signals import template_rendered

from django.db.backends.signals import connection_created

Register function 1
takes the function name as a parameter to complete the registration

# 导入模块
from django.core.signals import request_started

# 准备好要触发的函数
def callback(sender, **kwargs):
    print('callback')
    print(sender, kwargs)

request_started.connect(callback)  # 注册你的函数
# pre_init.connect(callback2)  # 可以注册多个,先注册的先执行

Registration function 2
Adding a decorator to the function can also complete the registration:

# 导入模块
from django.core.signals import request_started
from django.dispatch import receiver

# 准备好要触发的函数,并且加上装饰器
@receiver(request_started)
def callback(sender, **kwargs):
    print('callback')
    print(sender, kwargs)

custom signal

To customize a signal requires 3 steps:

  1. Define the signal: Here, create a separate file (the name is arbitrary, such as sg.py) to store the custom signal
  2. Registration signal: After the definition is complete, just register it. The registration method is the same as registering the built-in signal.
  3. Trigger signal: At the position you want to trigger, execute a send() method. For example, in the following example, the trigger of this signal is added to the processing function

Built-in signals only need to be registered. For custom signals, you need to define the signal before registration. Then go to the location you need and add the send() method of the trigger signal:

# sg.py 里的内容
# 第一步:定义信号
import django.dispatch
pizza_done = django.dispatch.Signal(providing_args=["toppings", "size"])  # 这里要求2个参数

# 第二步:注册信号
def callback(sender, **kwargs):
    print('callback')
    print(sender, kwargs)
pizza_done.connect(callback)

# views.py 里的内容,当然可以是任何地方
# 第三步:触发信号
# 导入信号
from sg import pizza_done
def my_sig(request):
    # 发送信号,第一个参数是发送者,后面是你自定义的函数要求的参数
    pizza_done.send(sender='seven', topping=123, size=456)

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=326290281&siteId=291194637