コンテンツにスキップ

Python

Book List

Author

Bases: Model

著者モデル

Attributes:

Name Type Description
id IntField

主キー

name CharField

著者名

Source code in src/nicegui_book_list/models.py
 6
 7
 8
 9
10
11
12
13
14
class Author(models.Model):
    """著者モデル

    :ivar id: 主キー
    :ivar name: 著者名
    """

    id: fields.IntField = fields.IntField(primary_key=True)
    name: fields.CharField = fields.CharField(max_length=255)

AuthorList

Bases: ListBase

著者リストのGUI

Attributes:

Name Type Description
name input

モデルのフィールド用

model Model

対象モデル

Source code in src/nicegui_book_list/ui.py
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
class AuthorList(ListBase):
    """著者リストのGUI

    :ivar name: モデルのフィールド用
    :cvar model: 対象モデル
    """

    name: ui.input
    model: ClassVar[Model] = models.Author

    @ui.refreshable
    async def build(self) -> None:
        """GUI作成"""
        super().build()
        authors: list[models.Author] = await models.Author.all()
        with self.list_ui:
            with self.add_ui:
                self.name = ui.input(label="Name").on("keydown.enter", self.keydown_enter)
            for author in reversed(authors):
                with ui.card(), ui.row().classes("items-center"):
                    ui.input("Name", on_change=author.save).bind_value(author, "name").on("blur", self.build.refresh)
                    ui.button(icon="delete", on_click=lambda a=author: self.delete(a)).props("flat")

    async def check(self) -> bool:
        """入力チェック"""
        if not self.name.value:
            ui.notify("Specify name")
            return False
        return True

build() async

GUI作成

Source code in src/nicegui_book_list/ui.py
123
124
125
126
127
128
129
130
131
132
133
134
@ui.refreshable
async def build(self) -> None:
    """GUI作成"""
    super().build()
    authors: list[models.Author] = await models.Author.all()
    with self.list_ui:
        with self.add_ui:
            self.name = ui.input(label="Name").on("keydown.enter", self.keydown_enter)
        for author in reversed(authors):
            with ui.card(), ui.row().classes("items-center"):
                ui.input("Name", on_change=author.save).bind_value(author, "name").on("blur", self.build.refresh)
                ui.button(icon="delete", on_click=lambda a=author: self.delete(a)).props("flat")

check() async

入力チェック

Source code in src/nicegui_book_list/ui.py
136
137
138
139
140
141
async def check(self) -> bool:
    """入力チェック"""
    if not self.name.value:
        ui.notify("Specify name")
        return False
    return True

Book

Bases: Model

書籍モデル

Attributes:

Name Type Description
id IntField

主キー

author ForeignKeyField

著者

title CharField

書籍名

Source code in src/nicegui_book_list/models.py
17
18
19
20
21
22
23
24
25
26
27
class Book(models.Model):
    """書籍モデル

    :ivar id: 主キー
    :ivar author: 著者
    :ivar title: 書籍名
    """

    id: fields.IntField = fields.IntField(primary_key=True)
    author: fields.ForeignKeyField = fields.ForeignKeyField("models.Author", related_name="books")
    title: fields.CharField = fields.CharField(max_length=255)

BookList

Bases: ListBase

書籍リストのGUI

Attributes:

Name Type Description
author_id select

モデルのフィールド用

title input

モデルのフィールド用

model Model

対象モデル

Source code in src/nicegui_book_list/ui.py
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
class BookList(ListBase):
    """書籍リストのGUI

    :ivar author_id: モデルのフィールド用
    :ivar title: モデルのフィールド用
    :cvar model: 対象モデル
    """

    author_id: ui.select
    title: ui.input
    model: ClassVar[Model] = models.Book

    @ui.refreshable
    async def build(self) -> None:
        """GUI作成"""
        super().build()
        authors: list[models.Author] = await models.Author.all()
        books: list[models.Book] = await models.Book.all()
        with self.list_ui:
            with self.add_ui:
                self.author_id = ui.select({author.id: author.name for author in authors}, label="Author")
                self.title = ui.input(label="Title").on("keydown.enter", self.keydown_enter)
            for book in reversed(books):
                author = await book.author
                with ui.card(), ui.row().classes("items-center"):
                    ui.label(author.name)
                    ui.input("Title", on_change=book.save).bind_value(book, "title").on("blur", self.build.refresh)
                    ui.button(icon="delete", on_click=lambda a=book: self.delete(a)).props("flat")

    async def check(self) -> bool:
        """入力チェック"""
        if not self.title.value:
            ui.notify("Specify title")
            return False
        if not await models.Author.exists(id=self.author_id.value):
            ui.notify("Select author")
            return False
        return True

build() async

GUI作成

Source code in src/nicegui_book_list/ui.py
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
@ui.refreshable
async def build(self) -> None:
    """GUI作成"""
    super().build()
    authors: list[models.Author] = await models.Author.all()
    books: list[models.Book] = await models.Book.all()
    with self.list_ui:
        with self.add_ui:
            self.author_id = ui.select({author.id: author.name for author in authors}, label="Author")
            self.title = ui.input(label="Title").on("keydown.enter", self.keydown_enter)
        for book in reversed(books):
            author = await book.author
            with ui.card(), ui.row().classes("items-center"):
                ui.label(author.name)
                ui.input("Title", on_change=book.save).bind_value(book, "title").on("blur", self.build.refresh)
                ui.button(icon="delete", on_click=lambda a=book: self.delete(a)).props("flat")

check() async

入力チェック

Source code in src/nicegui_book_list/ui.py
102
103
104
105
106
107
108
109
110
async def check(self) -> bool:
    """入力チェック"""
    if not self.title.value:
        ui.notify("Specify title")
        return False
    if not await models.Author.exists(id=self.author_id.value):
        ui.notify("Select author")
        return False
    return True

ListBase

Bases: ABC, element

著者リストと書籍リストのGUIの基底クラス

Attributes:

Name Type Description
label str

uiの見出し

refs set[ListBase]

一緒にrefreshするもの

fields set[str]

フィールドの集合

list_ui column

build時の一覧用のコンテナ

add_ui row

build時の追加入力用のコンテナ

model Model

対象モデル

Source code in src/nicegui_book_list/ui.py
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
class ListBase(ABC, ui.element):
    """著者リストと書籍リストのGUIの基底クラス

    :ivar label: uiの見出し
    :ivar refs: 一緒にrefreshするもの
    :ivar fields: フィールドの集合
    :ivar list_ui: build時の一覧用のコンテナ
    :ivar add_ui: build時の追加入力用のコンテナ
    :cvar model: 対象モデル
    """

    label: str
    refs: set["ListBase"]
    fields: set[str]
    list_ui: ui.column
    add_ui: ui.row
    model: ClassVar[Model]

    def __init__(self, *, label: str, refs: set["ListBase"] | None = None) -> None:
        """初期化"""
        self.label = label
        self.refs = refs or set()
        self.fields: set[str] = self.model.all().fields - {"id"}

    @ui.refreshable
    def build(self) -> None:
        """GUI作成"""
        self.list_ui = ui.column().classes("mx-auto")
        with self.list_ui:
            ui.label(self.label).classes("text-2xl")
            with ui.row().classes("w-full items-center px-4"):
                self.add_ui = ui.row()
                ui.button(on_click=self.create, icon="add").props("flat").classes("ml-auto")

    def refresh(self) -> None:
        """最新化"""
        self.build.refresh()
        for ref in self.refs:
            ref.build.refresh()

    @abstractmethod
    async def check(self) -> bool:
        """入力チェック"""

    async def create(self) -> None:
        """追加"""
        if await self.check():
            await self.model.create(**{field: getattr(self, field).value for field in self.fields})
            self.refresh()

    async def keydown_enter(self, event: events.GenericEventArguments) -> None:
        """Enterキー押下"""
        if not event.args.get("isComposing"):  # IME変換でないとき
            await self.create()

    async def delete(self, record: Model) -> None:
        """削除"""
        await record.delete()
        self.refresh()

__init__(*, label, refs=None)

初期化

Source code in src/nicegui_book_list/ui.py
30
31
32
33
34
def __init__(self, *, label: str, refs: set["ListBase"] | None = None) -> None:
    """初期化"""
    self.label = label
    self.refs = refs or set()
    self.fields: set[str] = self.model.all().fields - {"id"}

build()

GUI作成

Source code in src/nicegui_book_list/ui.py
36
37
38
39
40
41
42
43
44
@ui.refreshable
def build(self) -> None:
    """GUI作成"""
    self.list_ui = ui.column().classes("mx-auto")
    with self.list_ui:
        ui.label(self.label).classes("text-2xl")
        with ui.row().classes("w-full items-center px-4"):
            self.add_ui = ui.row()
            ui.button(on_click=self.create, icon="add").props("flat").classes("ml-auto")

check() abstractmethod async

入力チェック

Source code in src/nicegui_book_list/ui.py
52
53
54
@abstractmethod
async def check(self) -> bool:
    """入力チェック"""

create() async

追加

Source code in src/nicegui_book_list/ui.py
56
57
58
59
60
async def create(self) -> None:
    """追加"""
    if await self.check():
        await self.model.create(**{field: getattr(self, field).value for field in self.fields})
        self.refresh()

delete(record) async

削除

Source code in src/nicegui_book_list/ui.py
67
68
69
70
async def delete(self, record: Model) -> None:
    """削除"""
    await record.delete()
    self.refresh()

keydown_enter(event) async

Enterキー押下

Source code in src/nicegui_book_list/ui.py
62
63
64
65
async def keydown_enter(self, event: events.GenericEventArguments) -> None:
    """Enterキー押下"""
    if not event.args.get("isComposing"):  # IME変換でないとき
        await self.create()

refresh()

最新化

Source code in src/nicegui_book_list/ui.py
46
47
48
49
50
def refresh(self) -> None:
    """最新化"""
    self.build.refresh()
    for ref in self.refs:
        ref.build.refresh()