django10.md# django 10

  • 上下文处理器
    • debug
    • message
  • 缓存
    • django操作缓存 memcached
    • session 放入memcached

上下文处理器

  • 重点
    • debug 后期开发 查看 代码 数据库查询是否有问题
    • message 前端用户输入内容的错误信息 直接在页面上显示

上下文处理器是可以返回一些数据,在全局模板中都可以使用。比如登录后的用户信息,在很多页面中都需要使用,那么我们可以放在上下文处理器中,就没有必要在每个视图函数中都返回这个对象。

settings.TEMPLATES.OPTIONS.context_processors中,有许多内置的上下文处理器。这些上下文处理器的作用如下:

  1. django.template.context_processors.debug:增加一个debugsql_queries变量。在模板中可以通过他来查看到一些数据库查询。

    现在  settings.py中设置  INTERNAL_IPS = ['127.0.0.1'] 
    
    在页面 上   {{debug}}  或者  {{sql_queries}}
    
    
    首页 True ::::[{'sql': 'SELECT "front_user"."id", "front_user"."username", "front_user"."password", "front_user"."telephone" FROM "front_user"', 'time': '0.001'}]
    
  2. django.template.context_processors.request:增加一个request变量。这个request变量也就是在视图函数的第一个参数。

  3. django.contrib.auth.context_processors.authDjango有内置的用户系统,这个上下文处理器会增加一个user对象。

  4. django.contrib.messages.context_processors.messages:增加一个messages变量。
    level的四个级别 info debug Warnning erro

    如果想让 错误信息直接呈现在页面上    
    views.py  
    	from django.contrib import messages #先引入
    	class LoginView(View):
        def get(self,request):
            return render(request,'login.html')
    
        def post(self,request):
            form = LoginForm(request.POST)
            if form.is_valid():
                username = form.cleaned_data.get('username')
                password = form.cleaned_data.get('password')
                user = User.objects.filter(username=username,password=password).first()
                if user:
                    request.session['user_id'] = user.id #登录成功以后 将这个用户的id存到session
                    return redirect(reverse('index'))
                else:
                    print("用户名或者密码错误")
                    # messages.add_message(request,messages.INFO,"用户名或者密码错误")
                    messages.info(request, "用户名或者密码错误") #因为内置上下文处理器  上面方式效果一样   这是 用户名或者密码错误级别  
                    return redirect(reverse('login'))
                    外边是 用户名  密码 不能少于6位 错误级别  这个最开始是交给 forms.py来做的   
                    所以需要在里边 写一个 方法   
            else:
    		
                # errors = form.errors.get_json_data()
                # #'username': [{'message': '用户名不能少于6位', 'code': 'min_length'}], 'password': [{'message': '密码不能少于6位', 'code': 'min_length'}]}
                # for messages1 in errors.values():
                #     #print(messages1)
                #     #[{'message': '用户名不能少于6位', 'code': 'min_length'}]
                #     #[{'message': '密码不能少于6位', 'code': 'min_length'}]
                #     for messages_dict in messages1:
                #         for key,value in messages_dict.items():
                #             if key == "message":
                #                 print(value) 
                erros = form.get_errors()  #这里调用的是   下面forms.py中的方法  
                for erro in erros:
                    messages.info(request,erro)   
                return redirect(reverse('login'))
                
                
       forms.py    最终我们只想输出  用户名不能少于 6位用户名不能少于6位
       
       		def get_errors(self):
            new_error = []
            errors = self.errors.get_json_data()
            # 'username': [{'message': '用户名不能少于6位', 'code': 'min_length'}], 'password': [{'message': '密码不能少于6位', 'code': 'min_length'}]}
            for messages1 in errors.values():
                # print(messages1)
                # [{'message': '用户名不能少于6位', 'code': 'min_length'}]
                # [{'message': '用户名不能少于6位', 'code': 'min_length'}]
                for messages_dict in messages1:
                    for key, value in messages_dict.items():
                        if key == "message":
                            new_error.append(value)
            return new_error
            
            
       在 login.html 上   
           <ul>
                                {% for message in messages %}
                                    <li>{{ message }}</li>
                                {% endfor %}
    
                            </ul>
    
    
  5. django.template.context_processors.media:在模板中可以读取 MEDIA_URL。比如想要在模板中使用上传的文件,那么这时候就需要使用settings.py中设置的MEDIA_URL来拼接url。示例代码如下:

    1.在 settings.py OPTIONS  中  写入 'django.template.context_processors.media',
    然后制定  	
    	MEDIA_ROOT = os.path.join(BASE_DIR,'medias')
    	MEDIA_URL = '/medias/'
    urls.py 映射 
    	from django.conf.urls.static import static
    from django.conf import settings
    urlpatterns = [
        path('', views.index,name='index'),
    ]+ static(settings.MEDIA_URL,document_root=settings.MEDIA_ROOT)
    
    <img src="{{MEDIA_URL}}aa.png" />
    
    
  6. django.template.context_processors.static:在模板中可以使用STATIC_URL

    1.在 settings.py OPTIONS  中  写入 'django.template.context_processors.static',
    然后制定  	
    	
    urls.py 映射 
    
    <img src="{{STATIC}}aa.png" />
    
  7. django.template.context_processors.csrf:在模板中可以使用csrf_token变量来生成一个csrf token

    如果表单 post请求 在  form标签里边 加入下面两个 两个效果都可以  
    {#        <input type="hidden" name="csrfmiddlewaretoken" value="{{ csrf_token }}">#}
            {% csrf_token %}
    
    如果 不是 表单  
    
    可以在 head 上面 加一个 
    
    
    {% block head %}
        <meta name="csrf-coken" content="{{ csrf_token }}">
    {% endblock %}
    
    
    base页面上  得有  
    
    {% block head %}
    {% endblock %}
    

自定义上下文处理器:

有时候我们想要返回自己的数据。那么这时候我们可以自定义上下文处理器。自定义上下文处理器的步骤如下:

  1. 你可以根据这个上下文处理器是属于哪个app,然后在这个app中创建一个文件专门用来存储上下文处理器。比如context_processors.py。或者是你也可以专门创建一个Python包,用来存储所有的上下文处理器。

  2. 在你定义的上下文处理器文件中,定义一个函数,这个函数只有一个request参数。这个函数中处理完自己的逻辑后,把需要返回给模板的数据,通过字典的形式返回。如果不需要返回任何数据,那么也必须返回一个空的字典。示例代码如下:

  3. 在settings.py下 让 系统识别你写的 context_processors.py

    TEMPLATES = [
        {
            'BACKEND': 'django.template.backends.django.DjangoTemplates',
            'DIRS': [os.path.join(BASE_DIR, 'templates')]
            ,
            'APP_DIRS': True,
            'OPTIONS': {
                'context_processors': [
                    'django.template.context_processors.debug',
                    'django.template.context_processors.request',
                    'django.contrib.auth.context_processors.auth',
                    'django.contrib.messages.context_processors.messages',
                    'front.context_processors.front_user'  #这一步就是让context_processors 生效
                ],
            },
        },
    ]
    
      from .models import User
      def frontuser(request):
       userid = request.session.get("userid") #从session中读取  
       userModel = models.FrontendUser.objects.filter(pk=userid).first()#根据 useid 从User表中查详细信息   
       if userModel:
         return {'frontuser':userModel}
       else:
         return {}
       
    -------------------------
    from .models import User
    
    def front_user(request):
        userid = request.session.get('user_id') #从session中读取user_id
        context = {}
        if userid:
            try:
                user = User.objects.get(pk=userid)
                context['front_user'] = user
            except:
                pass
        return context
    
    
    在 页面上  
    
    	    {% if front_user %}
                 <li><a href="#">欢迎你,{{ front_user.username }}</a></li>
                 <li><a href="#">注销</a></li>
             {% else %}
                 <li><a href="{% url 'login' %}">登录</a></li>
                 <li><a href="{% url 'register' %}">注册</a></li>
             {% endif %}
    

memcached

什么是memcached:

  1. memcached之前是danga的一个项目,最早是为LiveJournal服务的,当初设计师为了加速LiveJournal访问速度而开发的,后来被很多大型项目采用。官网是www.danga.com或者是memcached.org
  2. Memcached是一个高性能的分布式内存对象缓存系统,全世界有不少公司采用这个缓存项目来构建大负载的网站,来分担数据库的压力。Memcached是通过在内存里维护一个统一的巨大的hash表,memcached能存储各种各样的数据,包括图像、视频、文件、以及数据库检索的结果等。简单的说就是将数据调用到内存中,然后从内存中读取,从而大大提高读取速度。
  3. 哪些情况下适合使用Memcached:存储验证码(图形验证码、短信验证码)、登录session等所有不是至关重要的数据。

安装和启动memcached

  1. windows:

    • 安装:memcached.exe -d install
    • 启动:memcached.exe -d start
  2. linux(ubuntu):

    • 安装:sudo apt install memcached

    • 启动:

      cd /usr/local/memcached/bin
      ./memcached -d start
      
  3. 可能出现的问题:

    • 提示你没有权限:在打开cmd的时候,右键使用管理员身份运行。
    • 提示缺少pthreadGC2.dll文件:将pthreadGC2.dll文件拷贝到windows/System32.
    • 不要放在含有中文的路径下面。
  4. 启动memcached

    • -d:这个参数是让memcached在后台运行。 &
    • -m:指定占用多少内存。以M为单位,默认为64M
    • -p:指定占用的端口。默认端口是11211
    • -l:别的机器可以通过哪个ip地址连接到我这台服务器。如果是通过service memcached start的方式,那么只能通过本机连接。如果想要让别的机器连接,就必须设置-l 0.0.0.0

    如果想要使用以上参数来指定一些配置信息,那么不能使用service memcached start,而应该使用/usr/bin/memcached的方式来运行。比如/usr/bin/memcached -u memcache -m 1024 -p 11222 start

telnet操作memcached

telnet ip地址 [11211]
  1. 添加数据:

    • set:
      
      • 语法:

          set key flas(是否压缩) timeout value_length
          value
        
      • 示例:

         set name 0 120 5    120秒为单位  5表示长度   
        hello
        STORED  存储成功
        
        set kangbazi 0 60 7   
        asdfghjk
        CLIENT_ERROR bad data chunk  #表示超出最大长度  
        ERROR  
        
        7 长度 7 要求只能输入7个字节  多 少 都出错  
        
    • add

      • 语法:

          add key flas(0) timeout value_length
          value
        
      • 示例:

        add python 0 60 7   如果 key python 不存在  那么 存入成功 
        qweasdz
        STORED
        
        add python 0 120 5   如果已经存在 key  python 那么 存入失败  
        hello
        NOT_STORED
        
        

        setadd的区别:add是只负责添加数据,不会去修改数据。如果添加的数据的key已经存在了,则添加失败,如果添加的key不存在,则添加成功。而set不同,如果memcached中不存在相同的key,则进行添加,如果存在,则替换。

  2. 获取数据:

    • 语法:

        get key
      
    • 示例:

        get username
          
      get name python #也支持批量获取
      VALUE name 0 5
      hello
      VALUE python 0 6
      qweasd
      END
      
      
  3. 删除数据:

    • 语法:

        delete key
      
    • 示例:

      delete python
      DELETED   表示删除成功  
      
    • flush_all:删除memcached中的所有数据。

      flush_all   
      OK
      
      
  4. 查看memcached的当前状态:

    • 语法:stats
  5. memcached 自增 自减 指定的值

    set num 0 120 2 
    10    保证key对应的value值 是int 类型 
    
    
    incr num 10  自增  
    20
    decr num 1  自减 
    19
    
    

通过python操作memcached

  1. 安装:python-memcachedpip install python-memcached

  2. 建立连接:

     import memcache
     mc = memcache.Client(['127.0.0.1:11211','192.168.174.130:11211'],debug=True)
    
  3. 设置数据:

     mc.set('username','hello world',time=60*5)
     mc.set_multi({'email':'[email protected]','telphone':'111111'},time=60*5)
    
  4. 获取数据:

     mc.get('telphone')
    
  5. 删除数据:

     mc.delete('email')
    
  6. 自增长:

     mc.incr('read_count')
    
  7. 自减少:

     mc.decr('read_count')
    

memcached的安全性:

memcached的操作不需要任何用户名和密码,只需要知道memcached服务器的ip地址和端口号即可。因此memcached使用的时候尤其要注意他的安全性。这里提供两种安全的解决方案。分别来进行讲解:

  1. 使用-l参数设置为只有本地可以连接:这种方式,就只能通过本机才能连接,别的机器都不能访问,可以达到最好的安全性。

    /usr/bin/memcached -l 127.0.0.1

  2. 使用防火墙,关闭11211端口,外面也不能访问。

  ufw enable # 开启防火墙
  ufw disable # 关闭防火墙
  ufw default deny # 防火墙以禁止的方式打开,默认是关闭那些没有开启的端口
  ufw deny 端口号 # 关闭某个端口
  ufw allow 端口号 # 开启某个端口

在Django中使用memcached:

首先需要在settings.py中配置好缓存:

CACHES = {
    'default': {
        'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
        'LOCATION': '127.0.0.1:11211',
    }
}

如果想要使用多台机器,那么可以在LOCATION指定多个连接,示例代码如下:

CACHES = {
    'default': {
        'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
        'LOCATION': [
            '172.19.26.240:11211',
            '172.19.26.242:11211',
        ]
    }
}

配置好memcached的缓存后,以后在代码中就可以使用以下代码来操作memcached了:

stats items 查看 memcached中所有的key

stats cachedump 1 0

stats cachedump item的id 0 表示所有的内容

from django.core.cache import cache

def index(request):
    cache.set("username","kangbazi",180)
    username = cache.get("username")
    print(username)
    return HttpResponse("index")

stats items
stats cachedump 1 0
ITEM :1:username [8 b; 297086766 s]
END
get :1:username
VALUE :1:username 16 8
kangbazi
END

需要注意的是,django在存储数据到memcached中的时候,不会将指定的key存储进去,而是会对key进行一些处理。比如会加一个前缀,会加一个版本号。如果想要自己加前缀,那么可以在settings.CACHES中添加KEY_FUNCTION参数:

CACHES = {
    'default': {
        'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
        'LOCATION': '127.0.0.1:11211',
        'KEY_FUNCTION': lambda key,prefix_key,version:"django:%s"%key
    }
}



stats items
        STAT items:1:number 2
        STAT items:1:age 3054595952
        STAT items:1:evicted 0
        STAT items:1:evicted_nonzero 0
        STAT items:1:evicted_time 0
        STAT items:1:outofmemory 0
        STAT items:1:tailrepairs 0
        END	
stats cachedump 1 0
        ITEM shanghai:python1806 [6 b; 297086910 s]
        ITEM :1:username [8 b; 297086766 s]
        END
get shanghai:python1806
        VALUE shanghai:python1806 16 6
        zelinx
        END

修改session的存储机制:下面这些 在 settings.py 中进行设置 session存储方式 很多 不止一种

最后一行 加入 SESSION_ENGINE = "django.contrib.sessions.backends.cached_db "

默认情况下,session数据是存储到数据库中的。当然也可以将session数据存储到其他地方。可以通过设置SESSION_ENGINE来更改session的存储位置,这个可以配置为以下几种方案:

  1. django.contrib.sessions.backends.cached_db:在存储数据的时候,会将数据先存到缓存中,再存到数据库中。这样就可以保证万一缓存系统出现问题,session数据也不会丢失。在获取数据的时候,会先从缓存中获取,如果缓存中没有,那么就会从数据库中获取。

     在 settings.py中 写入下面两段内容 
     SESSION_ENGINE = "django.contrib.sessions.backends.cached_db "
     CACHES = {
        'default': {
            'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
            'LOCATION': '127.0.0.1:11211',
            'KEY_FUNCTION': lambda key,prefix_key,version:"django:%s"%key
        }
    }
    
    
    view.py 
    	def session_view(request):
        request.session['shanghai'] = "python"
        request.session['classid'] = '1806'
        # username = request.session.pop("username")
        # userid = request.session.pop("userid")
    
        # request.session.clear()
        # request.session.flush()
        username = request.session.get("shanghai")
        print(username)
        
    telnet 127.0.0.1 11211   先回车   
    
    stats items  
    stats cachedump 5 0 
    get django:django.contrib.sessions.cached_dbeczyh9yvf9l89x4h71xrd9meyh155z00 获取session信息    
    
    
    
  2. django.contrib.sessions.backends.signed_cookies:将session信息加密后存储到浏览器的cookie中。这种方式要注意安全,建议设置SESSION_COOKIE_HTTPONLY=True,那么在浏览器中不能通过js来操作session数据,并且还需要对settings.py中的SECRET_KEY进行保密,因为一旦别人知道这个SECRET_KEY,那么就可以进行解密。另外还有就是在cookie中,存储的数据不能超过4k

相关文章:

  • 2021-09-18
  • 2022-01-07
  • 2021-06-24
  • 2022-12-23
  • 2021-06-27
  • 2021-12-03
  • 2022-12-23
  • 2022-12-23
猜你喜欢
  • 2021-05-27
  • 2021-06-17
  • 2022-12-23
  • 2021-08-07
  • 2021-10-21
  • 2021-04-20
  • 2021-09-27
相关资源
相似解决方案