Django

Quản lý subsite với django

Khi phát triển một website cho các hệ thống quản lý và thương mại, chắc hẳn mọi người sẽ gặp một bài toán như sau: "Ví dụ bạn xây dựng một website abc.com và muốn khi người dùng đăng ký với tên là xyz thì sẽ tự động tạo ra một site cho người dùng dưới dạng http://abc.com/xyz hoặc tên miền mà người dùng lựa chọn". Với bài toán như vậy chúng ta sẽ xây dựng website ra sao để có thể quản lý được các site con như vậy?

Đây là một bài toán mà nhiều người đã và đang giải quyết. Nếu sử dụng các hệ thống có sẵn như Joomla, Drupal, Wordpress hay Plone thì đã được hỗ trợ phần nào. Với Django thì bạn thực hiện bài toán đó như thế nào? Được truyền cảm hứng từ bài viết của pduyha (Cấu hình Apache với nhiều Django site), với cách làm trên thì mỗi lần tạo một site mới chúng ta phải restart lại Apache (hoặc có cách reload). Nhưng khi số lượng site lớn dần thì công đoạn đó sẽ mất thời gian đáng kể. Bên cạnh đó sẽ có sự lãng phí tài nguyên và tốn công cho việc nâng cấp.

Bài viết này sẽ cố gắng đưa ra một cách giải quyết khác để quản lý được các site con mà không ảnh hưởng đến Apache và tiết kiệm được không gian lưu trữ vì tất cả các site sẽ được chạy chung một mã nguồn, do vậy cũng thuận tiện cho việc sửa đổi và nâng cấp.

Ý tưởng của phương pháp này đó là chúng ta sẽ xử lý url của site trước khí trả về cho django xử lý. Ví dụ chúng ta có trang web http://abc.com, trang about có địa chỉ là http://abc.com/about. Giờ chúng ta muốn tạo một site còn là xyz và muốn khi vào địa chi http://abc.com/xyz/about thì sẽ ra trang thông tin của ông xyz. Vậy chúng ta phải làm sao phân biệt được url đó là của trang chính hay là của trang con? Đơn giản là chúng ta phải phân tích url để đưa ra quyết định. Có 2 việc chúng ta phải giải quyết

  • Phân tích URL trước khi cho Django xử lý
  • Quản lý thông tin site con

Về vấn đề quản lý thông tin của site con chúng ta có thể tận dụng luôn được đối tượng Site có sẵn của Django. Đối tượng này có 2 thông tin là domain và name. Ở đây chúng để phân biệt doamain và subsite, mình sẽ lưu subsite thêm ký tự / ở đầu. Ví dụ nếu một trang web là http://abc.com/xyz thì thông tin sẽ được lưu trong trường domain của Site là /xyz.

Việc tiếp theo là tạo một Middleware cho Django (tài liệu về Middleware có thể đọc tại đây). Chúng ta sẽ tạo một app với file middleware.py có nội dung như sau

from django.conf import settings
import re

from django.contrib.sites.models import Site

class MultiSiteMiddleware:
    def process_request(self, request):

        r = re.match("^/([^/]*)($|(/.*$))", request.path)
        found = False
        
        if r:
            possible_subsite = r.groups()[0]
            real_action = r.groups()[1]
            if len(real_action) > 0 and real_action[0] == '/':
                real_action = real_action[1:]
            
            sites = Site.objects.all()
            for site in sites:
                if site.domain[0] == '/': # neu duoc dang ky la subsite /subsite
                    subsite = site.domain[1:] # Loai bo / o dau
                    if subsite == possible_subsite:
                        found = True
                        break # thoi ra ngoai thoi, xg roi
                        
        request.META['SUB_SITE'] = ''
                    
        if found:       
            request.path = '/%s' % real_action
            request.path_info = '/%s' % real_action
            # cho them mot so thong tin de su dung
            request.META['SUB_SITE'] = possible_subsite
            request.META['SUB_SITE_ID'] = site.id
        else:
            request.META['SUB_SITE'] = ''
            request.META['SUB_SITE_ID'] = 0

Như trong code, khi url có dạng /xyz/function1 thì chương trình sẽ nhận diện đây là site /xyz và chạy chức năng function1, cùng với đó là các thông số được thiết lập thêm trong biến request (SUB_SITE và SUB_SITE_ID) để giúp các ứng dụng biết là hiện tại đang ở site nào.

Chúng ta cũng sẽ phải khai báo middleware này lên trên cùng khi khai báo Middleware của Django để đảm bảo luôn được thực thi đầu tiên. Việc khai báo này sẽ được làm trong phần settings của Django

MIDDLEWARE_CLASSES = (
    'my.apps.appmultisite.middleware.MultiSiteMiddleware', # Khai bao o tren cung!!!
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.locale.LocaleMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
)

Như vậy giờ đây chúng ta có thể áp dụng cho các project với nhiều subsite. ^^

Blog's tag:

Blog's topic:

Tạo môi trường làm việc ảo với virtualenv

Virtualenv là một công cụ để xây dựng môi trường độc lập khi phát triển với Python. Đó là một cách tuyệt vời để nhanh chóng kiểm tra các thư viện mới mà không làm lộn xộn các package có sẵn của bạn hoặc chạy nhiều dự án trên cùng một máy phụ thuộc vào một thư viện đặc biệt nhưng không phải cùng một phiên bản của thư viện đã có.

Ví dụ bạn có thể cài đặt phiên bản X của thư viện trong một môi trường và phiên bản Z của cùng một thư viện trong môi trường khác, mà không gây ảnh hưởng đến cái khác. Mỗi môi trường cung cấp thực thi Python riêng của nó và thư mục của site-package (không được chia sẻ giữa các môi trường).

Để cài đặt virtualenv, chỉ cần sử dụng easy_install với lệnh sau đây:

easy_install virtualenv

Một khi virtualenv được cài đặt, bạn có thể sử dụng lệnh virtualenv để tạo ra môi trường ảo. Các lệnh sau đây sẽ tạo ra một môi trường được gọi là "working":

virtualenv working

Bạn có thể kích hoạt các môi trường bằng cách chạy script kích hoạt nó, nằm trong thư mục bin của môi trường:

source working/bin/activate

Nếu bạn cài đặt một package trong môi trường ảo của bạn, bạn sẽ thấy script thực thi được đặt trong bin/working/ và egg trong working/lib/python2 .X/site-package/

Như bạn thấy, môi trường ảo sẽ kế thừa các gói từ thư mục site-packages mặc định của hệ thống. Điều này đặc biệt hữu ích khi dựa vào những package có sẵn, vì vậy bạn không cần phải cài đặt lại chúng trong mọi môi trường.

Tôi cố gắng giữ cho thư mục site-package của hệ thống tối giản và chỉ cà đặt các package mà tôi sử dụng trong gần như mọi dự án. Nó bao gồm giao diện làm việc với cơ sở dữ liệu như MySQLdb hoặc psycopg2 cũng như setuptools, tất nhiên là cả virtualenv.

Tuy nhiên, bạn cũng có thể thay đổi điều này bằng cách truyền --no-site-packages khi tạo ra một môi trường ảo. Điều này sẽ tạo ra một môi trường sạch sẽ mà không kế thừa các gói từ site-package của hệ thộng:

virtualenv --no-site-packages working

Để thoái khỏi một môi trường, chỉ cần chạy câu lệnh:

deactivate

Như vậy với virtualenv chúng ta có thể tạo ra những môi trường làm việc độc lập, thoải mái có thể thử nghiệm các package và chạy các ứng dụng lặt vặt khác. Điều này rất hữu ích cho việc học Django nói riêng và học Python nói chung.

Blog's topic:

Cài đặt Django trên Dreamhost

Mình đang sử dụng dịch vụ hosting trên Dreamhost và thấy khá thú vị vì các tính năng mà nó support từ SVN, Unlimited Bandwidth và Unlimited Storage. Thú vị hơn là mình có thể cài Django trên đó để có thể thực hành được các ứng dụng nhỏ. Bài viết này sẽ cụ thể hóa cách cài đặt Django trên Dreamhost.

Mặc định trên Dreamhost đã có cài Django, chúng ta có thể thấy được điều này nếu vào console python và gõ lệnh

>> import django >> django.get_version()

Kết quả trả về sẽ là version hiện tại của Django được cài trên host. Và mình có được version là 1.2.

Hiện tại version mới nhất của Django là 1.3. Để cài đặt được version mới nhất ta làm theo các bước sau.

Cài đặt Python virtualenv để có thể tự mình cài đặt các Python package. Kiểm tra trang virtualenv pypi để lấy bản mới nhất.

wget http://pypi.python.org/packages/source/v/virtualenv/virtualenv-1.6.3.tar.gz
tar xzf virtualenv-1.6.3.tar.gz
python virtualenv-1.6.3/virtualenv.py $HOME/local
rm -rf virtualenv*
export PATH=$HOME/local/bin:$PATH

Bạn nên sửa lại ~/.bashrc như sau

export PATH=$HOME/local/bin:$PATH

Kiểm tra lại đường dẫn đến python bằng lệnh which python, kết quả trả về là /home/youruser/local/bin/python chứ không phải là /usr/bin/python.

Giờ chúng ta có thể cài (cập nhật) bản mới nhất của Django thông qua lệnh

pip install --upgrade django

Vậy là bây giờ chúng ta đã có Django mới nhất (1.3) trên host của Dreamhost rồi. ^_^

Blog's tag:

Blog's topic:

Sử dụng Amazon SES với Django

Amazon Simple Email Service (Amazon SES) là một giải pháp email dễ dùng và hiệu quả cho các ứng dụng. Tuy Amazon SES đang được phát triển ở giai đoạn beta nhưng nó đã đáp ứng tương đối đầy đủ nhu cầu nhận và gửi mail.

Để đăng ký sử dụng Amazon SES chúng ta làm theo các bước hướng dẫn này để xác minh địa chỉ email cần sử dụng. Nếu làm việc trên môi trường Windows chúng ta cần đọc thêm hướng dẫn này nữa. 

Trên môi trường Ubuntu khi thực hiện quá trình verify email có thể sẽ gặp thông báo lỗi như là "Can't locate XML/LibXML.pm in @INC....". Lỗi này xảy ra khi máy của bạn chưa có thư việc XML của Perl. Để khắc phục bạn cài thêm 2 thư viện của Perl bằng dòng lệnh

sudo apt-get install libio-socket-ssl-perl

sudo apt-get install libxml-libxml-perl

Sau khi verify email thành công chúng ta có thể thực hiện gửi mail, nhưng chỉ gửi và nhận với địa chỉ email mà đã được đăng ký, chủ yếu dùng để debug trước khi thực hiện tiếp quá trình đăng ký Production để gửi email đến các địa chỉ khác.

Công việc tiếp theo là làm sao để sử dụng được Amazon SES từ Django. Chúng ta sẽ phải cài thêm boto (thư viện đóng gói làm việc với các dịch vụ Amazon trên Python) và django-ses.

sudo pip install boto

sudo pip install django-ses

Thêm các thông tin sau vào settings.py của project (thông tin về các KEY dưới bạn nên đọc trong phần hướng dẫn có link ở trên).

AWS_ACCESS_KEY_ID = 'YOUR-ACCESS-KEY-ID'

AWS_SECRET_ACCESS_KEY = 'YOUR-SECRET-ACCESS-KEY'

EMAIL_BACKEND = 'django_ses.SESBackend'

Sau khi điền đầy đủ các thông tin cần thiết, chúng ta có thể gửi mail bằng cách sử dụng django.core.mail.send_mail thông qua SES.

Đã được post trên django.vn

 

Blog's tag:

Blog's topic:

Tôi bắt đầu học Django

Tôi chưa bao giờ học Python, cũng đã có mấy dịp định học thêm Python nhưng vẫn chưa lần nào bắt đầu được. Tôi mới chỉ biết Python là ngôn ngữ lập trình hướng đối tượng triệt để, nôm na dễ hiểu đó là cái gì trong Python cũng là đối tượng hết.

Dịp này công ty có project về Django nên tôi cũng được join để làm một số task nho nhỏ. Trước đây khi tìm hiểu về một số web framework thì cũng đã biết đến Django nhưng chưa lần nào đọc kỹ và develop trên nó cả. Có lần cũng thử tìm hiểu Plone nhưng hoa hết cả mắt, đau hết cả đầu vì phải chưa gì đã vấp phải mấy khái niệm mới nào là egg, nào là bunches,...

Học Django lần này lại khác vì bây giờ tôi làm việc chủ yếu ở môi trường Ubuntu và bên cạnh có nhiều cao thủ Python và Django nên có gì lơ mơ là hỏi luôn thành ra mọi việc trở nên suôn sẻ hơn. Các bước học "mỳ ăn liền" được diễn ra chóng vánh

  • Đọc hướng dẫn và cài đặt Django trên Ubuntu
  • Cài đặt Django với Apache và mod_wsgi
  • Khái niệm project va app của Django
  • Thực tập tạo Project và app mới
  • Tìm hiểu về Models, urls, view, Template

Còn về ngôn ngữ Python thì vừa học vừa tìm hiểu và hỏi các partner bên cạnh, tuy chưa biết được nhiều về cấu trúc và cách sử dụng hàm của Python, những cũng giúp tôi đủ dùng để develop những app không quá phức tạp.

Nhìn chung qua một thời gian ngắn tiếp xúc với Django tôi cũng bắt đầu thấy thích và thấy đây là một framework khá thú vị để bỏ công sức tìm hiểu ^^

Blog's topic:

Subscribe to Django