iT邦幫忙

2018 iT 邦幫忙鐵人賽
DAY 4
1

其實今天原本是要寫安裝Laravel的介紹
但是因故卡關(上一次安裝已經是好久以前)
怕時間來不及所以果斷擱置,趕緊挖一個新坑


MVC & MTV

說到Django與Rails的比較,最常被拿出來討論的就是他的MTV架構
與我們熟知的MVC略有不同(如果你是先接觸Django,當然可能會有相反的認知)
一般來說我們會做以下的對照:

結構參照 Rails Django
模型(Data Access Logic) model model
視圖(Presentation Logic) view template
控制器(Business Logic) controller view

這也是MTV的由來(Model-Template-View)
不用特別觀察也可以發現這邊兩種不同架構view的角色不同
而model則是一致
但也有另外一種說法
認為view與template事實上都是對應視圖,而控制器應該是django本身
所以對照圖如下:

結構參照 Rails Django
模型(Data Access Logic) model model
視圖(Presentation Logic) view template、view
控制器(Business Logic) controller Django itself

但我個人基本上是不能接受這種說法的
先不說這樣無法算是MVT而應該是MVTD
如果我們看看一個傳統的Django view的例子:

from django.http import HttpResponse
def index(request):
    return HttpResponse('Hello from Django!')

會發現與Rails的controller基本上是做一樣的事情

class UsersController < ApplicationController
    def index
        @test = "Hello rails"
    end
end

Project and apps

在安裝完環境,開始創建第一個Django專案的時候
我注意到一個很少人比較的差異
就是Django有Project and apps的概念,也就是一個專案(project)下可能多有個apps
但rails專案下就是一個app,很少有聽人實作過複數以上apps的案例
按照django的說法,例如Facebook依照功能有以下的apps:

  • 使用者管理 -- accounts
  • 好友管理 -- friends
  • 塗鴉牆管理 -- timeline
  • 動態消息管理 -- news

如果我們未來要追加購物功能,accounts這個app就可以重複使用。
當這樣的情境在rails之下,我們依然會視其為同一個app
只是不同部分的功能區塊

第一次看到這種區分方式覺得很貼心,但是轉念一想
九成以上的專案其實沒有這種需求
按照rails「慣例優先於設定」的精神,自然會不喜歡這種設計
如果我們比較創建專案的指令:

~/projects$ django-admin.py startproject mysite
~/projects$ cd mysite
~/projects/mysite$ python manage.py startapp djangoapp

在rails,我們只需要:

~/projects$ rails new railsapp

就可以建立一個名為railsapp的專案
我覺得從產生一個新專案開始,就可以知道為什麼rails這麼迷人
如果一行可解決問題,那就不要兩行
我都還沒提到Django在startapp以後,還需要到settings.py去手動註冊新app

# mysite/settings.py

...

# Application definition

INSTALLED_APPS = (
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'djangoapp',
)

我敢打賭一定很多Django的新手忘記這步,然後奇怪server打開怎麼沒有東西


CLI

接續著對開發者的友善程度(或稱開發的簡便程度)
講嚴格一點,我認為光是CLI之前還需要強調語言才能用就已經很冗余了(不過這一點Laravel也相同)
比方說一些常見的指令:

  • python manage.py -h <command_name>
  • python manage.py runserver
  • python manage.py startapp <app_name>

而在rails 相對應的指令為:

  • rails h
  • rails s
  • rails new <app_name>

長度只有一半,輸入的時間就節省一半
我當然知道Django也會有些套件可以做到類似的事情,例如django-shortcuts
但當這件事還需要考慮套件時,先天上就已經輸了
rails會在下一版成為預設(好吧,也或許我被rails寵壞了)


Settings.py

除了CLI以外,我還觀察到新建app與Template資料夾以後
都需要到settings.py修改設定

# settings.py

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [os.path.join(BASE_DIR, 'templates').replace('\\', '/')],
        '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',
            ],
        },
    },
]

其中的DIR預設為[]
要改為[os.path.join(BASE_DIR, 'templates').replace('\\', '/')]

既然創建app與新增Template資料夾是每個專案幾乎固定的動作
環境根本就可以主動先去確認約定的檔案名稱是否存在
少數特例再使用設定就好
況且,九成九以上的專案都會用到Template資料夾
為什麼不乾脆一開始就新增好成為預設
還要讓使用者自己新增?


Resources for urls.py

倒數第二點
我發現Rails有一個很方便的工具,但是Django沒有(或是我目前沒有在教學文件上找到)
就是關於動態路由的對應,Django需要一條一條寫,例如:

#urls.py
from trips.views import hello_world, home, post_detail

urlpatterns = [
    ...
    url(r'^post/(?P<pk>\d+)/$', post_detail, name='post_detail'),
]

但是在rails我們有個方便的工具Resoruce

#routes.rb
Rails.application.routes.draw do
  resources :post
end

只要短短一行,就產生了七種常用的路由,還可以用onlyexcept去做調整
甚至可以做套疊
不僅大大節省了開發時間,也讓程式碼顯得更簡潔


Admin page

黑了Django這麼多,在最後一點試圖平反一下
我還是有發現一點我覺得很不錯,而Rails沒有的
就是Django預設內建的Admin page
雖然我不知道實務上專案常不常用到
但至少有這個開發工具我覺得是相當方便的
雖然Rails要寫出類似的東西或是使用Gem也不會很麻煩
但這點確實是Django比較貼心的地方
除此之外
Rails慣例優於設定的精神簡直大勝!
這是我的觀察啦,理性勿戰


上一篇
Laravel與Rails比較
下一篇
比較Phoenix之前,先來聊聊Elixir
系列文
新時代的網頁框架比較-- 淺談Rails、Django、Phoenix、Laravel8

1 則留言

0
froce
iT邦新手 3 級 ‧ 2017-12-07 21:12:30

黑了這麼多,然後說理性勿戰。XD
用Django有個好處,就是在windows開發也一點問題也沒有,可是在網路上看Rail對初學者的建議是有錢用MAC,沒錢用linux。這點是我當初選Django的原因。不知道現實狀況是怎樣呢?

Settings.py那節說錯了。
你只要在app建完,註冊進去,然後在app裡面建templates資料夾就可以了。
(不過我也不知道官方不在產生的時候就把app註冊進去的理由是什麼,因為我找不到建好app不註冊進去的理由...)

Django的想法是希望你專案建完就建app,不同的功能由不同的app去管理。
也就是「網站」=「project」,然後裡面的「功能」=「app」。
在project裡建templates資料夾反而少見,通常是對app去建的。

像我的習慣是使用者登入、管理會建一個app,各種功能會各建一個。
這樣的好處是就算你網站功能再複雜,光看資料夾名稱你就已經知道你要改啥了。

看更多先前的回應...收起先前的回應...
bater iT邦新手 5 級 ‧ 2017-12-08 14:03:33 檢舉

感謝回饋!能用Windows開發真是一個優點,我當初為了開發rails果斷買了MAC

project與app經過你這樣解釋我更理解了,確實挺方便的。

bater iT邦新手 5 級 ‧ 2017-12-08 14:07:18 檢舉

Settings.py的部分,我是參考這邊的學習手冊

你的意思是只要在app下建Template資料夾就可以了,不需要到settings.py註冊嗎?

froce iT邦新手 3 級 ‧ 2017-12-08 14:53:59 檢舉

要註冊app,但不用自己手動填入「os.path.join(BASE_DIR, 'templates').replace('\', '/')」
app註冊完,Django會自己去找app裡面的templates資料夾。

在project層級下建templates反而比較麻煩,在app下建比較容易,這也算是證明我上面講的Django對於project和app的想法。

說到自己手動填入路徑,我想再講個方便的點。

Django的settings.py本身就是個可執行的python檔,所以設定是可以依照你的狀態去改的。

例如我測試機在windows,實際佈署是linux,我可以利用模組去看我的project目前在什麼機器,然後參數寫在同一份設定,去用if來判斷就好。

甚至很多全站共用的參數,你都可以寫在settings.py去import進去,可以重複利用。

另外幫python/Django再辯駁一點:你如果深入一點寫python,你會發現python很注重code的可讀性,有時寧願犧牲一點簡潔,也要讓可讀性變高。

拿你的兩個例子來說:

class UsersController < ApplicationController
    def index
        @test = "Hello rails"
    end
end
from django.http import HttpResponse
def index(request):
    return HttpResponse('Hello from Django!')

Rail的確比較簡潔,但是python你不得不說如果你寫過其他語言,你應該會看得懂,比較符合慣例和虛擬碼。

這是當初設計語言者的哲學和取捨。
python甚至為了提高可讀性,出了一個規範,叫 PEP 8,而且大部分的python使用者都蠻樂意遵守的。
(有興趣的話還可以看看PEP 20)

froce iT邦新手 3 級 ‧ 2017-12-08 15:27:59 檢舉

然後Django Admin在Django 2.0之後變成RWD了。
雖然我還是只有測試的時候會用,開放給別人管後台的時候不給。
(沒辦法,使用者有時你真的沒辦法教育,還是寫個讓他一看就懂的後台給他比較省事。)

froce iT邦新手 3 級 ‧ 2017-12-08 16:16:02 檢舉

不過你現在這樣每個框架一天,你要怎麼撐過30天的鐵人賽啊。XD

我要留言

立即登入留言