本教程的目标是介绍框架的各个组成部分。
我们在这里只是浅尝辄止。Frappe 框架拥有
更多功能,使我们能够构建诸如
ERPNext 之类的复杂软件。
您可以通过阅读其余文档来深入了解各个主题。
以下是一些入门主题供您参考:
- 架构
- DocType(文档类型)
- 文档 API
- 表单 API
- Bench 命令行工具
需要帮助?
您可以在我们的公共论坛上寻求帮助:discuss.frappe.io
本教程的目标是介绍框架的各个组成部分。
我们在这里只是浅尝辄止。Frappe 框架拥有
更多功能,使我们能够构建诸如
ERPNext 之类的复杂软件。
您可以通过阅读其余文档来深入了解各个主题。
以下是一些入门主题供您参考:
您可以在我们的公共论坛上寻求帮助:discuss.frappe.io
表单脚本是客户端 JavaScript 代码,用于增强表单的用户体验。
假设你想为会员创建一条会员资格记录。为此,你需要
前往“图书馆会员”列表,创建一个新表单,选择会员并填写
其他字段,然后保存。
同样,当你想针对某位会员创建一笔交易时,你需要
新建一个“图书馆交易”表单。
我们可以让这个过程变得更简单。在 library_member.js 中编写以下代码:
frappe.ui.form.on('Library Member', {
refresh: function(frm) {
frm.add_custom_button('Create Membership', () => {
frappe.new_doc('Library Membership', {
library_member: frm.doc.name
})
})
frm.add_custom_button('Create Transaction', () => {
frappe.new_doc('Library Transaction', {
library_member: frm.doc.name
})
})
}
});
现在,刷新页面并前往“图书馆会员”表单。你应该会在右上角看到两个按钮。
点击它们试试看。它们会自动在这些文档中设置
图书馆会员,从而简化操作流程。
这里我们只是浅尝辄止。使用表单脚本,你还可以做更多事情。
在“表单脚本 API”中了解更多关于 API 的信息。
下一步:门户页面
Single DocType is a special type of DocType that stores only one record. It is useful for storing settings or configuration values that are global to the application. The data is stored in a single row in the database, and the form is always available for editing.
Now, let’s write code to use the Library Settings in our validations. We will
update the Library Transaction validation to check the loan period and
maximum number of issued articles.
library_transaction.py
from frappe.model.document import Document
from frappe.model.docstatus import DocStatus
import frappe
class LibraryMembership(Document):
# check before submitting this document
def before_submit(self):
exists = frappe.db.exists(
"Library Membership",
{
"library_member": self.library_member,
"docstatus": DocStatus.submitted(),
# check if the membership's end date is later than this membership's start date
"to_date": (">", self.from_date),
},
)
if exists:
frappe.throw("There is an active membership for this member")
# get loan period and compute to_date by adding loan_period to from_date
loan_period = frappe.db.get_single_value("Library Settings", "loan_period")
self.to_date = frappe.utils.add_days(self.from_date, loan_period or 30)
We used the tabSingles method to get the Library Settings record. Since it
is a Single DocType, we can directly access its fields. We also used thefrappe.db.get_single_value method to count the number of issued articles for the member.
We also need to update the Library Membership validation to use the Library
Settings for the loan period.
library_membership.py
import frappe
from frappe.model.document import Document
from frappe.model.docstatus import DocStatus
class LibraryTransaction(Document):
def before_submit(self):
if self.type == "Issue":
self.validate_issue()
self.validate_maximum_limit()
# set the article status to be Issued
article = frappe.get_doc("Article", self.article)
article.status = "Issued"
article.save()
elif self.type == "Return":
self.validate_return()
# set the article status to be Available
article = frappe.get_doc("Article", self.article)
article.status = "Available"
article.save()
def validate_issue(self):
self.validate_membership()
article = frappe.get_doc("Article", self.article)
# article cannot be issued if it is already issued
if article.status == "Issued":
frappe.throw("Article is already issued by another member")
def validate_return(self):
article = frappe.get_doc("Article", self.article)
# article cannot be returned if it is not issued first
if article.status == "Available":
frappe.throw("Article cannot be returned without being issued first")
def validate_maximum_limit(self):
max_articles = frappe.db.get_single_value("Library Settings", "max_articles")
count = frappe.db.count(
"Library Transaction",
{
"library_member": self.library_member,
"type": "Issue",
"docstatus": DocStatus.submitted(),
},
)
if count >= max_articles:
frappe.throw("Maximum limit reached for issuing articles")
def validate_membership(self):
# check if a valid membership exist for this library member
valid_membership = frappe.db.exists(
"Library Membership",
{
"library_member": self.library_member,
"docstatus": DocStatus.submitted(),
"from_date": ("<", self.date),
"to_date": (">", self.date),
},
)
if not valid_membership:
frappe.throw("The member does not have a valid membership")
Now, when you create a Library Membership, the loan period will be automatically
set based on the Library Settings.
In this tutorial, we learned about different types of doctypes in the framework:
We also learned how to use Link fields to connect records, fetch values from
linked records, and write validations for our doctypes.
tabSingles 的表中。它通常用于存储全局设置。
让我们对“库会员”进行修改,使得“截止日期”自动
根据“借阅期限”和“起始日期”计算得出。
library_membership.py
from frappe.model.document import Document
from frappe.model.docstatus import DocStatus
import frappe
class LibraryMembership(Document):
# check before submitting this document
def before_submit(self):
exists = frappe.db.exists(
"Library Membership",
{
"library_member": self.library_member,
"docstatus": DocStatus.submitted(),
# check if the membership's end date is later than this membership's start date
"to_date": (">", self.from_date),
},
)
if exists:
frappe.throw("There is an active membership for this member")
# get loan period and compute to_date by adding loan_period to from_date
loan_period = frappe.db.get_single_value("Library Settings", "loan_period")
self.to_date = frappe.utils.add_days(self.from_date, loan_period or 30)
我们使用了 frappe.db.get_single_value 方法来获取
“库设置”文档类型中的 loan_period 值。
现在,让我们对“库事务”进行修改,使得当文章被
“借出”时,它会检查是否达到了最大限制。
library_transaction.py
import frappe
from frappe.model.document import Document
from frappe.model.docstatus import DocStatus
class LibraryTransaction(Document):
def before_submit(self):
if self.type == "Issue":
self.validate_issue()
self.validate_maximum_limit()
# set the article status to be Issued
article = frappe.get_doc("Article", self.article)
article.status = "Issued"
article.save()
elif self.type == "Return":
self.validate_return()
# set the article status to be Available
article = frappe.get_doc("Article", self.article)
article.status = "Available"
article.save()
def validate_issue(self):
self.validate_membership()
article = frappe.get_doc("Article", self.article)
# article cannot be issued if it is already issued
if article.status == "Issued":
frappe.throw("Article is already issued by another member")
def validate_return(self):
article = frappe.get_doc("Article", self.article)
# article cannot be returned if it is not issued first
if article.status == "Available":
frappe.throw("Article cannot be returned without being issued first")
def validate_maximum_limit(self):
max_articles = frappe.db.get_single_value("Library Settings", "max_articles")
count = frappe.db.count(
"Library Transaction",
{
"library_member": self.library_member,
"type": "Issue",
"docstatus": DocStatus.submitted(),
},
)
if count >= max_articles:
frappe.throw("Maximum limit reached for issuing articles")
def validate_membership(self):
# check if a valid membership exist for this library member
valid_membership = frappe.db.exists(
"Library Membership",
{
"library_member": self.library_member,
"docstatus": DocStatus.submitted(),
"from_date": ("<", self.date),
"to_date": (">", self.date),
},
)
if not valid_membership:
frappe.throw("The member does not have a valid membership")
我们添加了一个 validate_maximum_limit 方法,并使用 frappe.db.count 来统计
该会员进行的交易次数。
至此,我们已经涵盖了文档类型创建的基础知识和文档类型的种类。
我们还为各种文档类型编写了业务逻辑。
干得好,坚持到了这里。让我们继续前进。
下一步:表单脚本
控制器方法允许您在文档的生命周期内编写业务逻辑。
让我们创建第二个文档类型:图书馆会员。它将包含以下字段:
创建文档类型后,前往图书馆会员列表,从 设置 > 重新加载 清除缓存,然后创建一个新的图书馆会员。
如果您注意到,表单中没有显示“全名”字段。这是因为我们将其设置为只读。只有当它有值时才会显示。
让我们在 Python 控制器类中编写代码,使“全名”能够根据“名字”和“姓氏”自动计算。
打开您的代码编辑器,打开文件 library_member.py 并进行以下更改:
librarymember.py
class LibraryMember(Document):
#this method will run every time a document is saved
def before_save(self):
self.full_name = f'{self.first_name} {self.last_name or ""}'
注意
如果上述代码片段对您不起作用,请确保已启用服务器端脚本,然后重新启动 bench
bench set-config -g server_script_enabled true
我们在 before_save 方法中编写了逻辑,该方法在每次保存文档时运行。这是 Document 类提供的众多钩子之一。您可以在控制器文档中了解所有可用钩子的更多信息。
现在,返回并创建另一个图书馆会员,保存后即可看到“全名”显示出来。
下一步:DocType 的类型
在上一章中,我们创建了 Article 文档类型。让我们看看还有哪些功能可以自定义。
如果你使用表单创建了文档,你可能会注意到文档的 name 值是一个随机生成的哈希值。让我们做一个更改,使我们提供的 Article Name 成为文档的 name。
为此,请从搜索栏打开文档类型列表,然后点击 Article。现在,向下滚动到 Naming 部分,在 Auto Name 字段中输入 field:article_name。点击 Save。
现在,返回 Article 列表并再次创建一篇新文章。
现在,文档的 name 将是 Article Name,并且它在所有文章中必须是唯一的。因此,你不能创建另一篇具有相同名称的文章。
你也可以通过在 mariadb 控制台中运行 select 查询来检查数据库记录。
MariaDB [_ad03fa1a016ca1c4]> select * from tabArticle;
| ------------ | ---------------------------- | ---------------------------- | --------------- | --------------- | ----------- | -------- | ------- |
| name | creation | modified | modified_by | owner | docstatus | parent | parent
| ------------ | ---------------------------- | ---------------------------- | --------------- | --------------- | ----------- | -------- | ------- |
| bd514646b9 | 2020-10-10 16:24:43.033457 | 2020-10-10 16:24:43.033457 | Administrator | Administrator | 0 | NULL | NULL
| Catch 22 | 2020-10-10 16:41:49.734499 | 2020-10-10 16:41:49.734499 | Administrator | Administrator | 0 | NULL | NULL
| ------------ | ---------------------------- | ---------------------------- | --------------- | --------------- | ----------- | -------- | ------- |
了解更多关于 DocType 命名的不同类型。
让我们自定义表单中字段的布局方式,同时充分利用可用空间。转到 Article 文档类型,滚动到 Fields 部分,并添加两个新字段,类型分别为 Column Break 和 Section Break。我们还将隐藏 Image 字段,因为它不需要在表单中显示。查看 GIF 以了解具体操作。
表单设置
转到 Article 文档类型并向下滚动到 Form Settings 部分。在 Image Field 字段中输入 image。这将在表单的左上角显示图像。你还可以启用 Allow Rename 以允许重命名文档。
你还可以配置要为 DocType 允许哪些角色,以及要限制哪些操作。转到 Article 文档类型,向下滚动到 Permission Rules 部分,并添加角色。
你还可以配置允许特定角色执行的操作类型。让我们添加一个 Librarian 角色,该角色拥有所有操作的权限,以及一个 Library Member 角色,该角色拥有 Read 操作的权限。
你可以通过创建一个具有 Librarian 角色的新用户,以及另一个具有 Library Member 角色的新用户来测试这一点。分别使用每个用户登录,查看允许哪些操作。
下一步:控制器方法
DocType 类似于其他框架中的 Model(模型)。除了定义属性外,它还定义了模型的行为。
在创建 DocType 之前,我们需要在 bench 上启用开发者模式。这将允许我们在创建 DocType 时生成样板代码,并且我们可以通过应用将这些代码纳入版本控制。
打开终端,如果 bench 服务器已经在运行,请先停止它,然后从 frappe-bench 目录运行以下命令:
bench set-config -g developer_mode true
bench start
在 Desk 中,使用 Awesomebar 导航到 DocType 列表。此列表将包含框架自带的 DocType、已安装的 Frappe 应用中的 DocType,以及您可以为每个站点创建的自定义 DocType。
我们要创建的第一个 DocType 是 Article。要创建它,请点击“新建”。
请参考以下 GIF 了解具体操作步骤:
添加完字段后,点击“保存”。
您会在表单右上角看到一个 前往 Article 列表 按钮。点击它进入 Article 列表。这里您会看到一个空列表,因为表中还没有记录。
让我们创建一些记录。但在此之前,我们需要清除 Desk 缓存。点击导航栏右侧的 设置 下拉菜单,然后点击 重新加载。
现在,您应该能看到 新建 按钮。点击它,您将看到 Article DocType 的表单视图。填写表单并点击“保存”。您就创建了第一个 Article 文档。返回列表视图,您应该能看到一条记录。
1. 数据库表
系统创建了一个名为 tabArticle 的数据库表,其中包含我们在字段表中指定的字段。您可以通过 MariaDB 控制台检查来确认这一点。
bench --site library.localhost mariadb
Welcome to the MariaDB monitor. Commands end with ; or \g.
Your MariaDB connection id is 2445938
Server version: 10.4.13-MariaDB Homebrew
Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
MariaDB [_ad03fa1a016ca1c4]> desc tabArticle;
+--------------+--------------+------+-----+-----------+-------+
| Field | Type | Null | Key | Default | Extra |
+--------------+--------------+------+-----+-----------+-------+
| name | varchar(140) | NO | PRI | NULL | |
| creation | datetime(6) | YES | | NULL | |
| modified | datetime(6) | YES | MUL | NULL | |
| modified_by | varchar(140) | YES | | NULL | |
| owner | varchar(140) | YES | | NULL | |
| docstatus | int(1) | NO | | 0 | |
| parent | varchar(140) | YES | MUL | NULL | |
| parentfield | varchar(140) | YES | | NULL | |
| parenttype | varchar(140) | YES | | NULL | |
| idx | int(8) | NO | | 0 | |
| article_name | varchar(140) | YES | | NULL | |
| image | text | YES | | NULL | |
| author | varchar(140) | YES | | NULL | |
| description | longtext | YES | | NULL | |
| isbn | varchar(140) | YES | | NULL | |
| status | varchar(140) | YES | | Available | |
| publisher | varchar(140) | YES | | NULL | |
| _user_tags | text | YES | | NULL | |
| _comments | text | YES | | NULL | |
| _assign | text | YES | | NULL | |
| _liked_by | text | YES | | NULL | |
+--------------+--------------+------+-----+-----------+-------+
21 rows in set (0.002 sec)
MariaDB [_ad03fa1a016ca1c4]>
我们以标题格式(Title Case)指定的字段会自动转换为小写蛇形命名(snake case),并用作表中的列名。例如,article_name、image、author 和 description。
此外,还创建了许多其他字段,如 name、creation、modified、modified_by。这些是所有 DocType 都会创建的标准字段。name 是主键列。
如果您通过表单创建了一条记录,您也可以运行标准的 SELECT 查询来获取这些行。
MariaDB [_ad03fa1a016ca1c4]> select * from tabArticle;
+------------+----------------------------+----------------------------+---------------+---------------+-----------+--------+-------------+------------+-----+-----------------------------+--
| name | creation | modified | modified_by | owner | docstatus | parent | parentfield | parenttype | idx | article_name | i
+------------+----------------------------+----------------------------+---------------+---------------+-----------+--------+-------------+------------+-----+-----------------------------+--
| bd514646b9 | 2020-10-10 16:24:43.033457 | 2020-10-10 16:24:43.033457 | Administrator | Administrator | 0 | NULL | NULL | NULL | 0 | The Girl with all the Gifts | N
+------------+----------------------------+----------------------------+---------------+---------------+-----------+--------+-------------+------------+-----+-----------------------------+--
MariaDB [_ad03fa1a016ca1c4]>
2. Desk 视图
系统还为我们的 DocType 创建了许多视图。Article 列表是显示数据库表记录的列表视图。表单视图是您创建新文档或查看现有文档时显示的视图。
3. 表单布局
如果您留意,表单中的字段布局是按照您在字段表中的排序方式排列的。例如,Article Name 是第一个字段,其次是 Image,然后是 Author。在教程的后续部分,我们将学习如何进一步自定义此布局。
4. 样板代码
注意
请确保在 DocType 配置中取消勾选“自定义?”复选框。否则,下面讨论的文件将不会生成。此处有相关解释。
如果您查看应用中的更改,应该会发现创建了许多文件。打开终端,从 frappe-bench 目录运行以下命令。
$ cd apps/library_management
$ git status -u
On branch master
Untracked files:
(use "git add
<file>..." to include in what will be committed)
library_management/library_management/doctype/__init__.py
library_management/library_management/doctype/article/__init__.py
library_management/library_management/doctype/article/article.js
library_management/library_management/doctype/article/article.json
library_management/library_management/doctype/article/article.py
library_management/library_management/doctype/article/test_article.py
nothing added to commit but untracked files present (use "git add" to track)
</file>
article.json – 定义 DocType 属性的 JSON 文件
article.js – 表单视图的客户端控制器
article.py – Article 的 Python 控制器
test_article.py – 用于编写测试的 Python 单元测试样板文件
如您所见,DocType 描述了模型的很多信息。它不仅定义了表和列名,还定义了它在 Desk 中各种视图中的呈现方式。
到目前为止,您很好地跟上了教程。让我们继续!
下一步:DocType 功能
每个站点都附带一个数据库。您可以通过特定于站点的脚本对其进行自定义,或者在其上安装应用。
要创建新站点,请在 frappe-bench 目录下运行以下命令:
$ bench new-site library.localhost
MySQL root password:
Installing frappe...
Updating DocTypes for frappe : [========================================] 100%
Set Administrator password:
*** Scheduler is disabled ***
Current Site set to library.localhost
此命令将创建一个新数据库,因此您需要输入 MariaDB 的 root 密码。它还会要求您为管理员用户设置密码,请设置一个您不会忘记的密码。这将在以后派上用场。
现在,您将在 sites 目录下拥有一个名为 library.localhost 的新文件夹。
如果站点创建因任何原因失败,系统会提示您回滚更改。这将删除您站点目录中的 library.localhost 或等效文件,并删除已创建的数据库/用户。这样您就可以轻松重试,而无需手动清理不可用的站点。
站点目录结构大致如下:
sites/library.localhost
├── indexes
│ └── web_routes
├── locks
├── logs
├── private
│ ├── backups
│ └── files
├── public
│ └── files
└── site_config.json
indexes 文件夹包含通过网站搜索生成的索引。
locks 文件夹维护站点内文档的基于文件的锁,以及站点自身状态的指示器。
如您所见,private 文件夹将包含所有数据库备份和私有文件。私有文件是需要身份验证才能访问的用户上传文件。
public 文件夹将包含无需身份验证即可访问的文件。其中可以包含无需登录即可访问的网站图片。
site_config.json 文件包含特定于此站点且不应进行版本控制的配置。这类似于环境变量文件。如果您查看该文件的内容,会发现其中包含此站点的数据库配置值。
{
"db_name": "_ad03fa1a016ca1c4",
"db_password": "pz1d2gN5y35ydRO5",
"db_type": "mariadb"
}
bench 允许您创建多个站点,并在浏览器中通过同一端口分别访问它们。这就是我们在 bench 中所说的多租户支持。
Frappe 将通过将请求的主机名与站点名称进行匹配来确定要提供哪个站点,因此您应该能够通过 http://library.localhost:8000 访问您的站点。
如果您的站点名称不以 .localhost 结尾,则此方法无法直接为您工作,因为您必须告诉操作系统 site_name 应指向 localhost。为此,您可以将以下条目添加到您的 /etc/hosts 文件中。
127.0.0.1 site_name
这会将 library.localhost 映射到 localhost。Bench 有一个便捷命令可以完成此操作。
$ bench --site site_name add-to-hosts
这将要求您输入 root 密码,并向您的 /etc/hosts 文件添加一个条目。
太棒了,现在您可以在 http://library.localhost:8000 访问您的站点。恭喜您走到了这一步。
要在我们的站点上安装我们的图书馆管理应用,请运行以下命令:
$ bench --site library.localhost install-app library_management
Installing library_management...
要确认应用是否已安装,请运行以下命令:
$ bench --site library.localhost list-apps
frappe
library_management
您应该会看到 frappe 和 library_management 已作为已安装的应用出现在您的站点上。
当您创建新站点时,
frappe应用会默认安装。
在继续以下操作之前,请确保站点处于开发者模式。为确保这一点,请在您的站点中运行以下命令
bench set-config -g developer_mode 1然后使用
bench start命令重启 bench
要在我们的应用中创建 DocType,我们必须登录 Desk。转到 http://library.localhost:8000,它应该会向您显示一个登录页面。
输入 Administrator 作为用户,并输入您在创建站点时设置的密码。
成功登录后,您将看到设置向导。这是一次性的设置向导,用于为您的站点设置本地化详细信息。请继续,选择您的语言,并完成向导。
干得好,您已经走到了这一步!
您应该会看到类似这样的 Desk:
我们使用 --site 选项运行了几个 bench 命令。这些命令被称为站点命令。
以下是一些有用的站点命令。
Python 控制台
# access the python console
$ bench --site library.localhost console
Apps in this namespace:
frappe, library_management
In [1]:
MariaDB 控制台
# access the mariadb console
$ bench --site library.localhost mariadb
Welcome to the MariaDB monitor. Commands end with ; or \g.
Your MariaDB connection id is 2333498
Server version: 10.4.13-MariaDB Homebrew
Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
MariaDB [_ad03fa1a016ca1c4]>
数据库备份
$ bench --site library.localhost backup
Backup Summary for library.localhost at 2020-10-06 23:21:17.277960
Config : ./library.localhost/private/backups/20201006_232116-library_test-site_config_backup.json 94.0B
Database: ./library.localhost/private/backups/20201006_232116-library_test-database.sql.gz 217.4KiB
Backup for Site library.localhost has been successfully completed
您可以通过运行以下命令查看所有站点命令的列表:
$ bench --help
Usage: bench frappe [OPTIONS] COMMAND [ARGS]...
Options:
--site TEXT
--profile Profile
--verbose Verbose
--force Force
--help Show this message and exit.
Commands:
add-system-manager Add a new system manager to a site
add-to-email-queue Add an email to the Email Queue
add-to-hosts Add site to hosts
backup Backup
browse Opens the site on web browser
build Minify + concatenate JS and CSS files, build...
build-message-files Build message files for translation
build-search-index
bulk-rename Rename multiple records via CSV file
clear-cache Clear cache, doctype cache and defaults
clear-website-cache Clear website cache
console Start ipython console for a site
data-import Import documents in bulk from CSV or XLSX...
destroy-all-sessions Clear sessions of all users (logs them out)
下一步:创建 DocType
使用 bench 命令行工具创建一个 Frappe 应用脚手架。
在开始之前,请确保你位于 bench 目录中。要确认这一点,请运行 bench find .:
$ bench find .
/home/frappe/frappe-bench is a bench directory!
要创建我们的图书馆管理应用,请运行 new-app 命令:
bench new-app library_management
你会看到一些提示和类似下面的输出。你可以手动输入信息,或者直接按回车选择默认值。
App Title (default: Library Management):
App Description: Library Management System
App Publisher: Faris Ansari
App Email: [email protected]
App Icon (default 'octicon octicon-file-directory'):
App Color (default 'grey'):
App License (default 'MIT'):
'library_management' created at /home/frappe/frappe-bench/apps/library_management
Installing library_management
$ ./env/bin/pip install -q -U -e ./apps/library_management
$ bench build --app library_management
yarn run v1.22.4
$ FRAPPE_ENV=production node rollup/build.js --app library_management
Production mode
✔ Built js/moment-bundle.min.js
✔ Built js/libs.min.js
✨ Done in 1.95s.
系统会提示你填写应用的相关信息,填写完成后,一个名为 library_management 的应用将在 apps 文件夹中创建。
要查看 octicons 图标库中所有支持的图标完整列表,请访问 https://primer.style/octicons/
你的应用目录结构应该类似于这样:
apps/library_management
├── README.md
├── library_management
│ ├── hooks.py
│ ├── library_management
│ │ └── __init__.py
│ ├── modules.txt
│ ├── patches.txt
│ ├── public
│ │ ├── css
│ │ └── js
│ ├── templates
│ │ ├── __init__.py
│ │ ├── includes
│ │ └── pages
│ │ └── __init__.py
│ └── www
└── pyproject.toml
library_management: 此目录将包含你应用的所有源代码
下一步:创建站点
Bench 是用于管理 Frappe 应用和站点的命令行工具。
如果你还没有安装 Bench,请按照安装指南进行操作。安装完成后,你应该能够运行以 bench 开头的命令。
运行以下命令来测试你的安装是否成功:
$ bench --version
5.1.0
让我们创建项目文件夹,它将包含我们的应用和站点。运行以下命令:
$ bench init frappe-bench
这将在你当前的工作目录中创建一个名为 frappe-bench 的目录。它将执行以下操作:
env 目录下创建一个 Python 虚拟环境。frappe 应用作为 Python 包。frappe 的 node 模块。.
├── Procfile
├── apps
│ └── frappe
├── config
│ ├── pids
│ ├── redis_cache.conf
│ ├── redis_queue.conf
│ └── redis_socketio.conf
├── env
│ ├── bin
│ ├── include
│ ├── lib
│ └── share
├── logs
│ ├── backup.log
│ └── bench.log
└── sites
├── apps.txt
├── assets
└── common_site_config.json
env:Python 虚拟环境
config:Redis 和 Nginx 的配置文件
logs:每个进程(Web、Worker)的日志文件
sites: 站点目录
apps: 应用目录
Procfile: 开发环境中运行的进程列表
现在我们已经创建了 frappe-bench 目录,可以通过运行以下命令来启动 Frappe Web 服务器:
$ cd frappe-bench
$ bench start
18:16:36 system | redis_cache.1 started (pid=11231)
18:16:36 system | redis_socketio.1 started (pid=11233)
18:16:36 system | redis_queue.1 started (pid=11234)
18:16:36 system | socketio.1 started (pid=11236)
18:16:36 system | web.1 started (pid=11237)
18:16:36 system | watch.1 started (pid=11240)
18:16:36 system | schedule.1 started (pid=11241)
18:16:36 system | worker_short.1 started (pid=11242)
18:16:36 redis_queue.1 | 11234:C 10 Jul 2020 18:16:36.320 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
18:16:36 redis_queue.1 | 11234:C 10 Jul 2020 18:16:36.320 # Redis version=6.0.5, bits=64, commit=00000000, modified=0, pid=11234, just started
18:16:36 redis_queue.1 | 11234:C 10 Jul 2020 18:16:36.320 # Configuration loaded
18:16:36 system | worker_long.1 started (pid=11244)
18:16:36 redis_cache.1 | 11231:C 10 Jul 2020 18:16:36.318 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
18:16:36 redis_cache.1 | 11231:C 10 Jul 2020 18:16:36.318 # Redis version=6.0.5, bits=64, commit=00000000, modified=0, pid=11231, just started
18:16:36 redis_cache.1 | 11231:C 10 Jul 2020 18:16:36.318 # Configuration loaded
18:16:36 redis_cache.1 | 11231:M 10 Jul 2020 18:16:36.320 * Increased maximum number of open files to 10032 (it was originally set to 256).
18:16:36 redis_queue.1 | 11234:M 10 Jul 2020 18:16:36.325 * Increased maximum number of open files to 10032 (it was originally set to 256).
18:16:36 system | worker_default.1 started (pid=11245)
18:16:36 redis_cache.1 | 11231:M 10 Jul 2020 18:16:36.337 * Running mode=standalone, port=13000.
18:16:36 redis_cache.1 | 11231:M 10 Jul 2020 18:16:36.337 # Server initialized
18:16:36 redis_cache.1 | 11231:M 10 Jul 2020 18:16:36.337 * Ready to accept connections
18:16:36 redis_queue.1 | 11234:M 10 Jul 2020 18:16:36.367 * Running mode=standalone, port=11000.
18:16:36 redis_queue.1 | 11234:M 10 Jul 2020 18:16:36.367 # Server initialized
18:16:36 redis_queue.1 | 11234:M 10 Jul 2020 18:16:36.367 * Ready to accept connections
18:16:36 redis_socketio.1 | 11233:C 10 Jul 2020 18:16:36.359 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
18:16:36 redis_socketio.1 | 11233:C 10 Jul 2020 18:16:36.359 # Redis version=6.0.5, bits=64, commit=00000000, modified=0, pid=11233, just started
18:16:36 redis_socketio.1 | 11233:C 10 Jul 2020 18:16:36.359 # Configuration loaded
18:16:36 redis_socketio.1 | 11233:M 10 Jul 2020 18:16:36.374 * Increased maximum number of open files to 10032 (it was originally set to 256).
18:16:36 redis_socketio.1 | 11233:M 10 Jul 2020 18:16:36.417 * Running mode=standalone, port=12000.
18:16:36 redis_socketio.1 | 11233:M 10 Jul 2020 18:16:36.418 # Server initialized
18:16:36 redis_socketio.1 | 11233:M 10 Jul 2020 18:16:36.418 * Ready to accept connections
18:16:37 socketio.1 | listening on *: 9000
18:16:41 web.1 | * Running on http://0.0.0.0:8000/ (Press CTRL+C to quit)
18:16:41 web.1 | * Restarting with fsevents reloader
18:16:41 watch.1 | yarn run v1.22.4
18:16:41 watch.1 | $ node rollup/watch.js
18:16:42 watch.1 |
18:16:42 watch.1 | Rollup Watcher Started
18:16:42 watch.1 |
18:16:42 watch.1 | Watching...
18:16:42 web.1 | * Debugger is active!
18:16:42 web.1 | * Debugger PIN: 100-672-925
18:16:43 watch.1 | Rebuilding frappe-web-b4.css
18:16:44 watch.1 | Rebuilding frappe-chat-web.css
18:16:44 watch.1 | Rebuilding chat.js
18:16:45 watch.1 | Rebuilding frappe-recorder.min.js
18:16:48 watch.1 | Rebuilding checkout.min.js
18:16:48 watch.1 | Rebuilding frappe-web.min.js
18:16:51 watch.1 | Rebuilding bootstrap-4-web.min.js
18:16:52 watch.1 | Rebuilding control.min.js
18:16:54 watch.1 | Rebuilding dialog.min.js
18:16:57 watch.1 | Rebuilding desk.min.css
18:16:57 watch.1 | Rebuilding frappe-rtl.css
18:16:58 watch.1 | Rebuilding printview.css
18:16:58 watch.1 | Rebuilding desk.min.js
18:17:04 watch.1 | Rebuilding form.min.css
18:17:04 watch.1 | Rebuilding form.min.js
18:17:07 watch.1 | Rebuilding list.min.css
18:17:07 watch.1 | Rebuilding list.min.js
18:17:09 watch.1 | Rebuilding report.min.css
18:17:09 watch.1 | Rebuilding report.min.js
18:17:12 watch.1 | Rebuilding web_form.min.js
18:17:12 watch.1 | Rebuilding web_form.css
18:17:13 watch.1 | Rebuilding email.css
18:17:13 watch.1 | Rebuilding social.min.js
18:17:13 watch.1 | Rebuilding barcode_scanner.min.js
18:17:15 watch.1 | Rebuilding data_import_tools.min.js
这将启动多个进程,包括基于 Gunicorn 的 Python Web 服务器、用于缓存、任务队列和 SocketIO 发布/订阅的 Redis 服务器、后台 Worker、用于 SocketIO 的 Node 服务器以及用于编译 JS/CSS 文件的 Node 服务器。
Web 服务器将在端口 8000 上开始监听,但目前我们还没有任何站点可供服务。下一步是创建我们的应用,并创建一个安装了该应用的站点。
请确保不要关闭运行 bench start 的终端。要运行 bench 命令,请打开另一个终端,并 cd 到 frappe-bench 目录中。
到目前为止,你做得很好!
下一步:创建应用