西维蜀黍

【Python】装饰器(Wrapper)

Introduction

每个人都有的内裤主要功能是用来遮羞,但是到了冬天它没法为我们防风御寒,咋办?

我们想到的一个办法就是把内裤改造一下,让它变得更厚更长。这样一来,它不仅有遮羞功能,还能提供保暖。

不过有个问题,这个内裤被我们改造成了长裤后,虽然还有遮羞功能,但本质上它不再是一条真正的内裤了。于是聪明的人们发明长裤,在不影响内裤的前提下,直接把长裤套在了内裤外面,这样内裤还是内裤,有了长裤后宝宝再也不冷了。装饰器就像我们这里说的长裤,在不影响内裤作用的前提下,给我们的身子提供了保暖的功效。

谈装饰器前,还要先要明白一件事,Python 中的函数和 Java、C++不太一样,Python 中的函数可以像普通变量一样当做参数传递给另外一个函数,例如:

def foo():
    print("foo")

def bar(func):
    func()

bar(foo)

回到我们的主题。装饰器本质上是一个 Python 函数或类,它可以让其他函数或类在不需要做任何代码修改的前提下增加额外功能,装饰器的返回值也是一个函数/类对象。

它经常用于有切面需求的场景,比如:插入日志、性能测试、事务处理、缓存、权限校验等场景,装饰器是解决这类问题的绝佳设计。

有了装饰器,我们就可以将大量与函数功能本身无关、但是又相似的代码抽离到装饰器中,并获得重用。概括的讲,装饰器的作用就是为已经存在的对象添加额外的功能。

先来看一个简单例子,虽然实际代码可能比这复杂很多:

def foo():
    print('i am foo')

现在有一个新的需求,希望可以记录下函数的执行日志,于是在代码中添加日志记录代码:

def foo():
    print('i am foo')
    logging.info("foo is running")

如果函数 bar()bar2() 也有类似的需求,怎么做?再写一个 logging 在 bar 函数里?这样就造成大量雷同的代码。为了减少重复代码(同时也就增加了重用性(reusability)),我们可以这样做,重新定义一个新的函数:专门处理日志 ,日志处理完之后再执行真正的业务代码

def use_logging(func):
    logging.warn("%s is running" % func.__name__)
    func()

def foo():
    print('i am foo')

use_logging(foo)

这样做逻辑上是没问题的,功能是实现了,但是我们调用的时候不再是调用真正的业务逻辑 foo 函数,而是换成了 use_logging 函数,这就破坏了原有的代码结构, 即我们不得不每次都要把原来的那个 foo 函数作为参数传递给 use_logging 函数。那么有没有更好的方式的呢?当然有,答案就是装饰器。

  ...


【Django】Django 路由规则

编写urlpatterns

最简单的情况

#urls.py
    from app import views #这里的app是你自己的应用的名字
    from django.urls import path
    urlpatterns = [
                path('index/', views.index, name='index'),
    ]

该方法对应view.py中的函数为:

#views.py
def index(request):
    ...
    return render(request,'index.html')
  ...


【Django】Django 创建 Django 项目或应用

Install Django

$ pip install django

Creating a project

$ django-admin startproject mysite

Start the Project

$ python manage.py runserver

You’ll see the following output on the command line:

If you want to change the server’s port, pass it as a command-line argument. For instance, this command starts the server on port 8080:

$ python manage.py runserver 8080

If you want to change the server’s IP, pass it along with the port. For example, to listen on all available public IPs (which is useful if you are running Vagrant or want to show off your work on other computers on the network), use:

  ...


【Django】template - 插入 Python 代码

if/else 标签

基本语法格式如下:

{% if condition %}
   ... display
{% endif %}

或者:

{% if condition1 %}
   ... display 1
{% elif condiiton2 %}
   ... display 2
{% else %}
   ... display 3
{% endif %}

根据条件判断是否输出。if/else 支持嵌套。

Note:模板标签中的变量是不需要用 {% raw %}{{ {% endraw %} 来包裹的。

and、or 或not

{% raw %}{% if %}{% endraw %} 标签接受 and , or 或者 not 关键字来对多个变量做判断 ,或者对变量取反(not),例如:

{% if athlete_list and coach_list %}
     athletes 和 coaches 变量都是可用的
{% endif %}

注意,{% raw %}{% if %}{% endraw %} 标签不允许在同一个标签中同时使用 and 和 or ,因为逻辑上可能模糊的,这样的代码是不合法的:

{% if athlete_list and coach_list or cheerleader_list %}

系统不支持用圆括号来组合比较操作。 如果你确实需要用到圆括号来组合表达你的逻辑式,考虑将它移到模板之外处理,然后以模板变量的形式传入结果吧。 或者,仅仅用嵌套的 {% raw %}{% if %}{% endraw %} 标签替换

  ...


【Django】Django ORM - QuerySet 序列化

最完美的方法

解决:

  • ‘dict’ object has no attribute ‘_meta’
  • Queryset is not JSON serializable
users = models.User.objects.values(*USER_FIELDS).filter(**filter)[start_index:start_index + limit]
if type(resp) is not list:
   resp = list(resp)
return HttpResponse(json.dumps(resp, indent=2, cls=DjangoJSONEncoder), content_type="application/json")
  ...