(91) 350-9520 support@omarine.org M-F: 7 AM - 7 PM; Weekends: 9 AM - 5 PM

Lập trình Web: Python: Django: Xây dựng cửa hàng trực tuyến với Oscar-Paypal, phần 1

1. Cài đặt Oscar

1) Tạo môi trường ảo

Tạo môi trường ảo luôn là bước đầu tiên cho một dự án Python. Chúng ta đã xây dựng chương trình Polls hoạt động trong môi trường ảo ~/python-env/mysite, bây giờ tạo môi trường ảo tại ~/python-env/myshop cho cửa hàng trực tuyến:

cd ~/python-env && python3 -m venv myshop
source myshop/bin/activate

2) Cài đặt Oscar

Trong mysite, chúng ta đã thực hiện đầy đủ các bước để nắm được cấu trúc căn bản của một chương trình Web, từ tạo chương trình, cài đặt cơ sở dữ liệu, thiết kế mô hình và di chuyển dữ liệu, cấu hình, thiết lập URLconf, thiết kế view và khuôn mẫu với form bảo mật, cho tới sử dụng file tĩnh, test, và tùy biến trang admin. Ngoài ra, triển khai server sản phẩm cho thấy tính thực tiễn của một dự án Python: Django.
Trong dự án này, chúng ta cài đặt và tùy biến Oscar. Qua đó, bạn sẽ tiếp cận các kỹ thuật nâng cao như đa ngôn ngữ, tiền tố ngôn ngữ trong mẫu URL, đăng nhập bằng email, xử lý tệp upload, máy tìm kiếm, tùy biến module, promotions, và nhiều hơn nữa.
Kỹ thuật tiền tố ngôn ngữ trong mẫu URL rất hữu ích, nó cho phép mọi khách hàng chuyển ngôn ngữ ngay tại cửa hàng trực tuyến không chỉ ngôn ngữ giao diện mà cả nội dung, vì mỗi tiền tố ngôn ngữ có thể chuyển tới các trang khác nhau.
Một vấn đề nữa là ngôn ngữ giao diện. Dịch ngôn ngữ là cần thiết vì ngôn ngữ giao diện tiếng Việt mới ở dạng sơ khai.
Ngoài khía cạnh kỹ thuật, một số vấn đề như tạo lớp sản phẩm, xử lý đơn hàng và vận chuyển, thanh toán trực tuyến là những khái niệm gần gũi và đáng quan tâm trong thời buổi thương mại điện tử.
Cài đặt Oscar như sau:

pip install django-oscar

Ngoài ra, chúng ta cài đặt Django mở rộng:

pip install django_extensions

2. Tạo dự án myshop

Cũng như mysite, dự án này sẽ được đặt trong ~/sites. Bạn chuyển tới đó và tạo một dự án tên là myshop:

cd ~/sites && django-admin startproject myshop

Chuyển tới thư mục dự án và sẵn sàng cấu hình trong mục tiếp theo:

cd myshop

3. Cấu hình myshop

Giống như mọi dự án Python: Django, cấu hình bao gồm các bước soạn thảo settings.py. Đầu tiên, định nghĩa một biểu thức lambda và gán nó cho biến hàm location:

location = lambda x: os.path.join(
        os.path.dirname(os.path.dirname(os.path.realpath(__file__))), x)

Hàm location có tác dụng xác định đường dẫn cho đối số nối từ thư mục dự án.

Tiếp theo, thêm một số chương trình vào dự án và đặt SITE_ID. Chúng ta chưa tích hợp Paypal tại thời điểm này, chỉ cấu hình myshop để chạy oscar:

INSTALLED_APPS = [
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.sites',
    'django.contrib.messages',
    'django.contrib.admin',
    'django.contrib.flatpages',
    'django.contrib.staticfiles',
    'django_extensions',
    'widget_tweaks',
]

from oscar import get_core_apps
INSTALLED_APPS += get_core_apps()

SITE_ID = 1

Thay bộ phận MIDDLEWARE với nội dung dưới đây. Đó là một danh sách các module hoạt động như plugin:

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
    'django.contrib.flatpages.middleware.FlatpageFallbackMiddleware',

    # Allow languages to be selected
    'django.middleware.locale.LocaleMiddleware',
    'django.middleware.http.ConditionalGetMiddleware',
    'django.middleware.common.CommonMiddleware',

    # Ensure a valid basket is added to the request instance for every request
    'oscar.apps.basket.middleware.BasketMiddleware',
]

Tiếp theo là cấu hình khuôn mẫu:

from oscar import OSCAR_MAIN_TEMPLATE_DIR

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [
            location('templates'),
            OSCAR_MAIN_TEMPLATE_DIR
        ],
        'OPTIONS': {
            'loaders': [
                'django.template.loaders.filesystem.Loader',
                'django.template.loaders.app_directories.Loader',
            ],
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.template.context_processors.i18n',
                'django.contrib.messages.context_processors.messages',

                'oscar.apps.search.context_processors.search_form',
                'oscar.apps.promotions.context_processors.promotions',
                'oscar.apps.checkout.context_processors.checkout',
                'oscar.apps.customer.notifications.context_processors.notifications',
                'oscar.core.context_processors.metadata',
            ],
        },
    },
]

Về cơ sở dữ liệu, cài đặt tượng tự dự án của chương trình Polls, sử dụng cơ sở dữ liệu django_myshop:

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'django_myshop',
        'USER': 'emin',
        'PASSWORD': '********',
        'HOST': '127.0.0.1',
    }
}

Bổ sung backend xác thực để người sử dụng có thể login sử dụng email của họ:

AUTHENTICATION_BACKENDS = (
    'oscar.apps.customer.auth_backends.EmailBackend',
    'django.contrib.auth.backends.ModelBackend',
)

Chỉ rõ yêu cầu chiều dài mật khẩu tối thiểu:

AUTH_PASSWORD_VALIDATORS = [
    {
        'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
        'OPTIONS': {
            'min_length': 9,
        }
    },
    {
        'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
    },
]

Bổ sung ngôn ngữ:

LANGUAGES = (
    ('ar', 'Arabic'),
    ('ca', 'Catalan'),
    ('cs', 'Czech'),
    ('da', 'Danish'),
    ('de', 'German'),
    ('en', 'English'),
    ('en-gb', 'British English'),
    ('el', 'Greek'),
    ('es', 'Spanish'),
    ('fi', 'Finnish'),
    ('fr', 'French'),
    ('it', 'Italian'),
    ('ja', 'Japanese'),
    ('ko', 'Korean'),
    ('nl', 'Dutch'),
    ('pl', 'Polish'),
    ('pt', 'Portuguese'),
    ('pt-br', 'Brazilian Portuguese'),
    ('ro', 'Romanian'),
    ('ru', 'Russian'),
    ('sk', 'Slovak'),
    ('uk', 'Ukrainian'),
    ('vi', 'Vietnamese'),
    ('zh-cn', 'Simplified Chinese'),
)

LANGUAGES là một danh sách (tuple) các ngôn ngữ được đại diện bởi các tuple 2 phần tử. Phần tử thứ nhất là mã ngôn ngữ. Phần tử thứ hai là tên ngôn ngữ. Bạn có thể thay tên ngôn ngữ bằng phiên bản tiếng địa phương của nó sử dụng hàm gettext_lazy(). Ví dụ:

from django.utils.translation import gettext_lazy as _

LANGUAGES = (
    ('en', _('English')),
    ('vi', _('Vietnamese')),
)

Các tên này không mang giá trị tức thời và hàm gettext_lazy() không thực hiện dịch ngay, cho tới khi các giá trị được truy cập, ví dụ, trong khuôn mẫu được kết xuất. Hàm gettext_lazy() sử dụng hàm lazy(), trong đó hàm gettext() bên trong thực hiện dịch văn bản thực tế khi cần. gettext_lazy thực chất là một biến hàm được gán như sau:

gettext_lazy = lazy(gettext, str)

Để hiểu rõ hơn hàm lazy(), chúng ta xem chương trình nhỏ ví dụ dưới đây:

from django.utils.functional import lazy

lang = 'en'

def vie():
    if lang == 'en':
        return 'Vietnamese'
    elif lang == 'vi':
        return 'Tiếng Việt'

vie_lazy = lazy(vie, str)

text = vie_lazy()

print (text)
lang = 'vi'
print (text)

Phép gán text = vie_lazy() chưa cho text một giá trị cụ thể vì hàm vie() chưa hoạt động. Cho tới khi gọi hàm print(), hàm vie() trả về xâu kí tự tùy thuộc giá trị của biến lang hiện hành. Như vậy, text được gán một lần nhưng được kết xuất khác nhau tùy theo ngữ cảnh của lang. Kết quả là:

Vietnamese
Tiếng Việt

Hàm gettext() dịch trực tiếp văn bản với ngôn ngữ hiện hành. Ví dụ


Trên đây đã phân tích cách xử lý đa ngôn ngữ liên quan tới LANGUAGES. Tuy nhiên, chúng ta không sử dụng hàm gettext_lazy() trong cấu hình dự án vì Oscar không sử dụng tên ngôn ngữ trong LANGUAGES, mà sử dụng thành phần name_local trong từ điển LANG_INFO. Từ điển LANG_INFO nằm trong django.conf.locale, mỗi mục từ điển tương ứng với một ngôn ngữ, có khóa là mã ngôn ngữ. Giá trị của khóa lại là một từ điển con chứa một số thông tin. Dưới đây là từ điển con dành cho tiếng Việt:

{
    'bidi': False,
    'code': 'vi',
    'name': 'Vietnamese',
    'name_local': 'Tiếng Việt',
}

Như vậy, tên ngôn ngữ trong LANGUAGES có thể đặt là rỗng. Nhưng không thể không có thành phần này vì một số hàm như get_languages() của django.utils.translation.trans_real yêu cầu LANGUAGES phải bao gồm các tuple (hay đối tượng lặp được nói chung) 2 phần tử.

Các ngôn ngữ trong danh sách sẽ được chứa trong một hộp chọn ngôn ngữ trên cửa hàng trực tuyến. Nếu bạn chỉ sử dụng một ngôn ngữ thì giữ lại chỉ ngôn ngữ đó trong danh sách, kèm theo đặt LANGUAGE_CODE theo mã ngôn ngữ đó. Khi đó hộp chọn ngôn ngữ sẽ không xuất hiện.

Cấu hình static và media:

STATIC_URL = '/static/'
STATIC_ROOT = location('public/static')

MEDIA_URL = '/media/'
MEDIA_ROOT = location('public/media')

Trong khi phát triển với DEBUG đặt tới True và sử dụng django.contrib.staticfiles trong INSTALLED_APPS, runserver sẽ xử lý các file tĩnh tự động. Nhưng điều đó không áp dụng đối với các file media tải lên từ người dùng vì chúng không được coi là các file tĩnh của dự án. Các file này cần bổ sung mẫu URL vào URLconf mà chúng ta sẽ thực hiện sau này.

Cấu hình backend tìm kiếm:

HAYSTACK_CONNECTIONS = {
    'default': {
        'ENGINE': 'haystack.backends.simple_backend.SimpleEngine',
    },
}

Chúng ta bắt đầu cấu hình Oscar từ đây:

from oscar.defaults import *

Đặt tên cửa hàng, ví dụ Omarine Shop:

OSCAR_SHOP_NAME = 'Omarine'
OSCAR_SHOP_TAGLINE = 'Shop'

Chấp nhận thanh toán đối với khách vãng lai:

OSCAR_ALLOW_ANON_CHECKOUT = True

Tiền thanh toán mặc định:

OSCAR_DEFAULT_CURRENCY = 'USD'

Trạng thái đơn hàng đi theo một hệ thống ống dẫn. Mỗi trạng thái có thể chuyển tiếp sang trạng thái khác, không chỉ sử dụng cho một đơn hàng mà còn được vận dụng theo tuyến để xử lý vận chuyển một phần đơn hàng. Ống dẫn được định nghĩa bởi OSCAR_ORDER_STATUS_PIPELINE. Bạn cũng cần chỉ ra trạng thái khởi tạo đơn hàng và khởi tạo tuyến, tương ứng trong OSCAR_INITIAL_ORDER_STATUS và OSCAR_INITIAL_LINE_STATUS. Ống dẫn trạng thái đơn giản là một từ điển trong đó mỗi trạng thái được đưa ra như một khóa. Giá trị của khóa là một tuple các trạng thái chuyển tiếp. Một tuple rỗng định nghĩa một điểm kết thúc của ống dẫn

OSCAR_INITIAL_ORDER_STATUS = 'Pending'
OSCAR_INITIAL_LINE_STATUS = 'Pending'

OSCAR_ORDER_STATUS_PIPELINE = {
    'Pending': ('Being processed', 'Cancelled',),
    'Being processed': ('Complete', 'Cancelled',),
    'Cancelled': (),
    'Complete': (),
}

Chúng ta mặc định sử dụng các tệp CSS thay vì sử dụng các tệp LESS mà tạo ra chúng:

OSCAR_USE_LESS = False

Advertisements

Gửi phản hồi

Website này sử dụng Akismet để hạn chế spam. Tìm hiểu bình luận của bạn được duyệt như thế nào.

%d bloggers like this: