Seeding

原意為播種,在這裡指的是批次建假資料,或是初始資料。假資料用於模擬真實的環境,供團隊成員去感受或模擬實際上線的使用,不過如果是單元測試的話,則與 seeding 的假資料無關,單元測試的假資料會在該單元測試的程式內有針對性的建立與消除,不會與 seeding 的假資料混用。

Seeding 指令

  • 執行全部 seeder:craft seed:run
  • 執行特定 seeder,以 Transaction model 為例:craft seed:run Transaction
  • 建立 seeder,以 Transaction model 為例:craft seed Transaction

範例

如果有用 craft auth 建立過用戶認證系統的話,這個指令也幫我們建了一套 User 物件的 seeder 範例,在實做我們的 seeder 前先看看範例的做法。

從 databases/seeds/database_seeder.py 開始看起:

"""Base Database Seeder Module."""

from orator.seeds import Seeder
from .user_table_seeder import UserTableSeeder


class DatabaseSeeder(Seeder):

    def run(self):
        """Run the database seeds."""
        self.call(UserTableSeeder)

前面提到過的 craft seed:run 就會執行這支看起來很空的 database_seeder.py,再透過裡面的 call() 來呼叫要被執行的 seeder。可以看到目前只有一個 UserTableSeeder,讓我們繼續看下去。

來看 database/seeds/user_table_seeder.py:

"""User Table Seeder.

You can run this seeder in order to generate users.

    - Each time it is ran it will generate 50 random users.
    - All users have the password of 'secret'.
    - You can run the seeder by running: craft seed:run.
"""

from orator.seeds import Seeder

from app.User import User
from config.factories import factory


class UserTableSeeder(Seeder):

    def run(self):
        """
        Run the database seeds.
        """
        factory(User, 50).create()

一樣很空,只是叫工廠幫我們做五十個 User 出來,至於具體工廠怎麼做出 User,從 config.factories 繼續追下去。

工廠在 config/factories.py:

from orator.orm import Factory
from app.User import User
from string import ascii_uppercase

factory = Factory()


def users_factory(faker):
    return {
        'name': faker.name(),
        'email': faker.email(),
        'password': '$2b$12$WMgb5Re1NqUr.uSRfQmPQeeGWudk/8/aNbVMpD1dR.Et83vfL8WAu', # == 'secret'
    }

factory.register(User, users_factory)

先看最下面註冊工廠方法的敘述:User 的工廠方法使用 users_factroy()users_factory() 接受一個 faker 參數,這個參數是 Faker 的一個實例,但不用自己產生,Orator 在呼叫工廠方法時會自己幫我們產生 Faker 實例並餵入。

Faker 是個產出假資料的包,在專案建立時應該就會被裝起來。Faker 的使用也很直白,看上面的範例都可以望文生義,想更深入了解可以去讀 Faker 文件。

有了這樣的工廠方法,便可應用於 seeding 與單元測試,它們都可以共用這些工廠方法,不用重複造輪子。

建立 Seeder

在此以 Transaction model 為例,建立 seeder 與相關的工廠方法。

建立 Seeder 檔案:

$ craft seed Transaction

建立 Transaction 的 factory 方法,編輯 config/factories.py,加入相關敘述:

from app.Transaction import Transaction
from string import ascii_uppercase

def transactions_factory(faker):
    return {
        'user_id': faker.random_int(min=1, max=User.max('id')),
        'date': faker.date_this_decade(after_today=True),
        'amount': faker.random_int(),
        'receipt_number': faker.bothify(text="??-########", letters=ascii_uppercase),
        'description': faker.sentence(),
    }

factory.register(Transaction, transactions_factory)

基本就是抄改 users_factory()

工廠方法完成後,回到 Transaction seeder 檔案,設定工廠製造數量。編輯 databases/seeds/transaction_table_seeder.py:

from orator.seeds import Seeder

from app.Transaction import Transaction
from config.factories import factory


class TransactionTableSeeder(Seeder):

    def run(self):
        """
        Run the database seeds.
        """
        factory(Transaction, 1000).create()

基本上也是抄改。

工廠有了,製作數量設定了,再來讓 Transaction seeder 也會和其它 seeder 一起被執行,在 databases/seeds/database_seeder.py 加入這行:

self.call(TransactionTableSeeder)

最後實際跑一次 seeder:

$ craft seed:run

跑完可以進資料庫看一下是不是如預期的建了這些假資料。