iT邦幫忙

2023 iThome 鐵人賽

DAY 7
0

在學習如何查詢之前,我們應該先要有一些資料,為此我們建立一個服務元件來產生假資料。

首先安裝一個產生假資料的 Python 套件,faker

$ poetry add 'faker==19.6.0'

接著建立一個UserService來作為操作使用者資料的服務。

# app/services.py
import typing

from faker import Faker

from app import types

fake = Faker(["zh_TW", "en_US"])

def gen_user_info() -> (
    typing.Tuple[
        typing.Dict[str, typing.Any],
        typing.Dict[str, typing.Any],
    ]
):
    profile = fake.simple_profile()
    user_info = dict(
        id=fake.random_int(min=1),
        username=profile["username"],
        email=fake.ascii_safe_email(),
        first_name=fake.first_name(),
        last_name=fake.last_name(),
        password=fake.lexify(text="??????????????????????????????"),
        last_login=fake.date_time_this_century() if fake.random_digit() > 1 else None,
        is_active=bool(fake.random_digit() > 1),
    )
    detail = dict(
        birthdate=profile["birthdate"],
        address=profile["address"],
        phone=fake.phone_number(),
    )
    return user_info, detail

def gen_normal_user() -> types.User:
    user_info, detail = gen_user_info()
    user_info["role"] = types.UserRole.NORMAL
    user_info["detail"] = types.NormalUserDetail(**detail)
    return types.User(**user_info)

def gen_staff_user(department: str) -> types.User:
    user_info, detail = gen_user_info()
    user_info["role"] = types.UserRole.STAFF
    detail["department"] = department
    user_info["detail"] = types.StaffUserDetail(**detail)
    return types.User(**user_info)

def gen_manager_user(
    department: str,
    subordinates: typing.List[types.User],
) -> types.User:
    user_info, detail = gen_user_info()
    user_info["role"] = types.UserRole.MANAGER
    detail["department"] = department
    detail["subordinates"] = subordinates
    user_info["detail"] = types.ManagerUserDetail(**detail)
    return types.User(**user_info)

def gen_admin_user() -> types.User:
    user_info, _ = gen_user_info()
    user_info["role"] = types.UserRole.ADMIN
    user_info["detail"] = types.AdminUserDetail(
        system_permissions=fake.random_choices(
            elements=(
                "read_users",
                "read_user",
                "write_user",
                "update_user",
                "delete_user",
            ),
        )
    )
    return types.User(**user_info)

class UserService:
    def __init__(self) -> None:
        self.normal_users = [gen_normal_user() for _ in range(20)]
        self.staff_users = []
        self.manager_users = []
        self.admin_users = [gen_admin_user() for _ in range(10)]
        self.departments = [
            "Human Resources",
            "IT",
            "Accounting",
            "Finance",
            "Marketing",
            "Research",
            "Development",
            "Production",
        ]
        self._gen_department_users()

    def _gen_department_users(self) -> None:
        for department in fake.random_choices(elements=self.departments):
            staffs = [gen_staff_user(department) for _ in range(fake.random_digit())]
            managers = [
                gen_manager_user(department, staffs)
                for _ in range(fake.random_int(min=0, max=5))
            ]
            self.staff_users.extend(staffs)
            self.manager_users.extend(managers)

    def all_users(self) -> typing.List[types.User]:
        return list(
            self.normal_users + self.admin_users + self.staff_users + self.manager_users
        )
		
		def user(self, id: int) -> typing.Optional[types.User]:
        for user in self.all_users():
            if user.id == id:
                return user
        return None
  • fake = Faker(["zh_TW", "en_US"]):建立一個fake物件,Faker 傳入一個要產生哪些語系的假資料列表。
  • gen_user_info():產生使用者基本資料與詳細資訊的共通欄位。
  • gen_normal_user():產生普通使用者物件。
  • gen_staff_user(department):產生特定部門員工物件。
  • gen_manager_user(department, subordinates):產生特定部門與所屬下屬管理者物件。
  • gen_admin_user():產生系統管理者物件。
  • UserService.__init__():初始化,產生所有類型使用者物件列表。
  • UserService._gen_department_users():產生有部門的使用者物件列表。
  • UserService.all_users():列出所有類型使用者物件列表。
  • UserService.user(id):使用 id 查詢特定使用者。

接者將UserService跟 GraphQL 查詢物件串接在一起。

# app/query.py
import typing
-import datetime

import strawberry

-from app import types
+from app import types, services

+user_service = services.UserService()
-def get_users() -> typing.List[types.User]:
-   return [
-       types.User(
-           id=1,
-           username="bob",
-           email="bob@mymail.com",
-           first_name="Bob",
-           last_name="User",
-           password="xxxxxx",
-           last_login=datetime.datetime.now(),
-           role=types.UserRole.NORMAL,
-       ),
-   ]

@strawberry.type
class Query:
-    users: typing.List[types.User] = strawberry.field(resolver=get_users)
+    users: typing.List[types.User] = strawberry.field(resolver=user_service.all_users)
+    user: typing.Optional[types.User] = strawberry.field(resolver=user_service.user)

這邊新增了兩個查詢物件,分別是列出所有使用者(users)與查詢某個使用者(user)。

到這邊我們可以在 GraphiQL 的頁面上使用 GraphiQL Explorer,使用點選的方式建立查詢,或是直接編輯查詢語法。

query UserListQuery {
  users {
    email
    firstName
    fullName
    id
    isActive
    lastLogin
    lastName
    password
    role
    username
  }
}

我們使用查詢語法建立一個名為UserListQuery的查詢,執行並得到所有使用者的基本資料:

https://ithelp.ithome.com.tw/upload/images/20230922/201619576QCNGuy89K.png
圖上有標記 GraphiQL 頁面 Explorer 操作順序。


query UserQuery {
  user(id: 2896) {
    username
    id
    email
    isActive
    fullName
    firstName
    lastLogin
    lastName
    password
    role
  }
}

我們再建立另一個查詢UserQuery,來得到特定 id 的使用者資訊:

https://ithelp.ithome.com.tw/upload/images/20230922/20161957bBwtpPCzK0.png
圖上有標記 GraphiQL 頁面 Explorer 操作順序。

到這邊就完成兩個最基本的查詢操作。

在上面的兩個查詢操作(Queries),我們定義兩個名稱,分別是UserListQueryUserQuery在 GraphQL 中稱為操作名稱(Operation name),而user(id: 2896)id: 稱為引數(Arguments)。

app/query.py 的完整程式碼:

import typing
import strawberry

from app import types, services

user_service = services.UserService()

@strawberry.type
class Query:
    users: typing.List[types.User] = strawberry.field(resolver=user_service.all_users)
    user: typing.Optional[types.User] = strawberry.field(resolver=user_service.user)

參考資料


上一篇
Day 6:使用 Strawberry 學習 GraphQL 型別 – 3
下一篇
Day 8:使用 Strawberry 學習 GraphQL 變數與別名
系列文
Django 與 Strawberry GraphQL:探索現代 API 開發之路30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言