Use of Django Framework Caching and Paging

Posted by ThatGuyBob on Tue, 17 Sep 2019 14:00:46 +0200

cache

What is caching?

Caching is a kind of media that can read data faster. It also refers to other storage methods that can speed up data reading. Usually used to store temporary data, the common medium is fast memory.

Why use caching?

View rendering has a certain cost. For pages with low frequency changes, caching technology can be considered to reduce the actual rendering times.

case analysis

from django.shortcuts import render

def index(request):
    # Rendering with extremely high time complexity
    book_list = Book.objects.all()  #-> The assumption here is that it takes 2s.
    return render(request, 'index.html', locals())

Optimization thought

given a URL, try finding that page in the cache
if the page is in the cache:
    return the cached page
else:
    generate the page
    save the generated page in the cache (for next time)
    return the generated page

Using caching scenarios:

1. Blog List Page

2. Details page of e-commerce commodities

3. Cache navigation and footer

Setting up caching in Django

There are many caching methods in Django, which need to be configured in settings.py if needed.

1. Database caching

Django can store its cached data in your database

CACHES = {
    'default': {
        'BACKEND': 'django.core.cache.backends.db.DatabaseCache',
        'LOCATION': 'my_cache_table',
    }
}

Create cached tables

python manage.py createcachetable

2. File system caching

CACHES = {
    'default': {
        'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache',
        'LOCATION': '/var/tmp/django_cache',#This is the path of the folder.
        #'LOCATION': 'c:\test\cache',#Examples under windows
    }
}

3. Local memory cache

CACHES = {
    'default': {
        'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
        'LOCATION': 'unique-snowflake'
    }
}

Using caching in Django

  • Use in View View
  • Use in routing URL s
  • Use in templates

Using cache in View view View

from django.views.decorators.cache import cache_page

@cache_page(30)  -> Company s
def my_view(request):
    ...

Use in routing

from django.views.decorators.cache import cache_page

urlpatterns = [
    path('foo/', cache_page(60)(my_view)),
]

Use in templates

{% load cache %}
{% cache 500 sidebar request.user.username %}
    .. sidebar for logged in user ..
{% endcache %}

Caching in Browsers

Browser Cache Classification:

Strong cache

Instead of sending requests to the server, read resources directly from the cache

1,Expires

The cache expiration time, used to specify the expiration time of resources, is the specific time point on the server side.

Expires=max-age + request time

Expires is a product of HTTP/1 and is limited by local time. If you change local time, it may cause cache invalidation.

2, Cache-Control

In HTTP/1.1, Cache-Control is mainly used to control web caching. For example, when Cache-Control:max-age=120 represents 120 seconds after the request creation time, the cache fails.

Horizontal comparison Expires VS Cache-Control

Negotiation cache

** Negotiating caching is the process of forcing the cache to fail, and the browser initiates a request to the server with the cache identifier. The server decides whether to use the cache or not according to the cache identifier.

1, Last-Modified and If-Modified-Since

On the first visit, the server returns

Last-Modified: Fri, 22 Jul 2016 01:47:00 GMT

The browser carries the header If-Modified-Since on its next request, which is Last-Modified

After receiving the request, the server returns 304 if the resource has not changed, otherwise returns 200 and returns the new resource to the browser.

Disadvantage: It can only be accurate to seconds. It is prone to multiple modifications in a single second and can not be detected.

2. ETag and If-None-Match

Etag is a unique identifier (generated by the server) that returns the current resource file when the server responds to the request. As long as the resource changes, the Etag will be regenerated.

Ibid.

Lateral Contrast Last-Modified VS ETag

Middleware

  • Middleware is a hook framework for Django request/response processing. It is a lightweight, low-level "plug-in" system for changing Django's input or output globally.

  • Each middleware component is responsible for doing some specific functions. For example, Django contains a middleware component, Authentication Middleware, which uses sessions to associate users with requests.

  • His documentation explains how middleware works, how to activate middleware, and how to write your own middleware. Django has some built-in middleware that you can use directly. They are recorded in build-in middleware reference.

  • Middleware class:

    • The middleware class must inherit from the django. utils. deprecation. Middleware Mixin class
    • The middleware class must implement one or more of the following five methods:
      • def process_request(self, request): Called before routing, on each request, returns a None or HttpResponse object
      • def process_view(self, request, callback, callback_args, callback_kwargs): Called before the view is invoked, invoked on each request, and returned to the None or HttpResponse object
      • def process_response(self, request, response): All responses are called before they are returned to the browser, on each request, and back to the HttpResponse object
      • def process_exception(self, request, exception): Called when an exception is thrown during processing, returning an HttpResponse object
      • def process_template_response(self, request, response): Called just after the view is executed, on each request, returns the response object that implements the render method
    • Note: When returning None, most methods in middleware ignore the current operation and enter the next event. When returning the HttpResponse object, they end the request and return it directly to the client.
  • Write middleware classes:

# file : middleware/mymiddleware.py
from django.http import HttpResponse, Http404
from django.utils.deprecation import MiddlewareMixin

class MyMiddleWare(MiddlewareMixin):
    def process_request(self, request):
        print("Middleware Method process_request Be called")

    def process_view(self, request, callback, callback_args, callback_kwargs):
        print("Middleware Method process_view Be called")

    def process_response(self, request, response):
        print("Middleware Method process_response Be called")
        return response

    def process_exception(self, request, exception):
        print("Middleware Method process_exception Be called")

    def process_template_response(self, request, response):
        print("Middleware Method process_template_response Be called")
        return response
  • Registration middleware:
# file : settings.py
MIDDLEWARE = [
    ...
    'middleware.mymiddleware.MyMiddleWare',
]
  • The execution process of Middleware
    -

  • Practice

    • Using middleware to force an IP address to send only five GET requests to / test
    • Tips:
      • Requ.META ['REMOTE_ADDR'] can get the IP address of the remote client
      • request.path_info can get the routing information of GET requests accessed by clients.
    • Answer:
      from django.http import HttpResponse, Http404
      from django.utils.deprecation import MiddlewareMixin
      import re
      class VisitLimit(MiddlewareMixin):
          '''This middleware restricts one IP Address Corresponding Access/user/login The number of times can not be changed more than 10 times,Prohibit use after exceeding'''
          visit_times = {}  # This dictionary is used to record the number of visits to client IP addresses
          def process_request(self, request):
              ip_address = request.META['REMOTE_ADDR']  # Get the IP address
              if not re.match('^/test', request.path_info):
                  return
              times = self.visit_times.get(ip_address, 0)
              print("IP:", ip_address, 'Visited', times, 'second!:', request.path_info)
              self.visit_times[ip_address] = times + 1
              if times < 5:
                  return
      
              return HttpResponse('You've already visited' + str(times) + 'Secondly, you are forbidden.')
      

Cross-Station Request Forgery Protection CSRF

  • Cross-Station Request Forgery Attack

    • Some malicious websites contain links, form buttons, or JavaScript, which use the authentication information of logged-in users in browsers to try to complete certain operations on your website. This is CSRF (Cross-Site Request Forgey).
  • Explain:

  • CSRF middleware and template tags provide easy-to-use protection against forgery of cross-station requests.

  • Effect:

    • Do not allow other forms to be submitted to this Django server
  • Solution:

    1. Cancel csrf validation (not recommended)

      • Delete the middleware of django.middleware.csrf.CsrfViewMiddleware in MIDDLEWARE in settings.py
    2. Verify csrf_token

      You need to add a label to the form 
      {% csrf_token %}
      

paging

  • Pagination means that there is a large amount of data to be displayed on a web page. In order to read conveniently, only part of the data is displayed on each page.
  • Benefits:
    1. Convenient reading
    2. Reduce the amount of data extraction, reduce server pressure.
  • Django provides Paginator class to facilitate paging
  • The Paginator class is located in the django.core.paginator module.

Paginator object

  • Object Construction Method

    • Paginator(object_list, per_page)
    • parameter
      • object_list Requires an Object List of Classified Data
      • Number of data per_page per page
    • Return value:
      • Paging object
  • Paginator attribute

    • count: Total number of objects that need to be categorized
    • num_pages: Total number of pages after paging
    • page_range: Range object from 1, used to record the current face number
    • Number of data per_page per page
  • Paginator method

    • Paginator.page(number)
      • The parameter number is page number information (starting from 1)
      • Returns the page information corresponding to the current number page
      • If the supplied page number does not exist, throw an InvalidPage exception
  • Paginator exception

    • InvalidPage: Thrown when an invalid page number is passed to page()
    • PageNotAnInteger: Thrown when a value that is not an integer is passed to page()
    • EmptyPage: When a valid value is provided to page(), but there is no object on that page, it is thrown

Page object

  • create object
    The page() method of the Paginator object returns the Page object without manual construction.

  • Page object properties

    • object_list: A list of all data objects on the current page
    • number: number of the current page, starting from 1
    • Paginator: Paginator object associated with the current page object
  • Page object method

    • has_next(): If you have the next page return to True
    • has_previous(): If the previous page returns to True
    • has_other_pages(): If you have the previous page or the next page, return to True
    • next_page_number(): Returns the page number of the next page and throws an InvalidPage exception if the next page does not exist.
    • Pre_page_number(): Returns the page number of the previous page and throws an InvalidPage exception if the previous page does not exist.
    • len(): Number of objects returned to the current page
  • Explain:

    • Page objects are iterative objects that can be accessed with the for statement for each object in the current page
  • Reference document https://docs.djangoproject.com/en/1.11/topics/pagination/

  • Paging example:

    • View function
    from django.core.paginator import Paginator
    def book(request):
        bks = models.Book.objects.all()
        paginator = Paginator(bks, 10)
        print('The total number of current objects is:', paginator.count)
        print('The area code range of the current object is:', paginator.page_range)
        print('The total number of pages is:', paginator.num_pages)
        print('Maximum number of pages per page:', paginator.per_page)
    
        cur_page = request.GET.get('page', 1)  # Get the default current page
        page = paginator.page(cur_page)
        return render(request, 'bookstore/book.html', locals())
    
    • Template design
    <html>
    <head>
        <title>Paging display</title>
    </head>
    <body>
    {% for b in page %}
        <div>{{ b.title }}</div>
    {% endfor %}
    
    {# Paging function #}
    {# Previous page functionality #}
    {% if page.has_previous %}
    <a href="{% url 'book' %}?page={{ page.previous_page_number }}">Previous page</a>
    {% else %}
    Previous page
    {% endif %}
    
    {% for p in paginator.page_range %}
        {% if p == page.number %}
            {{ p }}
        {% else %}
            <a href="{% url 'book' %}?page={{ p }}">{{ p }}</a>
        {% endif %}
    {% endfor %}
    
    {#Next page functionality#}
    {% if page.has_next %}
    <a href="{% url 'book' %}?page={{ page.next_page_number }}">next page</a>
    {% else %}
    next page
    {% endif %}
    PageCount: {{ page.len }}
    </body>
    </html>
    

File upload

  • File upload must be submitted for POST

  • When uploading a file in form <form>, it must have enctype="multipart/form-data" before it can contain the file content data.

  • Upload files with <input type="file" name="xxx"> tag in the form

    • The name XXX corresponds to the memory buffer file stream object corresponding to request.FILES['xxx']. Access to uploaded file data via the object returned by request.FILES['xxx']
    • file=request.FILES['xxx'] file binds the file stream object, which can obtain file data through the following information of the file stream object
      file.name filename
      Byte stream data of file.file file
  • Form Writing Method for Uploading Documents

    <!-- file: index/templates/index/upload.html -->
    <html>
    <head>
        <meta charset="utf-8">
        <title>File upload</title>
    </head>
    <body>
        <h3>Upload files</h3>
        <form method="post" action="/upload" enctype="multipart/form-data">
            <input type="file" name="myfile"/><br>
            <input type="submit" value="upload">
        </form>
    </body>
    </html>
    
  • Set a variable MEDIA_ROOT in set.py to record the location of uploaded files

    # file : settings.py
    ...
    MEDIA_ROOT = os.path.join(BASE_DIR, 'static/files')
    
  • Create the static/files folder under the current project folder

    $ mkdir -p static/files
    
  • Adding Routing and Corresponding Processing Functions

    # file urls.py
    urlpatterns = [
        url(r'^admin/', admin.site.urls),
        url(r'^upload', views.upload_view)
    ]
    
  • View Processing Function for Uploading Files

    # file views.py
    from django.http import HttpResponse, Http404
    from django.conf import settings
    import os
    
    def upload_view(request):
        if request.method == 'GET':
            return render(request, 'index/upload.html')
        elif request.method == "POST":
            a_file = request.FILES['myfile']
            print("The name of the uploaded file is:", a_file.name)
    
            filename =os.path.join(settings.MEDIA_ROOT, a_file.name)
            with open(filename, 'wb') as f:
                data = a_file.file.read()
                f.write(data)
                return HttpResponse("receive files:" + a_file.name + "Success")
        raise Http404
    
  • Access address: http://127.0.0.1:8000/static/upload.html

Topics: Django Database Python Windows