Django中基于函数的视图和基于类的视图以及路由传参

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Django中基于函数的视图和基于类的视图以及路由传参相关的知识,希望对你有一定的参考价值。

django中有两种视图函数的声明方式:基于函数,基于类

1. 基于函数

1. 使用query进行传参

路由传参,使用get方式进行传参时,也就是使用query的方式进行传参,类似于?name=‘zs’&age=12的方式。此时就可以使用视图函数中的requrest对象进行获取。注意:一般情况下我们的二级路由中后面都要带个反斜杠,如果有参数传递的话则不能带反斜杠,其他地方没有变化

# views.py
def index(request):
    # 这里设置的是默认参数
    name = request.GET.get(\'name\', \'lisi\')
    age = request.GET.get(\'age\', 22)
    return HttpResponse(f\'hello Django 当前参数中:name-name,age-age\')

# app01/urls.py
	urlpatterns = [
    path(\'v1\', index)
]
# mysite/urls.py
urlpatterns = [
    path(\'admin/\', admin.site.urls),
    path(\'test/\',include(\'app01.urls\'))
]

# 此时urls地址 http://127.0.0.1:8000/test/v1?name=zs&age=34

2.使用params进行传参

第二种路由传参,使用url进行传参,也就是动态路由匹配,比如test/zs/22,这样的方式进行传递。如果使用这种方式的话,那么我们的参数就要在视图函数的参数中进行接收,之后在应用的url中进行配置

### views.py
def index(request,name,age):
    return HttpResponse(f\'hello Django 当前参数中:name-name,age-age\')

### app01/urls.py
	urlpatterns = [
    path(\'v1/<string:name>/<int:age>\', index)
]
### mysite/urls.py
urlpatterns = [
    path(\'admin/\', admin.site.urls),
    path(\'test/\',include(\'app01.urls\'))
]

### 此时urls地址 http://127.0.0.1:8000/test/v1?name=zs&age=34

2. 基于对象

基于类的视图以class定义,而不是函数视图的def定义。使用类视图后可以将视图对应的不同请求方式以类中的不同方法来区别定义(get方法处理GET请求,post方法处理POST请求),相对于函数视图逻辑更清晰,代码也有更高的复用性。

# app01/views.py
from django.http import HttpResponse
from django.views.generic import View


class Test(View):
    def get(self, request):
        name = request.GET.get(\'name\', \'\')
        age = request.GET.get(\'age\', 12)
        return HttpResponse(f\'the name is name,age is age\')
    def post(self,request):
        pass
#app01/urls.py
from django.urls import path
from .views import Test

urlpatterns = [
    path(\'v1\', Test.as_view()),
]
# 基于面向对象的好处就是我们可以不用再去判断request.method是post还是get来处理不同的请求

在 Django 的基于类的视图中模拟函数

【中文标题】在 Django 的基于类的视图中模拟函数【英文标题】:Mocking functions in Django's class based views 【发布时间】:2013-03-17 22:36:19 【问题描述】:

我正在将 Django REST Framework 用于我正在处理的 API。出于几个原因,我想使用基于类的视图。但是,我对我的单元测试有点挑剔,我从不让我的单元测试接触数据库。注意:我总是使用 Carl Meyer 在 Pycon 2012 演示的“技巧”,他在其中模拟了 Cursor 包装器。

cursor_wrapper = Mock()
cursor_wrapper.side_effect = RuntimeError("No touching the database!")

@patch('django.db.backends.util.CursorWrapper', cursor_wrapper)
class TestMyCode(TestCase):

如果您对幻灯片感兴趣,这里是link。

我在其中一个视图中有一个方法可以检查数据库中的某些内容。为了干燥,它在 POST 和 PUT 之间共享。但是,我在为我的单元测试模拟它时遇到了问题。这是因为类方法 as_view 创建了一个新的实例和类调度,并返回调度返回的“处理程序”函数。因此,我似乎无法在基于类的视图中获取共享方法来模拟它。

我可以模拟出基于类的视图所使用的模型,但是我必须从根本上打破我“干”的目标,并在 POST 和 PUT 中复制代码。我想我可以重构代码并将逻辑移到模型上。但是,我不肯定我想这样做。

如何模拟基于类的视图的共享方法以避免实际接触数据库?只是避开它们?

【问题讨论】:

【参考方案1】:

我想你回答了你自己的问题。用于测试任何 Web 框架的相同内容也适用于 Django,例如控制反转和依赖注入。你可以在 Python 中保持它非常简单,所以不要被 Spring 这样的东西吓倒或关闭。

为什么不将代码移出基于类的视图?如果您出于某种原因在其他地方需要相同的逻辑,您的代码仍然不会干燥。仅仅因为它是 Django 并不意味着好的编程原则不适用。

我建议在新的类/python 模块中抽象一些东西,例如服务(作为一个概念,而不是 Django 对服务的定义)和其他用于数据访问的逻辑抽象。然后,您完全独立于 Django 视图的请求/响应生命周期。 Django 和 Rails 开发人员倾向于将所有逻辑都直接放在模型或视图中。这只会导致上帝类和难以测试的东西。

您也可以通过将视图视为轻量抽象来促进这一点,该抽象处理诸如将参数编组 (GET/POST) 等处理到您的其余代码并调用封装在其他地方的必要逻辑。 IMO,如果您想要可测试的代码,那么 99% 的逻辑应该在 Web 上下文之外,除非它对流程绝对至关重要。这也使得在后台和并行运行事情变得更容易。

您最终应该得到的是易于测试的普通 python 模块和类,因为它们不直接依赖于 HTTP。如果你需要模拟 HTTP,你可以简单地模拟请求对象。你很幸运,python/django 的组合使得将这些东西转储和模拟为简单的 dicts/kwargs 变得很容易。

我意识到使用基于类的视图的一件事是它们非常适合与 mixins 一起使用并强制执行一些约定(返回 json、打开图形属性等),但使用更“高级”的基于类的视图直接需要模型,例如因为 DetailView 只会让事情变得不必要地复杂化。这些视图非常适合管理屏幕,但对于真正的应用程序来说,帮助大于伤害。除非您找到一种很好的、​​无缝的方式来集成缓存层等,否则它们会使事情变得难以测试和破坏性能。这个时候,一般只是继承自View或者TemplateView就可以了。

关于数据库模拟,创建你的模拟并检查你的业务逻辑。然后,只要符合一组特定的规则和接口,您输入/输出的内容就无关紧要。例如,请参阅 Mixer 之类的内容。您还可以在测试期间简单地创建/销毁临时数据库。一种方法是为 dev/staging/production/testing 等创建单独的设置模块,并根据环境动态加载它们。这样你就可以避免在运行单元测试时损坏你的开发数据库。当然,这更多地涉及一种集成测试形式,但您可能也应该这样做。上述解决方案在 Hibernate 等其他 ORM 中很常见。

与上一个相关,您可以在设置中执行类似于以下代码的操作,以使用内存数据库进行单元测试。最终,您仍然需要考虑针对您的实际数据存储类型(例如 MySQL)进行集成测试

if 'test' in sys.argv:
    DATABASES['default']['ENGINE'] = 'sqlite3'

;tldr

    将类视图之外的逻辑放入适当的对象和模块中。

    不要把自己锁在试图让各种捆绑的基于类的视图适用于实际应用程序和每个用例;自己动手。

    使用一般良好的 TDD 原则,例如 IOC,将所需参数传递给构造函数,松散耦合,避免过多的专有状态要求(尤其是 HTTP)。

      通过创建标准模拟对象(参见#3)和通过类似服务的接口(参见#1)来避免对数据库的依赖。

【讨论】:

以上是关于Django中基于函数的视图和基于类的视图以及路由传参的主要内容,如果未能解决你的问题,请参考以下文章

Django框架之视图层(views)介绍

在 Django 的基于类的视图中模拟函数

Django中基于类的视图上带有参数的函数装饰器

Django编写RESTful API:基于类的视图

如何在 django 中使用基于类的视图

django-select2 基于类或基于函数的视图