談談 django 應用實踐

pythontab發表於2017-10-25

python 的 web 框架非常多,比較出名的有 django, flask, tornado。django 作為一個老牌框架,無論是文件還是程式碼質量都非常高,另外他自帶的 admin 後臺和一些有用的 app,如果你的需求是做 cms 之類的 web 應用的話,基本上不用開發多少程式碼就能出一個成品。不過很多新手可能一開始不太適應他的設計模式,遇到問題後基本就懵了,所以這裡我按照自己用 django 的經驗,寫一下 django 的一些應用實踐,可能寫的比較零散,大家見諒。

整體流程

談談 django 應用實踐

首先我們得了解下 django 這個框架整體的處理流程,假設我們採用 nginx + uwsgi + django 的 web server 模式

1. 一個請求過來後,首先經過 nginx 做反向代理,將請求轉發到 uwsgi (python 用 wsgi 這種協議來解析 http 請求,uwsgi 是一個 解析 wsgi 的應用),uwsgi 再將解析過的資料傳到 django。

2. django 收到請求後,首先會經過一組全域性的中介軟體 (middleware),呼叫 process_request 作為預處理,比如解析使用者狀態,檢驗 csrf_token (post 請求),如果有問題,則直接返回 response,不再呼叫 view 函式。否則,呼叫 process_view ,如果沒問題進入 view 函式。

3. 進入 view 函式後開發者可以寫自己的邏輯,比如運算元據庫,更新快取,最後返回一個 response。

4. 接下來 跳出 view 函式,重新進入 middleware,呼叫 process_response,對 response 做些最後的修飾,返回給使用者。

views 模組

1. view 不僅可以用函式,也可以用通用檢視類(generic_view),好處是:程式碼更加清晰,可以複用繼承,並且結合 mixin 能夠開發更加靈活的 view 模組

def hello_fn(request, name="World"):
        return HttpResponse("Hellp {}!".format(name))
class FeedMixin(object):
        def get_context_data(self, **kwargs):
            context = super().get_context_data(**kwargs)
            context["feed"] = models.Post.objects.viewable_posts(self.request.user)
            return context
            
class MyFeed(FeedMixin, generic.CreateView):
        model = models.Post
        template_name = "myfeed.html"
        success_url = reverse_lazy("my_feed")

2. python 的裝飾器很好用,也可以用於 views 函式, 比如下面的裝飾器用於登入使用者的檢測

@login_required
def simple_view(request):
       return HttpResponse()

urls 模組

1. urls.py 這個檔案將訪問的 url 跟 view 模組對應起來,按從上到下的順序匹配

2. 採用 include 函式可以包含其他 app 的 urls,namespace 引數定義後可以在模板中直接呼叫,比如

{% url 'articles'%} 
url(r'^articles/$', include(articles.urls), namespace="articles"),

models 模組

1. model 是具有處理資料庫的一種物件導向的方法的類,能夠讓不熟悉資料庫語句的程式設計師也能快速運算元據庫

2. 採用物件導向的方式建立類,加上 abstract = True 則為抽象類

class Postable(models.Model):
    created = models.DateTimeField(auto_now_add=True)
    modified = modified.DateTimeField(auto_now=True)
    message = models.TextField(max_length=500)
    class Meta:
        abstract = True
class Post(Postable):
    ...
class Comment(Postable):
   ···

3. django 表對應關係有一對一(OneToOneField),一對多 (ForeignKey),多對多 (ManyToManyField),其中 多對多的模式透過建立一箇中間表來實現。

class Book(models.Model):
    place = models.OneToOneField(Place, primary_key=True)
    pub=models.ForeignKey(Publisher)
    authors=models.ManyToManyField(Author)

上面的例子中間表包括 author_id 和 book_id

4. django 的 signal 實現 hook 資料庫寫行為,比如,pre_save, post_save,pre_delete, post_delete,你也可以自定義 signal, hook 其他行為。

@receiver(post_save, sender=TransactionDetail, dispatch_uid="update_stock_count")
def update_stock(sender, instance, **kwargs):
     instance.product.stock -= instance.amount
     instance.product.save()

5. Person.objects.all(), 這裡面的 objects 其實是個 manager, 實現了 all, filter 等函式,可以自定義。

class Person(models.Model):
    object = models.Manager()

6. django 的 queryset 是惰性的,只有在真正用的時候才會去資料庫查詢,並且查詢一次後,會有快取,當再次遍歷這個 queryset 的時候,不會再去查詢。

person_set = Person.objects.filter(first_name="Dave")

7. 資料庫第一次建立後,會有再次更新欄位的需求。django 在 1.4 版本前並沒有這個功能,得用第三方庫 south 來更新,後來的版本 django 自帶了 migration 功能,能夠將最新的 model 版本和資料庫的欄位作對比,自動生成 migration 檔案


python manage.py makemigrations # 生成 migration 檔案
   python manage.py migrate # 將更改應用到資料庫

8. orm 不能直接看到 raw sql 語句,可以透過如下語句檢視 sql

from django.db import connection
connection.queries

9. 可以使用 django-debug-toolbar 外掛檢視慢查詢,也能對對哪些頁面載入較慢有個大致的瞭解。

10. 在 orm 中使用 select_related() 減少查詢資料庫次數:,select_related() 會自動擴充套件外來鍵關係

class Province(models.Model):
    name = models.CharField(max_length=10)
class City(models.Model):
    name = models.CharField(max_length=5)
    province = models.ForeignKey(Province)
citys = City.objects.select_related().all()

不過對於高併發的應用來說外來鍵不是很推薦。

forms 模組

1. 前端傳上來一個表單的值,但是沒法確認這些值是不是為空,是不是型別正確,這個時候當然可以自己一個個值判斷,也可以採用 forms 模組去做驗證,用過 django-rest-framework 的同學會知道和裡面的 serializers 是同一個概念

class PersonDetailsForm(forms.Form):
       name = forms.CharField(max_length=100)
       age = forms.IntegerField()

2. 如果你用的是模板渲染的方式,那麼展示的時候更簡單,表單能自動生成 html 的表單。

>>> f = PersonDetailsForm()
>>> print(f.as_p())
<p><label for="id_name">Name:</label> <input id="id_name" maxlength="100"
name="name" type="text" /></p>
<p><label for="id_age">Age:</label> <input id="id_age" name="age"
type="number" /></p>

admin 模組

1. admin 基本上開箱即用,如果需要定製的話,也能做一些元件的定製,不過這些東西得看文件去詳細瞭解了。

commands 模組

1. django 提供了後臺指令碼模組,可以自己整合 BaseCommand 類去自定義指令碼

python mannage.py -h

這個命令就能看到所有的 commands 命令

2. 如果不想用他的模組,又想引入 django 專案的一些模組,可以採用下面的方法解決

os.environ.setdefault("DJANGO_SETTINGS_MODULE", "myproject.settings")
django.setup()

settings 模組

1. 所有的 settings 預設值都在這裡面能找到,https://github.com/django/django/blob/master/django/conf/global_settings.py

2. 上線的時候記得把 DEBUG 改成 False, 然後加上 ALLOWED_HOSTS

3. MEDIA_ROOT, MEDIA_URL, STATIC_ROOT, STATIC_URL 這幾個之前經常搞混,其實可以分為兩類,MEDIA_ROOT 指的是上傳檔案的目錄,MEDIA_URL 指的是字首名,http://example.com/media/, 其中的media 就是 MEDIA_URL, 同樣,STATIC_ROOT 指的是靜態檔案的目錄,一般放 css, js 之類,STATIC_URL 值得是字首名,http://example.com/static/。

4. 一般部署上線的時候,用 nginx 直接渲染靜態檔案

   location /media  {
        alias /root/example_project/public/media;
    }
    location /static {
        alias /root/example_project/static;
    }

contrib 模組

1. 這裡面的模組是 django 自帶的 apps,用的比較多的有 admin, auth, sessions

2. admin 模組其實就是 django 的後臺

3. auth 模組就是使用者模組,功能上比較齊全,基本上可以基於這個模組做擴充套件。

4. session 模組結合 auth ,用來做使用者的登入狀態,對於大型網站來說,session 的儲存可能是個問題,django 也提供了不同的 backends,支援 db, cache, file 等儲存方式。

middleware 模組

1. django 自帶的 middlreware 對於普通網站的需求已經蠻完善了,比如 CsrfMiddleware , HttpMiddleware。

2. 如果有自己的需求,也可以自定義,比如記錄詳細 log 資訊,LogMiddleware,還有跨域的 CorsMiddleware。

其他

1. 網上有人說 django 只能做小網站,不支援大的併發,其實這個說法還是很片面的。django 自身只是一個框架,如果網站請求處理慢,很多情況下是自己寫的邏輯沒有最佳化。確認是 django 框架問題的話,django 雖然設計上略複雜,但是很多模組還是可以拆分去自定義的。最後實在不濟,靠增加機器數量也能頂一陣。

2. django 的國際化模組做的很不錯

3. setting 檔案可分成 product, 和 dev 兩份,根據開發環境和生產環境不同引入不同的 setting 檔案。

4. django-celery 用來執行非同步任務

5. django 的外掛非常多,rosarior/awesome-django


相關文章