Xây dựng một trang web

Nguy hiểm

This tutorial is outdated. We recommend reading Server framework 101 instead.

Cảnh báo

Tạo một mô-đun cơ bản

Trong SoOn, các tác vụ được thực hiện bằng cách tạo các mô-đun.

Các mô-đun tùy chỉnh hoạt động của bản cài đặt SoOn, bằng cách thêm các hành vi mới hoặc bằng cách thay đổi các hành vi hiện có (bao gồm cả các hành vi được thêm bởi các mô-đun khác).

Giàn giáo của SoOn có thể thiết lập một mô-đun cơ bản. Để bắt đầu nhanh chóng, chỉ cần gọi:

$ ./odoo-bin scaffold Academy my-modules

Điều này sẽ tự động tạo một thư mục mô-đun my-modules * với mô-đun học viện bên trong. Thư mục này có thể là thư mục mô-đun hiện có nếu bạn muốn, nhưng tên mô-đun phải là duy nhất trong thư mục.

Mô-đun trình diễn

Chúng tôi có một mô-đun "hoàn chỉnh" sẵn sàng để cài đặt.

Mặc dù nó hoàn toàn không làm gì nhưng chúng ta có thể cài đặt nó:

  • khởi động máy chủ SoOn

    $ ./odoo-bin --addons-path addons,my-modules
    
  • đi tới http://localhost:8069

  • tạo cơ sở dữ liệu mới bao gồm dữ liệu trình diễn

  • bắt đầu Settings ‣ Modules ‣ Modules

  • ở góc trên bên phải, xóa bộ lọc Đã cài đặt và tìm kiếm học viện

  • nhấp vào nút Install cho mô-đun Academy

Tới trình duyệt

Bộ điều khiển diễn giải các yêu cầu của trình duyệt và gửi dữ liệu trở lại.

Thêm một bộ điều khiển đơn giản và đảm bảo nó được nhập bởi __init__.py (để SoOn có thể tìm thấy nó):

học viện/bộ điều khiển.py
# -*- coding: utf-8 -*-
from odoo import http

class Academy(http.Controller):

    @http.route('/academy/academy/', auth='public')
    def index(self, **kw):
        return "Hello, world"

Tắt máy chủ của bạn (^C) sau đó khởi động lại nó:

$ ./odoo-bin --addons-path addons,my-modules

và mở một trang tới http://localhost:8069/academy/academy/, bạn sẽ thấy "trang" của mình xuất hiện:

../../_images/helloworld.png

Mẫu

Tạo HTML bằng Python không hề dễ chịu chút nào.

Giải pháp thông thường là templates, tài liệu giả có phần giữ chỗ và logic hiển thị. SoOn cho phép bất kỳ hệ thống tạo khuôn mẫu Python nào, nhưng cung cấp hệ thống tạo khuôn mẫu QWeb riêng tích hợp với các tính năng khác.

Tạo một mẫu và đảm bảo tệp mẫu được đăng ký trong tệp kê khai __manifest__.py và thay đổi bộ điều khiển để sử dụng mẫu của chúng tôi:

học viện/bộ điều khiển.py
class Academy(http.Controller):

    @http.route('/academy/academy/', auth='public')
    def index(self, **kw):
        return http.request.render('academy.index', {
            'teachers': ["Diana Padilla", "Jody Caroll", "Lester Vaughn"],
        })
học viện/templates.xml
<odoo>

    <template id="index">
        <title>Academy</title>
        <t t-foreach="teachers" t-as="teacher">
            <p><t t-esc="teacher"/></p>
        </t>
    </template>

</odoo>

Các mẫu lặp lại (t-foreach) trên tất cả các giáo viên (được chuyển qua ngữ cảnh mẫu) và in mỗi giáo viên trong đoạn văn riêng của giáo viên đó.

Cuối cùng khởi động lại SoOn và cập nhật dữ liệu của mô-đun (để cài đặt mẫu) bằng cách đi tới Settings ‣ Modules ‣ Modules ‣ Academy và nhấp vào Upgrade.

Mẹo

Ngoài ra, SoOn có thể được khởi động lại cập nhật các mô-đun cùng lúc:

$ odoo-bin --addons-path addons,my-modules -d academy -u academy

Truy cập http://localhost:8069/academy/academy/ bây giờ sẽ dẫn đến:

../../_images/basic-list.png

Lưu trữ dữ liệu trong SoOn

Mô hình SoOn ánh xạ tới các bảng cơ sở dữ liệu.

Trong phần trước chúng ta vừa hiển thị danh sách chuỗi được nhập tĩnh trong mã Python. Điều này không cho phép sửa đổi hoặc lưu trữ liên tục nên bây giờ chúng tôi sẽ chuyển dữ liệu của mình sang cơ sở dữ liệu.

Xác định mô hình dữ liệu

Xác định mô hình giáo viên và đảm bảo mô hình đó được nhập từ __init__.py để được tải chính xác:

học viện/models.py
from odoo import models, fields, api

class Teachers(models.Model):
    _name = 'academy.teachers'

    name = fields.Char()

Sau đó thiết lập basic access control cho mô hình và thêm chúng vào bảng kê khai:

học viện/__manifest__.py
# always loaded
'data': [
    'security/ir.model.access.csv',
    'templates.xml',
],
học viện/bảo mật/ir.model.access.csv
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_academy_teachers,access_academy_teachers,model_academy_teachers,,1,0,0,0

điều này chỉ đơn giản là cấp quyền truy cập đọc (perm_read) cho tất cả người dùng (group_id:id để trống).

Ghi chú

Các tệp dữ liệu (XML hoặc CSV) phải được thêm vào bảng kê khai mô-đun, các tệp Python (mô hình hoặc bộ điều khiển) không nhưng phải được nhập từ __init__.py (trực tiếp hoặc gián tiếp)

Cảnh báo

người dùng quản trị viên bỏ qua kiểm soát truy cập, họ có quyền truy cập vào tất cả các mô hình ngay cả khi không được cấp quyền truy cập

Dữ liệu trình diễn

Bước thứ hai là thêm một số dữ liệu trình diễn vào hệ thống để có thể kiểm tra dễ dàng. Điều này được thực hiện bằng cách thêm một demo data file, tệp này phải được liên kết từ tệp kê khai:

học viện/demo.xml
<odoo>

    <record id="padilla" model="academy.teachers">
        <field name="name">Diana Padilla</field>
    </record>
    <record id="carroll" model="academy.teachers">
        <field name="name">Jody Carroll</field>
    </record>
    <record id="vaughn" model="academy.teachers">
        <field name="name">Lester Vaughn</field>
    </record>

</odoo>

Mẹo

Tệp dữ liệu có thể được sử dụng cho dữ liệu demo và không phải demo. Dữ liệu demo chỉ được tải ở "chế độ demo" và có thể được sử dụng để kiểm tra và trình diễn luồng, dữ liệu không phải demo luôn được tải và sử dụng làm thiết lập hệ thống ban đầu.

Trong trường hợp này, chúng tôi đang sử dụng dữ liệu trình diễn vì người dùng thực tế của hệ thống muốn nhập hoặc nhập danh sách giáo viên của riêng họ, danh sách này chỉ hữu ích cho việc thử nghiệm.

Truy cập dữ liệu

Bước cuối cùng là thay đổi mô hình và mẫu để sử dụng dữ liệu trình diễn của chúng tôi:

  1. lấy các bản ghi từ cơ sở dữ liệu thay vì có một danh sách tĩnh

  2. Bởi vì search() trả về một tập hợp các bản ghi khớp với bộ lọc ("tất cả các bản ghi" ở đây), hãy thay đổi mẫu để in tên của mỗi giáo viên

học viện/bộ điều khiển.py
class Academy(http.Controller):

     @http.route('/academy/academy/', auth='public')
     def index(self, **kw):
         Teachers = http.request.env['academy.teachers']
         return http.request.render('academy.index', {
             'teachers': Teachers.search([])
         })
học viện/templates.xml
<odoo>

    <template id="index">
         <title>Academy</title>
         <t t-foreach="teachers" t-as="teacher">
             <p><t t-esc="teacher.id"/> <t t-esc="teacher.name"/></p>
         </t>
    </template>

</odoo>

Khởi động lại máy chủ và cập nhật mô-đun (để cập nhật bảng kê khai và mẫu cũng như tải tệp demo), sau đó điều hướng đến http://localhost:8069/academy/academy/. Trang này trông hơi khác một chút: tên chỉ cần được bắt đầu bằng một số (mã định danh cơ sở dữ liệu dành cho giáo viên).

Hỗ trợ trang web

SoOn gói một mô-đun dành riêng cho việc xây dựng trang web.

Cho đến nay, chúng tôi đã sử dụng bộ điều khiển khá trực tiếp, nhưng SoOn 8 đã bổ sung thêm khả năng tích hợp sâu hơn và một số dịch vụ khác (ví dụ: kiểu dáng mặc định, chủ đề) thông qua mô-đun trang web.

  1. đầu tiên, thêm trang web làm phần phụ thuộc vào học viện

  2. sau đó thêm cờ website=True trên bộ điều khiển, điều này sẽ thiết lập một vài biến mới trên đối tượng yêu cầu và cho phép sử dụng bố cục trang web trong mẫu của chúng tôi

  3. sử dụng bố cục trang web trong mẫu

học viện/__manifest__.py
'version': '0.1',

# any module necessary for this one to work correctly
'depends': ['website'],

# always loaded
'data': [
học viện/bộ điều khiển.py
class Academy(http.Controller):

     @http.route('/academy/academy/', auth='public', website=True)
     def index(self, **kw):
         Teachers = http.request.env['academy.teachers']
         return http.request.render('academy.index', {
             'teachers': Teachers.search([])
         })
học viện/templates.xml
<odoo>

    <template id="index">
        <t t-call="website.layout">
            <t t-set="title">Academy</t>
            <div class="oe_structure">
                <div class="container">
                    <t t-foreach="teachers" t-as="teacher">
                        <p><t t-esc="teacher.id"/> <t t-esc="teacher.name"/></p>
                    </t>
                </div>
            </div>
        </t>
    </template>

</odoo>

Sau khi khởi động lại máy chủ trong khi cập nhật mô-đun (để cập nhật bảng kê khai và mẫu), quyền truy cập http://localhost:8069/academy/academy/ sẽ mang lại một trang trông đẹp hơn với nhãn hiệu và một số thành phần trang tích hợp (trên cùng). -trình đơn cấp, chân trang, …)

../../_images/layout1.png

Bố cục trang web cũng hỗ trợ các công cụ chỉnh sửa: nhấp vào Sign In (ở trên cùng bên phải), điền thông tin đăng nhập vào (admin / admin theo mặc định) sau đó nhấp vào :guilabel: Đăng nhập.

Bây giờ bạn đang ở trong SoOn "thích hợp": giao diện quản trị. Bây giờ hãy nhấp vào mục menu Website (góc trên cùng bên trái.

Chúng tôi đã quay lại trang web nhưng với tư cách là quản trị viên, có quyền truy cập vào các tính năng chỉnh sửa nâng cao do bộ phận hỗ trợ trang web cung cấp:

  • một trình soạn thảo mã mẫu (Customize ‣ HTML Editor) nơi bạn có thể xem và chỉnh sửa tất cả các mẫu được sử dụng cho trang hiện tại

  • nút Edit ở phía trên bên trái chuyển sang "chế độ chỉnh sửa" nơi có sẵn các khối (đoạn trích) và chỉnh sửa văn bản đa dạng thức

  • một số tính năng khác như xem trước trên thiết bị di động hoặc SEO

URL và định tuyến

Các phương thức điều khiển được liên kết với routes thông qua trình trang trí route(), trình trang trí này nhận chuỗi định tuyến và một số thuộc tính để tùy chỉnh hành vi hoặc bảo mật của nó.

Chúng tôi đã thấy một chuỗi định tuyến "theo nghĩa đen", khớp chính xác với một phần URL, nhưng các chuỗi định tuyến cũng có thể sử dụng mẫu chuyển đổi khớp với các bit của URL và cung cấp các bit đó dưới dạng biến cục bộ. Chẳng hạn, chúng ta có thể tạo một phương thức điều khiển mới lấy một chút URL và in ra:

học viện/bộ điều khiển.py
# New route
@http.route('/academy/<name>/', auth='public', website=True)
def teacher(self, name):
    return '<h1>{}</h1>'.format(name)

khởi động lại SoOn, truy cập http://localhost:8069/academy/Alice/http://localhost:8069/academy/Bob/ và thấy sự khác biệt.

Như tên đã chỉ ra, mẫu chuyển đổi không chỉ thực hiện trích xuất, chúng còn thực hiện xác thựcchuyển đổi, vì vậy chúng ta có thể thay đổi bộ điều khiển mới để chỉ chấp nhận số nguyên:

học viện/bộ điều khiển.py
@http.route('/academy/<int:id>/', auth='public', website=True)
def teacher(self, id):
    return '<h1>{} ({})</h1>'.format(id, type(id).__name__)

Khởi động lại SoOn, truy cập http://localhost:8069/academy/2, lưu ý giá trị cũ là một chuỗi nhưng giá trị mới đã được chuyển đổi thành số nguyên. Hãy thử truy cập http://localhost:8069/academy/Carol/ và lưu ý rằng không tìm thấy trang: vì "Carol" không phải là số nguyên nên tuyến đường bị bỏ qua và không tìm thấy tuyến đường nào.

SoOn cung cấp một công cụ chuyển đổi bổ sung có tên model cung cấp các bản ghi trực tiếp khi được cung cấp id. Hãy sử dụng điều này để tạo một trang chung cho tiểu sử giáo viên:

học viện/bộ điều khiển.py
@http.route('/academy/<model("academy.teachers"):teacher>/', auth='public', website=True)
def teacher(self, teacher):
    return http.request.render('academy.biography', {
        'person': teacher
    })
học viện/templates.xml
<template id="biography">
    <t t-call="website.layout">
        <t t-set="title">Academy</t>
        <div class="oe_structure"/>
        <div class="oe_structure">
            <div class="container">
                <h3><t t-esc="person.name"/></h3>
            </div>
        </div>
        <div class="oe_structure"/>
    </t>
</template>

sau đó thay đổi danh sách mô hình để liên kết với bộ điều khiển mới của chúng tôi:

học viện/templates.xml
<template id="index">
    <t t-call="website.layout">
        <t t-set="title">Academy</t>
        <div class="oe_structure">
            <div class="container">
                <t t-foreach="teachers" t-as="teacher">
                    <p>
                        <a t-attf-href="/academy/{{ slug(teacher) }}">
                        <t t-esc="teacher.name"/></a>
                    </p>
                </t>
            </div>
        </div>
    </t>
</template>

Khởi động lại SoOn và nâng cấp mô-đun, sau đó bạn có thể truy cập trang của từng giáo viên. Như một bài tập, hãy thử thêm các khối vào trang của một giáo viên để viết tiểu sử, sau đó chuyển đến trang của một giáo viên khác, v.v. Bạn sẽ phát hiện ra rằng tiểu sử của bạn được chia sẻ giữa tất cả các giáo viên vì các khối được thêm vào mẫu và mẫu tiểu sử được chia sẻ giữa tất cả các giáo viên, khi một trang được chỉnh sửa thì tất cả chúng đều được chỉnh sửa cùng một lúc.

Chỉnh sửa trường

Dữ liệu dành riêng cho một bản ghi phải được lưu trên bản ghi đó, vì vậy chúng ta hãy thêm trường tiểu sử mới cho giáo viên của mình:

học viện/models.py
class Teachers(models.Model):
    _name = 'academy.teachers'

    name = fields.Char()
    biography = fields.Html()
học viện/templates.xml
<template id="biography">
    <t t-call="website.layout">
        <t t-set="title">Academy</t>
        <div class="oe_structure"/>
        <div class="oe_structure">
            <div class="container">
                <h3><t t-esc="person.name"/></h3>
                <div><t t-esc="person.biography"/></div>
            </div>
        </div>
        <div class="oe_structure"/>
    </t>
</template>

Khởi động lại SoOn và cập nhật chế độ xem, tải lại trang của giáo viên và… trường này sẽ ẩn vì không chứa gì.

Đối với các trường bản ghi, mẫu có thể sử dụng lệnh t-field đặc biệt cho phép chỉnh sửa nội dung trường từ trang web bằng giao diện dành riêng cho trường. Thay đổi mẫu person để sử dụng t-field:

học viện/templates.xml
<div class="oe_structure">
    <div class="container">
        <h3 t-field="person.name"/>
        <div t-field="person.biography"/>
    </div>
</div>

Khởi động lại SoOn và nâng cấp mô-đun, hiện có một phần giữ chỗ dưới tên giáo viên và một vùng mới cho các khối trong chế độ Edit. Nội dung được thả ở đó sẽ được lưu trữ trong trường tiểu sử của giáo viên tương ứng và do đó dành riêng cho giáo viên đó.

Tên của giáo viên cũng có thể chỉnh sửa được và khi được lưu, thay đổi sẽ hiển thị trên trang mục lục.

t-field cũng có thể có các tùy chọn định dạng phụ thuộc vào trường chính xác. Ví dụ: nếu chúng tôi hiển thị ngày sửa đổi hồ sơ của giáo viên:

học viện/templates.xml
<div class="oe_structure">
    <div class="container">
        <h3 t-field="person.name"/>
        <p>Last modified: <i t-field="person.write_date"/></p>
        <div t-field="person.biography"/>
    </div>
</div>

nó được hiển thị theo cách rất "máy tính" và khó đọc, nhưng chúng ta có thể yêu cầu một phiên bản mà con người có thể đọc được:

học viện/templates.xml
<div class="oe_structure">
    <div class="container">
        <h3 t-field="person.name"/>
        <p>Last modified: <i t-field="person.write_date" t-options='{"format": "long"}'/></p>
        <div t-field="person.biography"/>
    </div>
</div>

hoặc một màn hình tương đối:

học viện/templates.xml
<div class="oe_structure">
    <div class="container">
        <h3 t-field="person.name"/>
        <p>Last modified: <i t-field="person.write_date" t-options='{"widget": "relative"}'/></p>
        <div t-field="person.biography"/>
    </div>
</div>

Tích hợp quản trị và ERP

Giới thiệu ngắn gọn và đầy đủ về quản trị SoOn

Quản trị SoOn được giới thiệu ngắn gọn trong phần hỗ trợ trang web. Chúng ta có thể quay lại bằng cách sử dụng Administrator ‣ Administrator trong menu (hoặc Sign In nếu bạn đã đăng xuất).

Cấu trúc khái niệm của chương trình phụ trợ SoOn rất đơn giản:

  1. đầu tiên là các menu, một cây (menu có thể có menu con) của các bản ghi. Thực đơn không có trẻ em ánh xạ tới…

  2. hành động. Hành động có nhiều loại khác nhau: liên kết, báo cáo, mã mà SoOn sẽ thực thi hoặc hiển thị dữ liệu. Các hành động hiển thị dữ liệu được gọi là hành động cửa sổ và yêu cầu SoOn hiển thị một mô hình nhất định theo một tập hợp các chế độ xem…

  3. một chế độ xem có một loại, một danh mục rộng mà nó tương ứng (danh sách, biểu đồ, lịch) và kiến trúc tùy chỉnh cách hiển thị mô hình bên trong chế độ xem.

Chỉnh sửa trong quản trị SoOn

Theo mặc định, mô hình SoOn về cơ bản là vô hình đối với người dùng. Để làm cho nó hiển thị, nó phải có sẵn thông qua một hành động, bản thân hành động này cần có thể truy cập được, thường là thông qua một menu.

Hãy tạo một menu cho mô hình của chúng tôi:

học viện/__manifest__.py
# always loaded
'data': [
    'security/ir.model.access.csv',
    'templates.xml',
    'views.xml',
],
học viện/views.xml
<odoo>
    <record id="action_academy_teachers" model="ir.actions.act_window">
        <field name="name">Academy teachers</field>
        <field name="res_model">academy.teachers</field>
    </record>

    <menuitem sequence="0" id="menu_academy" name="Academy"/>
    <menuitem id="menu_academy_content" parent="menu_academy"
                name="Academy Content"/>
    <menuitem id="menu_academy_content_teachers"
                parent="menu_academy_content"
                action="action_academy_teachers"/>
</odoo>

sau đó truy cập http://localhost:8069/web/ ở trên cùng bên trái phải là menu Academy, được chọn theo mặc định, vì đây là menu đầu tiên và đã mở danh sách giáo viên. Từ danh sách, bạn có thể Tạo hồ sơ giáo viên mới và chuyển sang chế độ xem theo hồ sơ "biểu mẫu".

Nếu không có định nghĩa về cách trình bày bản ghi (a view), SoOn sẽ tự động tạo một bản ghi cơ bản ngay lập tức. Trong trường hợp của chúng tôi, hiện tại nó hoạt động với chế độ xem "danh sách" (chỉ hiển thị tên giáo viên) nhưng trong chế độ xem "biểu mẫu", trường tiểu sử HTML được hiển thị song song với trường tên và không có đủ không gian. Hãy xác định chế độ xem biểu mẫu tùy chỉnh để giúp việc xem và chỉnh sửa hồ sơ giáo viên trở thành trải nghiệm tốt hơn:

học viện/views.xml
<record id="academy_teacher_form" model="ir.ui.view">
    <field name="name">Academy teachers: form</field>
    <field name="model">academy.teachers</field>
    <field name="arch" type="xml">
        <form>
            <sheet>
                <field name="name"/>
                <field name="biography"/>
            </sheet>
        </form>
    </field>
</record>

Mối quan hệ giữa các mô hình

Chúng tôi đã thấy một cặp trường "cơ bản" được lưu trữ trực tiếp trong bản ghi. Có một số trường cơ bản. Loại trường rộng thứ hai là relational và được sử dụng để liên kết các bản ghi với nhau (trong một mô hình hoặc giữa các mô hình).

Để minh họa, hãy tạo một mô hình courses. Mỗi khóa học phải có trường giáo viên, liên kết với một bản ghi giáo viên duy nhất, nhưng mỗi giáo viên có thể dạy nhiều khóa học:

học viện/models.py
class Courses(models.Model):
    _name = 'academy.courses'

    name = fields.Char()
    teacher_id = fields.Many2one('academy.teachers', string="Teacher")
học viện/bảo mật/ir.model.access.csv
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_academy_teachers,access_academy_teachers,model_academy_teachers,,1,0,0,0
access_academy_courses,access_academy_courses,model_academy_courses,,1,0,0,0

Chúng ta cũng hãy thêm các chế độ xem để chúng ta có thể xem và chỉnh sửa giáo viên của khóa học:

học viện/views.xml
<record id="action_academy_courses" model="ir.actions.act_window">
    <field name="name">Academy courses</field>
    <field name="res_model">academy.courses</field>
</record>
<record id="academy_course_search" model="ir.ui.view">
    <field name="name">Academy courses: search</field>
    <field name="model">academy.courses</field>
    <field name="arch" type="xml">
        <search>
            <field name="name"/>
            <field name="teacher_id"/>
        </search>
    </field>
</record>
<record id="academy_course_list" model="ir.ui.view">
    <field name="name">Academy courses: list</field>
    <field name="model">academy.courses</field>
    <field name="arch" type="xml">
        <tree string="Courses">
            <field name="name"/>
            <field name="teacher_id"/>
        </tree>
    </field>
</record>
<record id="academy_course_form" model="ir.ui.view">
    <field name="name">Academy courses: form</field>
    <field name="model">academy.courses</field>
    <field name="arch" type="xml">
        <form>
            <sheet>
                <field name="name"/>
                <field name="teacher_id"/>
            </sheet>
        </form>
    </field>
</record>

<menuitem sequence="0" id="menu_academy" name="Academy"/>
<menuitem id="menu_academy_content" parent="menu_academy"
            name="Academy Content"/>
<menuitem id="menu_academy_content_courses"
            parent="menu_academy_content"
            action="action_academy_courses"/>
<menuitem id="menu_academy_content_teachers"
            parent="menu_academy_content"
            action="action_academy_teachers"/>

Bạn cũng có thể tạo các khóa học mới trực tiếp từ trang của giáo viên hoặc xem tất cả các khóa học họ dạy, vì vậy hãy thêm mối quan hệ nghịch đảo vào mô hình teachers:

học viện/models.py
class Teachers(models.Model):
    _name = 'academy.teachers'

    name = fields.Char()
    biography = fields.Html()

    course_ids = fields.One2many('academy.courses', 'teacher_id', string="Courses")

class Courses(models.Model):
    _name = 'academy.courses'

    name = fields.Char()
    teacher_id = fields.Many2one('academy.teachers', string="Teacher")
học viện/views.xml
<record id="academy_teacher_form" model="ir.ui.view">
    <field name="name">Academy teachers: form</field>
    <field name="model">academy.teachers</field>
    <field name="arch" type="xml">
        <form>
            <sheet>
                <field name="name"/>
                <field name="biography"/>
                <field name="course_ids">
                    <tree Sstring="Courses" editable="bottom">
                        <field name="name"/>
                    </tree>
                </field>
            </sheet>
        </form>
    </field>
</record>

Thảo luận và thông báo

SoOn cung cấp các mô hình kỹ thuật không trực tiếp đáp ứng nhu cầu kinh doanh nhưng bổ sung khả năng cho các đối tượng kinh doanh mà không cần phải xây dựng chúng bằng tay.

Một trong số đó là hệ thống Chatter, một phần của hệ thống nhắn tin và email của SoOn, có thể thêm thông báo và chuỗi thảo luận vào bất kỳ mô hình nào. Mô hình chỉ cần _inherit mail.thread và thêm trường message_ids vào chế độ xem biểu mẫu để hiển thị chuỗi thảo luận. Chủ đề thảo luận được thực hiện trên mỗi bản ghi.

Đối với học viện của chúng tôi, việc cho phép các khóa học thảo luận xử lý các vấn đề, ví dụ: là hợp lý. lên lịch thay đổi hoặc thảo luận giữa giáo viên và trợ lý:

học viện/__manifest__.py
'version': '0.1',

# any module necessary for this one to work correctly
'depends': ['website', 'mail'],

# always loaded
'data': [
học viện/models.py
class Courses(models.Model):
    _name = 'academy.courses'
    _inherit = 'mail.thread'

    name = fields.Char()
    teacher_id = fields.Many2one('academy.teachers', string="Teacher")
học viện/views.xml
<record id="academy_course_form" model="ir.ui.view">
    <field name="name">Academy courses: form</field>
    <field name="model">academy.courses</field>
    <field name="arch" type="xml">
        <form>
            <sheet>
                <field name="name"/>
                <field name="teacher_id"/>
            </sheet>
            <div class="oe_chatter">
                <field name="message_follower_ids" widget="mail_followers"/>
                <field name="message_ids" widget="mail_thread"/>
            </div>
        </form>
    </field>
</record>

Ở cuối mỗi biểu mẫu khóa học, hiện có một chuỗi thảo luận và người dùng hệ thống có thể để lại tin nhắn và theo dõi hoặc hủy theo dõi các cuộc thảo luận được liên kết với các khóa học cụ thể.

Bán khóa học

SoOn cũng cung cấp các mô hình kinh doanh cho phép sử dụng hoặc lựa chọn các nhu cầu kinh doanh một cách trực tiếp hơn. Ví dụ: mô-đun website_sale thiết lập một trang web thương mại điện tử dựa trên các sản phẩm trong hệ thống SoOn. Chúng tôi có thể dễ dàng bán được các gói đăng ký khóa học bằng cách cung cấp các loại sản phẩm cụ thể cho khóa học của mình.

Thay vì kế thừa cổ điển trước đó, điều này có nghĩa là thay thế mô hình khóa học của chúng tôi bằng mô hình sản phẩm và mở rộng các sản phẩm tại chỗ (để thêm bất kỳ thứ gì chúng tôi cần vào đó).

Trước hết chúng ta cần thêm một phụ thuộc vào website_sale để có được cả hai sản phẩm (thông qua sale) và giao diện thương mại điện tử:

học viện/__manifest__.py
'version': '0.1',

# any module necessary for this one to work correctly
'depends': ['mail', 'website_sale'],

# always loaded
'data': [

khởi động lại SoOn, cập nhật mô-đun của bạn, hiện có phần Shop trên trang web, liệt kê một số sản phẩm được điền sẵn (thông qua dữ liệu minh họa).

Bước thứ hai là thay thế mô hình courses bằng product.template và thêm danh mục sản phẩm mới cho các khóa học:

học viện/__manifest__.py
    'security/ir.model.access.csv',
    'templates.xml',
    'views.xml',
    'data.xml',
],
# only loaded in demonstration mode
'demo': [
học viện/data.xml
<odoo>
    <record model="product.public.category" id="category_courses">
        <field name="name">Courses</field>
        <field name="parent_id" ref="website_sale.categ_others"/>
    </record>
</odoo>
học viện/demo.xml
<record id="course0" model="product.template">
    <field name="name">Course 0</field>
    <field name="teacher_id" ref="padilla"/>
    <field name="public_categ_ids" eval="[(4, ref('academy.category_courses'), False)]"/>
    <field name="website_published">True</field>
    <field name="list_price" type="float">0</field>
    <field name="type">service</field>
</record>
<record id="course1" model="product.template">
    <field name="name">Course 1</field>
    <field name="teacher_id" ref="padilla"/>
    <field name="public_categ_ids" eval="[(4, ref('academy.category_courses'), False)]"/>
    <field name="website_published">True</field>
    <field name="list_price" type="float">0</field>
    <field name="type">service</field>
</record>
<record id="course2" model="product.template">
    <field name="name">Course 2</field>
    <field name="teacher_id" ref="vaughn"/>
    <field name="public_categ_ids" eval="[(4, ref('academy.category_courses'), False)]"/>
    <field name="website_published">True</field>
    <field name="list_price" type="float">0</field>
    <field name="type">service</field>
</record>
học viện/models.py
class Courses(models.Model):
    _name = 'academy.courses'
    _inherit = ['mail.thread', 'product.template']

    name = fields.Char()
    teacher_id = fields.Many2one('academy.teachers', string="Teacher")

Với cài đặt này, một số khóa học hiện có sẵn trong Shop, mặc dù bạn có thể phải tìm kiếm chúng.

Ghi chú

  • để mở rộng một mô hình tại chỗ, đó là inherited mà không cấp cho nó một _name mới

  • product.template đã sử dụng hệ thống thảo luận nên chúng tôi có thể xóa nó khỏi mô hình tiện ích mở rộng của mình

  • theo mặc định, chúng tôi đang tạo các khóa học của mình dưới dạng đã xuất bản để có thể xem được mà không cần phải đăng nhập

Thay đổi chế độ xem hiện có

Cho đến nay, chúng ta đã thấy ngắn gọn:

  • việc tạo ra các mô hình mới

  • việc tạo ra các quan điểm mới

  • việc tạo ra các kỷ lục mới

  • sự thay đổi của các mô hình hiện có

Chúng ta chỉ còn lại việc thay đổi các hồ sơ hiện có và thay đổi các quan điểm hiện có. Chúng tôi sẽ thực hiện cả hai việc trên trang Shop.

Việc thay đổi chế độ xem được thực hiện bằng cách tạo các chế độ xem tiện ích, được áp dụng lên trên chế độ xem ban đầu và thay đổi nó. Những chế độ xem thay đổi này có thể được thêm hoặc xóa mà không cần sửa đổi bản gốc, giúp việc thử mọi thứ và khôi phục các thay đổi trở lại dễ dàng hơn.

Vì các khóa học của chúng tôi là miễn phí nên không có lý do gì để hiển thị giá của chúng trên trang cửa hàng, vì vậy chúng tôi sẽ thay đổi chế độ xem và ẩn giá nếu nó bằng 0. Nhiệm vụ đầu tiên là tìm ra chế độ xem nào hiển thị giá, điều này có thể được thực hiện thông qua Customize ‣ HTML Editor cho phép chúng ta đọc các mẫu khác nhau liên quan đến việc hiển thị một trang. Xem qua một vài trong số đó, "Sản phẩm" có vẻ là thủ phạm.

Việc thay đổi kiến trúc khung nhìn được thực hiện theo 3 bước:

  1. Tạo chế độ xem mới

  2. Mở rộng chế độ xem cần sửa đổi bằng cách đặt inherit_id của chế độ xem mới thành id bên ngoài của chế độ xem đã sửa đổi

  3. Trong kiến trúc, sử dụng thẻ xpath để chọn và thay đổi các thành phần từ chế độ xem đã sửa đổi

học viện/templates.xml
 <template id="product_item_hide_no_price" inherit_id="website_sale.products_item">
     <xpath expr="//div[hasclass('product_price')]/b" position="attributes">
         <attribute name="t-if">product.price &gt; 0</attribute>
     </xpath>
 </template>

Điều thứ hai chúng tôi sẽ thay đổi là làm cho thanh bên danh mục sản phẩm hiển thị theo mặc định: Customize ‣ Product Category cho phép bạn bật và tắt một cây danh mục sản phẩm (được sử dụng để lọc màn hình chính).

Việc này được thực hiện thông qua các trường customize_showactive của các mẫu tiện ích mở rộng: một mẫu tiện ích mở rộng (chẳng hạn như mẫu chúng tôi vừa tạo) có thể là customize_show=True. Lựa chọn này sẽ hiển thị chế độ xem trong menu Customize bằng một hộp kiểm, cho phép quản trị viên kích hoạt hoặc vô hiệu hóa chúng (và dễ dàng tùy chỉnh các trang web của họ).

Chúng ta chỉ cần sửa đổi bản ghi Danh mục sản phẩm và đặt mặc định thành active="True":

học viện/templates.xml
<record id="website_sale.products_categories" model="ir.ui.view">
    <field name="active" eval="True"/>
</record>

Với điều này, thanh bên Danh mục sản phẩm sẽ tự động được bật khi mô-đun Học viện được cài đặt.