Django
django test---
title: Django 和 Laravel 的一些使用上的异同对比——路由篇
tags:
- Django
- Laravel
- Chinese
date: 2019-06-07 20:50:18
---
由于一些原因`(贴近 LeetCode 技术栈|希望尝试一下 Python 的 Web 框架)`,需要使用 Django 来做一些开发,在使用上感受到了与之前习惯的 Laravel 框架之间的一些差异。
Django 和 Laravel 都是 MVC 框架,所以从理论上来说他们的工作逻辑都是差不多的,不过从实际的使用体验上来看,还是有一些比较大的差距,遂决定从自身使用的角度来评点一下这些差异,或许可以帮助一些还在 Laravel 中且希望往 Django 转换的同学一些参考。
![](https://blog-assets.nova.moe/pics/django-laravel/mvc.png)
## 路由
这个解释起来非常简单,简单来说,就是给定一个地址,我们要做什么操作,最简单的可能就是普通的页面啦,我们只需要渲染一个页面就好啦,稍微复杂一点的可能需要处理用户订单,修改密码啥的。
### Laravel
#### 渲染请求
在 Laravel 的一些小型项目中,路由的文件是放在:`routes/web.php` 中的,比如我们需要响应一个静态的 `/about` 页面,那么路由中是这样写的:
```php
Route::get('/about','PageController@about');
```
表示如果用户访问了 `/about` ,那么使用 `PageController` 的 `about` 方法(也就是函数)来处理, `PageController` 是通过指令:
```bas
php artisan make:controller PageController
```
来生成的,位于:`app/Http/Controllers/PageController.php` 中,对应的函数是:
```php
public function about()
{
return view('about');
}
```
#### 不同类型的请求
如果要响应不同类型的请求的话,可以这样写(哈哈,为什么一个 `about` 页面要接受这么多请求):
```php
Route::post('/about','PageController@create_about');
Route::put('/about','PageController@edit_about');
Route::delete('/about','PageController@delete_about');
```
如果是一个 CRUD 项目的话,你其实可以直接偷懒使用:
```
php artisan make:controller PhotoController --resource
```
来生成对应控制器,直接处理四中不同的 HTTP 请求,对应路由可以这么写:
```
Route::resources([
'photos' => 'PhotoController',
'posts' => 'PostController'
]);
```
然后你就可以直接处理以下请求了,是不是很方便?
| Verb | URI | 方法(函数) | Route Name |
| --------- | ---------------------- | ------------ | -------------- |
| GET | `/photos` | index | photos.index |
| GET | `/photos/create` | create | photos.create |
| POST | `/photos` | store | photos.store |
| GET | `/photos/{photo}` | show | photos.show |
| GET | `/photos/{photo}/edit` | edit | photos.edit |
| PUT/PATCH | `/photos/{photo}` | update | photos.update |
| DELETE | `/photos/{photo}` | destroy | photos.destroy |
> 这里补充一个,从我最初接触 Laravel 的时候(Laravel 5.6)还没有 `/photos/{photo}/edit` 这个对应的 GET 请求,所以如果需要显示一个包含编辑器的修改页面的话还需要手动创建一个 GET 请求的地址用来显示,当然,这么操作我是学习(抄袭)的 GitHub Gist 的。
好奇的同学可能要问了,这个 `view('about')` 是个什么,其实是对应的 `resources/views/about.blade.php` 这个页面的内容,即直接在这个文件中写入 HTML 即可。
由于 HTML 规范中没有 DELETE/PUT 之类的请求,所以 Laravel 对于这类请求的方法是,在 `<form>` 中加入一个字段来表示:
```
@method('PUT')
```
这样写的话,Laravel 会在表单中渲染成以下给后端去处理:
```html
<input type="hidden" name="_method" value="PUT">
```
对应的,csrf 是这样写的:
```
@csrf
```
会被渲染成:
```html
<input type="hidden" name="_token" value="{{ csrf_token() }}">
```
#### 跳转请求
那么假设我们完成了一个请求,需要进行跳转的话(比如下单成功,自动跳转回用户个人面板这种),该如何操作呢?
```php
return redirect('home/dashboard');
```
啊哈~
### Django
在 Django 中创建路由就稍微麻烦一些,因为刚刚创建好的一个项目中会有一个和项目同名的文件夹,其下有一个 `urls.py` ,默认的文件结构是这样的:
```
mysite/
manage.py
mysite/
__init__.py
settings.py
urls.py
wsgi.py
```
文件内容是这个样子的:
```python
from django.urls import path
from . import views
urlpatterns = [
path('', views.index, name='index'),
]
```
官方推荐的方式是,如果需要做什么请求的话,建议分到一个被称为 `app` 的里面去,一般就是创建了一个同级的文件夹(通过指令:`django-admin startapp polls`),内部有独立的模型和视图,文件结构一般如下,这里以官方的 `polls` 这个 `app` 为例:
```
mysite/
manage.py
mysite/
__init__.py
settings.py
urls.py
wsgi.py
polls/
__init__.py
admin.py
apps.py
migrations/
__init__.py
models.py
tests.py
urls.py
views.py
```
然后就需要在 `/mysite/mysite/urls.py` 中手动引用:
```python
from django.contrib import admin
from django.urls import include, path
urlpatterns = [
path('polls/', include('polls.urls')),
path('admin/', admin.site.urls),
]
```
然后在 `/mysite/polls/urls.py` 中接受一些路由,比如(以下来自我自己一个项目的 `urls.py`,有删改):
```python
from django.urls import path
from . import views
urlpatterns = [
path('about/',views.about),
path('status/',views.status),
]
```
哦对了,polls 下刚刚创建好的时候呀,连 `urls.py` 都没有,几乎所有需要需要 `import` 的内容呀,需要手动去官网查...
#### 渲染请求
在上面的例子中,我们已经定义了 `/polls/about/` 的路由了,是由 `views`(也就是 `views.py` 文件)中的 `about` 方法(也就是函数)来处理,那么对应的方法是如何写的呢?
```python
def about(request):
return render(request,'about.html',{})
```
看上去很简单?不对哦,我们还需要手动引用一些东西,不然会报错,比如:
```python
from django.shortcuts import render
```
这个东西哪儿来?得自己查...
#### 不同类型的请求
POST 和 GET 请求好说,可以有两种方式实现,一个是直接写在方法里面,大致如下:
```python
if request.method == 'GET':
do_something()
elif request.method == 'POST':
do_something_else()
```
或者也可以使用一个被称为 class-based view 的方式来写,如下:
```python
class HelloController(View):
def get(self, request):
hello_param = request.GET["helloParam"]
def post(self, request):
hello_param = request.POST["helloParam"]
```
如果需要处理 PUT 之类的请求的话...似乎不行...
CSRF 的话,Django 中写法如下:
```html
{% csrf_token %}
```
#### 跳转请求
同样,如果我们完成了一个请求,需要跳转的话,应该如何写呢?
```python
return HttpResponseRedirect('home/dashboard')
```
这样就完了?不对哦,还得手动引用:
```python
from django.http import HttpResponseRedirect
```
## 小结
从以上对比可以看出,对于一个不是非常大的项目来说,Laravel 的中心化管理路由的方式比较容易理解,尤其是一键创建多个方法的操作比较适合 CRUD (比如简单的博客系统之类的),但是这样的设计会在一定程度上给使用者一些局限性,不得不 Think the Laravel Way,还是有少量的不便。
而 Django 的话,如果完全不理解 MVC 的模式的话,上手可能会比较头痛(毕竟官方文档似乎不是很...亲民?),但是从长远来看,撇开那个自带的 `admin` 不说,分布式的路由结构还是非常适合团队合作以及各种类型的项目的,当然,需要对于整个项目有一个比较好的把控才行。