nsd-extension-framework 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- nsd_extension_framework-0.1.0/PKG-INFO +267 -0
- nsd_extension_framework-0.1.0/README.md +256 -0
- nsd_extension_framework-0.1.0/pyproject.toml +92 -0
- nsd_extension_framework-0.1.0/setup.cfg +4 -0
- nsd_extension_framework-0.1.0/src/nsd_extension_framework/__init__.py +6 -0
- nsd_extension_framework-0.1.0/src/nsd_extension_framework/apps.py +17 -0
- nsd_extension_framework-0.1.0/src/nsd_extension_framework/bases.py +338 -0
- nsd_extension_framework-0.1.0/src/nsd_extension_framework/db.py +104 -0
- nsd_extension_framework-0.1.0/src/nsd_extension_framework/drf.py +30 -0
- nsd_extension_framework-0.1.0/src/nsd_extension_framework/forms.py +42 -0
- nsd_extension_framework-0.1.0/src/nsd_extension_framework/tests/__init__.py +1 -0
- nsd_extension_framework-0.1.0/src/nsd_extension_framework/tests/example/__init__.py +1 -0
- nsd_extension_framework-0.1.0/src/nsd_extension_framework/tests/example/apps.py +12 -0
- nsd_extension_framework-0.1.0/src/nsd_extension_framework/tests/example/extensions.py +23 -0
- nsd_extension_framework-0.1.0/src/nsd_extension_framework/tests/example/models.py +18 -0
- nsd_extension_framework-0.1.0/src/nsd_extension_framework/tests/extensions.py +34 -0
- nsd_extension_framework-0.1.0/src/nsd_extension_framework/tests/settings.py +70 -0
- nsd_extension_framework-0.1.0/src/nsd_extension_framework/tests/test_bases.py +79 -0
- nsd_extension_framework-0.1.0/src/nsd_extension_framework/tests/test_db.py +104 -0
- nsd_extension_framework-0.1.0/src/nsd_extension_framework/tests/test_forms.py +19 -0
- nsd_extension_framework-0.1.0/src/nsd_extension_framework/tests/urls.py +1 -0
- nsd_extension_framework-0.1.0/src/nsd_extension_framework/utils.py +77 -0
- nsd_extension_framework-0.1.0/src/nsd_extension_framework.egg-info/PKG-INFO +267 -0
- nsd_extension_framework-0.1.0/src/nsd_extension_framework.egg-info/SOURCES.txt +25 -0
- nsd_extension_framework-0.1.0/src/nsd_extension_framework.egg-info/dependency_links.txt +1 -0
- nsd_extension_framework-0.1.0/src/nsd_extension_framework.egg-info/requires.txt +4 -0
- nsd_extension_framework-0.1.0/src/nsd_extension_framework.egg-info/top_level.txt +1 -0
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: nsd-extension-framework
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: niceDjango Extension Framework
|
|
5
|
+
Requires-Python: >=3.12
|
|
6
|
+
Description-Content-Type: text/markdown
|
|
7
|
+
Requires-Dist: django>=5.2
|
|
8
|
+
Requires-Dist: djangorestframework>=3.17.1
|
|
9
|
+
Requires-Dist: importlib>=1.0.4
|
|
10
|
+
Requires-Dist: wrapt>=2.0.1
|
|
11
|
+
|
|
12
|
+
# niceDjango Extension Framework
|
|
13
|
+
|
|
14
|
+
提供 Python/Django 擴展之開發框架。
|
|
15
|
+
|
|
16
|
+
## 概述
|
|
17
|
+
|
|
18
|
+
擴展 (Extension) 用來提供給呼叫端,無須知道具體實作方式,便可取得實作對象 (Target) 之機制。
|
|
19
|
+
|
|
20
|
+
每一個擴展需定義:
|
|
21
|
+
|
|
22
|
+
- ``extension_type``: 擴展的類型。使用 ``[A-z_-.][A-z0-9_-.]`` 組成之字串。
|
|
23
|
+
- ``extension_id``: 擴展的識別碼。使用 ``[A-z_-.][A-z0-9_-.]`` 組成之字串。空值或省略時,將以擴展的識別子 (
|
|
24
|
+
類別名稱,或函數名稱) 做為識別碼。
|
|
25
|
+
- ``label``: 擴展的標籤,給人類看的名稱。空值或省略時,將以擴展的識別子 (類別名稱,或函數名稱) 做為標籤。
|
|
26
|
+
- ``description``:給人類閱讀的描述。
|
|
27
|
+
|
|
28
|
+
擴展的完整識別子 (Identifier) 為 <code><i>extension_type</i>:<i>extension_id</i></code>。
|
|
29
|
+
|
|
30
|
+
## 功能
|
|
31
|
+
|
|
32
|
+
- 簡化擴展之開發。
|
|
33
|
+
- 可從所有 EGG 中載入指定的擴展。
|
|
34
|
+
- 提供給 Django Model 使用的 Field 類別,以保存擴展資訊到資料庫。
|
|
35
|
+
- 提供給 Django Form 使用的 Field 類別,讓用戶可從表單選取或設定擴展。
|
|
36
|
+
- 提供給 Django REST Framework 使用的 Field 類別,讓 API Client 可以選取或設定擴展。
|
|
37
|
+
|
|
38
|
+
## 安裝
|
|
39
|
+
|
|
40
|
+
```shell
|
|
41
|
+
$ pip install nsd-extension-framework
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## 使用
|
|
45
|
+
|
|
46
|
+
### 宣告擴展 (Declaration extension)
|
|
47
|
+
|
|
48
|
+
首先,你需要先宣告你的擴展。擴展可以是一個類別 (Class),也可以是一個函數 (Function)。
|
|
49
|
+
|
|
50
|
+
每個擴展都需使用 ``@extension`` 裝飾器宣告其為擴展:
|
|
51
|
+
|
|
52
|
+
```python
|
|
53
|
+
from django.utils.translation import gettext as _
|
|
54
|
+
|
|
55
|
+
from nsd_extension_framework import extension
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
@extension(
|
|
59
|
+
extension_type="foo",
|
|
60
|
+
extension_id="boo_class",
|
|
61
|
+
label=_("Boo Class Extension")
|
|
62
|
+
)
|
|
63
|
+
class BooExtension:
|
|
64
|
+
def test(self):
|
|
65
|
+
print("Boo Class Extension - Test")
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
@extension(
|
|
69
|
+
extension_type="foo",
|
|
70
|
+
extension_id="boo_function",
|
|
71
|
+
label=_("Boo Function Extension")
|
|
72
|
+
)
|
|
73
|
+
def boo():
|
|
74
|
+
print("Boo Function Extension - Test")
|
|
75
|
+
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### 註冊你的擴展 (Register your extensions)
|
|
79
|
+
|
|
80
|
+
宣告擴展後,可在使用之前註冊你的擴展。註冊的方法有兩種:
|
|
81
|
+
|
|
82
|
+
- 使用代碼
|
|
83
|
+
- 使用 EGG EntryPoint
|
|
84
|
+
|
|
85
|
+
#### 使用代碼
|
|
86
|
+
|
|
87
|
+
例如,在 Django 中,你可以透過 ``AppConfig.ready()`` 來註冊之:
|
|
88
|
+
|
|
89
|
+
```python
|
|
90
|
+
from django.apps import AppConfig as _AppConfig
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
class AppConfig(_AppConfig):
|
|
94
|
+
def ready(self):
|
|
95
|
+
from myapp.extensions import BooExtension, boo # NOQA
|
|
96
|
+
from nsd_extension_framework import factory
|
|
97
|
+
factory.register(BooExtension).register(boo)
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
#### 使用 EGG EntryPoint
|
|
103
|
+
|
|
104
|
+
請在你的 Python EGG 套件中,定義一個 EntryPoint。
|
|
105
|
+
|
|
106
|
+
例如 ``pyproject.toml`` 中:
|
|
107
|
+
|
|
108
|
+
```toml
|
|
109
|
+
[project.entry-points."AppExtensions"]
|
|
110
|
+
"foo:boo_class" = "myapp.extensions:BooExtension"
|
|
111
|
+
"foo:boo_function" = "myapp.extensions:boo"
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
或是 ``setup.py`` 中:
|
|
115
|
+
|
|
116
|
+
```python
|
|
117
|
+
from setuptools import setup # NOQA
|
|
118
|
+
|
|
119
|
+
setup(
|
|
120
|
+
# ...
|
|
121
|
+
entry_points={
|
|
122
|
+
"AppExtensions": {
|
|
123
|
+
"foo:boo_class": "myapp.extensions:BooExtension",
|
|
124
|
+
"foo:boo_function": "myapp.extensions:boo",
|
|
125
|
+
}
|
|
126
|
+
},
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
然後在使用之前,透過 ``nsd_extension_framework.factory.load()`` 從所有的 EGG 套件中載入所有擴展:
|
|
132
|
+
|
|
133
|
+
```python
|
|
134
|
+
from django.apps import AppConfig as _AppConfig
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
class AppConfig(_AppConfig):
|
|
138
|
+
def ready(self):
|
|
139
|
+
from nsd_extension_framework import factory
|
|
140
|
+
factory.load(entry_point_group_name="AppExtensions")
|
|
141
|
+
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
### 取得擴展 (Get extension)
|
|
145
|
+
|
|
146
|
+
註冊後,可以在程序運行的任何時候,透過 ``factory.get_extension()`` 來取得擴展:
|
|
147
|
+
|
|
148
|
+
```python
|
|
149
|
+
from nsd_extension_framework import factory
|
|
150
|
+
|
|
151
|
+
boo_class = factory.get_extension("foo:boo_class")
|
|
152
|
+
extension = boo_class()
|
|
153
|
+
extension.test()
|
|
154
|
+
# Boo Class Extension - Test
|
|
155
|
+
|
|
156
|
+
boo_function = factory.get_extension("foo:boo_function")
|
|
157
|
+
boo_function()
|
|
158
|
+
# Boo Function Extension - Test
|
|
159
|
+
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
## 進階 (Advanced)
|
|
163
|
+
|
|
164
|
+
### Django 模型欄位 (Django Model Field)
|
|
165
|
+
|
|
166
|
+
本套件中提供 ``nsd_extension_framework.db.ExtensionField``,讓你可以將擴展資訊保存到資料庫中。
|
|
167
|
+
|
|
168
|
+
使用範例:
|
|
169
|
+
|
|
170
|
+
```python
|
|
171
|
+
from django.db import models
|
|
172
|
+
|
|
173
|
+
from nsd_extension_framework.db import ExtensionField
|
|
174
|
+
from myapp.extensions import BooExtension # NOQA
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
class ExtensionModel(models.Model):
|
|
178
|
+
extension = ExtensionField(
|
|
179
|
+
required=False,
|
|
180
|
+
db_index=True
|
|
181
|
+
)
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
ext = ExtensionModel(extension=BooExtension)
|
|
185
|
+
# 回傳 BooExtension 實例
|
|
186
|
+
impl = ext.extension()
|
|
187
|
+
# 呼叫 BooExtension.test()
|
|
188
|
+
impl.test()
|
|
189
|
+
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
### Django 表單欄位 (Django Form Field)
|
|
193
|
+
|
|
194
|
+
```python
|
|
195
|
+
from django import forms
|
|
196
|
+
|
|
197
|
+
from nsd_extension_framework import Extension
|
|
198
|
+
from nsd_extension_framework.forms import ExtensionField
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
class BooForm(forms.Form):
|
|
202
|
+
extension = ExtensionField(
|
|
203
|
+
required=False,
|
|
204
|
+
)
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
def boo_form_post(request):
|
|
208
|
+
form = BooForm(request.POST)
|
|
209
|
+
if form.is_valid():
|
|
210
|
+
# 回傳 BooExtension 實例
|
|
211
|
+
extension = form.cleaned_data["extension"]
|
|
212
|
+
if extension:
|
|
213
|
+
# 取得 Extension 的 FullID
|
|
214
|
+
opts = Extension.get_extension_options(extension)
|
|
215
|
+
if opts:
|
|
216
|
+
print(opts.full_id)
|
|
217
|
+
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
目前也支援 Django ModelForm:
|
|
221
|
+
|
|
222
|
+
```python
|
|
223
|
+
from django import forms
|
|
224
|
+
from myapp.models import ExtensionModel # NOQA
|
|
225
|
+
|
|
226
|
+
|
|
227
|
+
# 自定義的 ModelForm
|
|
228
|
+
class BooModelForm(forms.ModelForm):
|
|
229
|
+
class Meta:
|
|
230
|
+
model = ExtensionModel
|
|
231
|
+
fields = '__all__'
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
# 使用 modelform_factory() 建立 ModelForm
|
|
235
|
+
|
|
236
|
+
ModelForm = forms.modelform_factory(ExtensionModel, fields='__all__')
|
|
237
|
+
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
### Django REST Framework 欄位 (Django REST Framework Field)
|
|
241
|
+
|
|
242
|
+
```python
|
|
243
|
+
from rest_framework import serializers
|
|
244
|
+
|
|
245
|
+
from nsd_extension_framework.drf import ExtensionField
|
|
246
|
+
|
|
247
|
+
|
|
248
|
+
class BooSerializer(serializers.Serializer):
|
|
249
|
+
extension = ExtensionField(
|
|
250
|
+
required=False,
|
|
251
|
+
)
|
|
252
|
+
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
也支援 ModelSerializer:
|
|
256
|
+
|
|
257
|
+
```python
|
|
258
|
+
from rest_framework import serializers
|
|
259
|
+
from myapp.models import ExtensionModel # NOQA
|
|
260
|
+
|
|
261
|
+
|
|
262
|
+
class ExtensionModelSerializer(serializers.ModelSerializer):
|
|
263
|
+
class Meta:
|
|
264
|
+
model = ExtensionModel
|
|
265
|
+
field = '__all__'
|
|
266
|
+
|
|
267
|
+
```
|
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
# niceDjango Extension Framework
|
|
2
|
+
|
|
3
|
+
提供 Python/Django 擴展之開發框架。
|
|
4
|
+
|
|
5
|
+
## 概述
|
|
6
|
+
|
|
7
|
+
擴展 (Extension) 用來提供給呼叫端,無須知道具體實作方式,便可取得實作對象 (Target) 之機制。
|
|
8
|
+
|
|
9
|
+
每一個擴展需定義:
|
|
10
|
+
|
|
11
|
+
- ``extension_type``: 擴展的類型。使用 ``[A-z_-.][A-z0-9_-.]`` 組成之字串。
|
|
12
|
+
- ``extension_id``: 擴展的識別碼。使用 ``[A-z_-.][A-z0-9_-.]`` 組成之字串。空值或省略時,將以擴展的識別子 (
|
|
13
|
+
類別名稱,或函數名稱) 做為識別碼。
|
|
14
|
+
- ``label``: 擴展的標籤,給人類看的名稱。空值或省略時,將以擴展的識別子 (類別名稱,或函數名稱) 做為標籤。
|
|
15
|
+
- ``description``:給人類閱讀的描述。
|
|
16
|
+
|
|
17
|
+
擴展的完整識別子 (Identifier) 為 <code><i>extension_type</i>:<i>extension_id</i></code>。
|
|
18
|
+
|
|
19
|
+
## 功能
|
|
20
|
+
|
|
21
|
+
- 簡化擴展之開發。
|
|
22
|
+
- 可從所有 EGG 中載入指定的擴展。
|
|
23
|
+
- 提供給 Django Model 使用的 Field 類別,以保存擴展資訊到資料庫。
|
|
24
|
+
- 提供給 Django Form 使用的 Field 類別,讓用戶可從表單選取或設定擴展。
|
|
25
|
+
- 提供給 Django REST Framework 使用的 Field 類別,讓 API Client 可以選取或設定擴展。
|
|
26
|
+
|
|
27
|
+
## 安裝
|
|
28
|
+
|
|
29
|
+
```shell
|
|
30
|
+
$ pip install nsd-extension-framework
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## 使用
|
|
34
|
+
|
|
35
|
+
### 宣告擴展 (Declaration extension)
|
|
36
|
+
|
|
37
|
+
首先,你需要先宣告你的擴展。擴展可以是一個類別 (Class),也可以是一個函數 (Function)。
|
|
38
|
+
|
|
39
|
+
每個擴展都需使用 ``@extension`` 裝飾器宣告其為擴展:
|
|
40
|
+
|
|
41
|
+
```python
|
|
42
|
+
from django.utils.translation import gettext as _
|
|
43
|
+
|
|
44
|
+
from nsd_extension_framework import extension
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
@extension(
|
|
48
|
+
extension_type="foo",
|
|
49
|
+
extension_id="boo_class",
|
|
50
|
+
label=_("Boo Class Extension")
|
|
51
|
+
)
|
|
52
|
+
class BooExtension:
|
|
53
|
+
def test(self):
|
|
54
|
+
print("Boo Class Extension - Test")
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
@extension(
|
|
58
|
+
extension_type="foo",
|
|
59
|
+
extension_id="boo_function",
|
|
60
|
+
label=_("Boo Function Extension")
|
|
61
|
+
)
|
|
62
|
+
def boo():
|
|
63
|
+
print("Boo Function Extension - Test")
|
|
64
|
+
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### 註冊你的擴展 (Register your extensions)
|
|
68
|
+
|
|
69
|
+
宣告擴展後,可在使用之前註冊你的擴展。註冊的方法有兩種:
|
|
70
|
+
|
|
71
|
+
- 使用代碼
|
|
72
|
+
- 使用 EGG EntryPoint
|
|
73
|
+
|
|
74
|
+
#### 使用代碼
|
|
75
|
+
|
|
76
|
+
例如,在 Django 中,你可以透過 ``AppConfig.ready()`` 來註冊之:
|
|
77
|
+
|
|
78
|
+
```python
|
|
79
|
+
from django.apps import AppConfig as _AppConfig
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
class AppConfig(_AppConfig):
|
|
83
|
+
def ready(self):
|
|
84
|
+
from myapp.extensions import BooExtension, boo # NOQA
|
|
85
|
+
from nsd_extension_framework import factory
|
|
86
|
+
factory.register(BooExtension).register(boo)
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
#### 使用 EGG EntryPoint
|
|
92
|
+
|
|
93
|
+
請在你的 Python EGG 套件中,定義一個 EntryPoint。
|
|
94
|
+
|
|
95
|
+
例如 ``pyproject.toml`` 中:
|
|
96
|
+
|
|
97
|
+
```toml
|
|
98
|
+
[project.entry-points."AppExtensions"]
|
|
99
|
+
"foo:boo_class" = "myapp.extensions:BooExtension"
|
|
100
|
+
"foo:boo_function" = "myapp.extensions:boo"
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
或是 ``setup.py`` 中:
|
|
104
|
+
|
|
105
|
+
```python
|
|
106
|
+
from setuptools import setup # NOQA
|
|
107
|
+
|
|
108
|
+
setup(
|
|
109
|
+
# ...
|
|
110
|
+
entry_points={
|
|
111
|
+
"AppExtensions": {
|
|
112
|
+
"foo:boo_class": "myapp.extensions:BooExtension",
|
|
113
|
+
"foo:boo_function": "myapp.extensions:boo",
|
|
114
|
+
}
|
|
115
|
+
},
|
|
116
|
+
)
|
|
117
|
+
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
然後在使用之前,透過 ``nsd_extension_framework.factory.load()`` 從所有的 EGG 套件中載入所有擴展:
|
|
121
|
+
|
|
122
|
+
```python
|
|
123
|
+
from django.apps import AppConfig as _AppConfig
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
class AppConfig(_AppConfig):
|
|
127
|
+
def ready(self):
|
|
128
|
+
from nsd_extension_framework import factory
|
|
129
|
+
factory.load(entry_point_group_name="AppExtensions")
|
|
130
|
+
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
### 取得擴展 (Get extension)
|
|
134
|
+
|
|
135
|
+
註冊後,可以在程序運行的任何時候,透過 ``factory.get_extension()`` 來取得擴展:
|
|
136
|
+
|
|
137
|
+
```python
|
|
138
|
+
from nsd_extension_framework import factory
|
|
139
|
+
|
|
140
|
+
boo_class = factory.get_extension("foo:boo_class")
|
|
141
|
+
extension = boo_class()
|
|
142
|
+
extension.test()
|
|
143
|
+
# Boo Class Extension - Test
|
|
144
|
+
|
|
145
|
+
boo_function = factory.get_extension("foo:boo_function")
|
|
146
|
+
boo_function()
|
|
147
|
+
# Boo Function Extension - Test
|
|
148
|
+
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
## 進階 (Advanced)
|
|
152
|
+
|
|
153
|
+
### Django 模型欄位 (Django Model Field)
|
|
154
|
+
|
|
155
|
+
本套件中提供 ``nsd_extension_framework.db.ExtensionField``,讓你可以將擴展資訊保存到資料庫中。
|
|
156
|
+
|
|
157
|
+
使用範例:
|
|
158
|
+
|
|
159
|
+
```python
|
|
160
|
+
from django.db import models
|
|
161
|
+
|
|
162
|
+
from nsd_extension_framework.db import ExtensionField
|
|
163
|
+
from myapp.extensions import BooExtension # NOQA
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
class ExtensionModel(models.Model):
|
|
167
|
+
extension = ExtensionField(
|
|
168
|
+
required=False,
|
|
169
|
+
db_index=True
|
|
170
|
+
)
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
ext = ExtensionModel(extension=BooExtension)
|
|
174
|
+
# 回傳 BooExtension 實例
|
|
175
|
+
impl = ext.extension()
|
|
176
|
+
# 呼叫 BooExtension.test()
|
|
177
|
+
impl.test()
|
|
178
|
+
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
### Django 表單欄位 (Django Form Field)
|
|
182
|
+
|
|
183
|
+
```python
|
|
184
|
+
from django import forms
|
|
185
|
+
|
|
186
|
+
from nsd_extension_framework import Extension
|
|
187
|
+
from nsd_extension_framework.forms import ExtensionField
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
class BooForm(forms.Form):
|
|
191
|
+
extension = ExtensionField(
|
|
192
|
+
required=False,
|
|
193
|
+
)
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
def boo_form_post(request):
|
|
197
|
+
form = BooForm(request.POST)
|
|
198
|
+
if form.is_valid():
|
|
199
|
+
# 回傳 BooExtension 實例
|
|
200
|
+
extension = form.cleaned_data["extension"]
|
|
201
|
+
if extension:
|
|
202
|
+
# 取得 Extension 的 FullID
|
|
203
|
+
opts = Extension.get_extension_options(extension)
|
|
204
|
+
if opts:
|
|
205
|
+
print(opts.full_id)
|
|
206
|
+
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
目前也支援 Django ModelForm:
|
|
210
|
+
|
|
211
|
+
```python
|
|
212
|
+
from django import forms
|
|
213
|
+
from myapp.models import ExtensionModel # NOQA
|
|
214
|
+
|
|
215
|
+
|
|
216
|
+
# 自定義的 ModelForm
|
|
217
|
+
class BooModelForm(forms.ModelForm):
|
|
218
|
+
class Meta:
|
|
219
|
+
model = ExtensionModel
|
|
220
|
+
fields = '__all__'
|
|
221
|
+
|
|
222
|
+
|
|
223
|
+
# 使用 modelform_factory() 建立 ModelForm
|
|
224
|
+
|
|
225
|
+
ModelForm = forms.modelform_factory(ExtensionModel, fields='__all__')
|
|
226
|
+
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
### Django REST Framework 欄位 (Django REST Framework Field)
|
|
230
|
+
|
|
231
|
+
```python
|
|
232
|
+
from rest_framework import serializers
|
|
233
|
+
|
|
234
|
+
from nsd_extension_framework.drf import ExtensionField
|
|
235
|
+
|
|
236
|
+
|
|
237
|
+
class BooSerializer(serializers.Serializer):
|
|
238
|
+
extension = ExtensionField(
|
|
239
|
+
required=False,
|
|
240
|
+
)
|
|
241
|
+
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
也支援 ModelSerializer:
|
|
245
|
+
|
|
246
|
+
```python
|
|
247
|
+
from rest_framework import serializers
|
|
248
|
+
from myapp.models import ExtensionModel # NOQA
|
|
249
|
+
|
|
250
|
+
|
|
251
|
+
class ExtensionModelSerializer(serializers.ModelSerializer):
|
|
252
|
+
class Meta:
|
|
253
|
+
model = ExtensionModel
|
|
254
|
+
field = '__all__'
|
|
255
|
+
|
|
256
|
+
```
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "nsd-extension-framework"
|
|
3
|
+
description = "niceDjango Extension Framework"
|
|
4
|
+
readme = "README.md"
|
|
5
|
+
requires-python = ">=3.12"
|
|
6
|
+
dynamic = ["version"]
|
|
7
|
+
dependencies = [
|
|
8
|
+
"django>=5.2",
|
|
9
|
+
"djangorestframework>=3.17.1",
|
|
10
|
+
"importlib>=1.0.4",
|
|
11
|
+
"wrapt>=2.0.1",
|
|
12
|
+
]
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
[build-system]
|
|
16
|
+
requires = ["setuptools"]
|
|
17
|
+
build-backend = "setuptools.build_meta"
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
#[tool.pytest]
|
|
21
|
+
#django_settings_module = "nsd_extension_framework.tests.settings"
|
|
22
|
+
#pythonpath = ["src"]
|
|
23
|
+
#django_find_project = false
|
|
24
|
+
#testpaths = ["src/nsd_extension_framework/tests"]
|
|
25
|
+
#python_files = "test*.py"
|
|
26
|
+
#python_classes = "Test*"
|
|
27
|
+
#python_functions = "test_*"
|
|
28
|
+
#norecursedirs = "*.egg .eggs dist build docs .tox .git __pycache__"
|
|
29
|
+
|
|
30
|
+
[tool.behave]
|
|
31
|
+
#default_format = "plain"
|
|
32
|
+
#default_tags = "not (@xfail or @not_implemented)"
|
|
33
|
+
junit = true
|
|
34
|
+
junit_directory = "build/behave.reports"
|
|
35
|
+
logging_level = "WARNING"
|
|
36
|
+
|
|
37
|
+
[tool.pytest.ini_options]
|
|
38
|
+
DJANGO_SETTINGS_MODULE = "nsd_extension_framework.tests.settings"
|
|
39
|
+
#django_settings_module = "nsd_extension_framework.tests.settings"
|
|
40
|
+
pythonpath = ["src"]
|
|
41
|
+
django_find_project = false
|
|
42
|
+
testpaths = ["src/nsd_extension_framework/tests"]
|
|
43
|
+
python_files = "test*.py"
|
|
44
|
+
python_classes = "*TestCase"
|
|
45
|
+
python_functions = "test_*"
|
|
46
|
+
norecursedirs = "*.egg .eggs dist build docs .tox .git __pycache__"
|
|
47
|
+
#markers = [
|
|
48
|
+
# "integration: tests under examples/integrations (opt-in)",
|
|
49
|
+
# "ui: browser-based tests",
|
|
50
|
+
#]
|
|
51
|
+
#addopts = [
|
|
52
|
+
# "--strict-markers",
|
|
53
|
+
# "-m", "not integration",
|
|
54
|
+
#]
|
|
55
|
+
#addopts = ["-p", "no:warnings"]
|
|
56
|
+
|
|
57
|
+
[[tool.uv.index]]
|
|
58
|
+
url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple"
|
|
59
|
+
default = true
|
|
60
|
+
#markers = [
|
|
61
|
+
# "integration: tests under examples/integrations (opt-in)",
|
|
62
|
+
# "ui: browser-based tests",
|
|
63
|
+
#]
|
|
64
|
+
#addopts = [
|
|
65
|
+
# "--strict-markers",
|
|
66
|
+
# "-m", "not integration",
|
|
67
|
+
#]
|
|
68
|
+
|
|
69
|
+
[tool.setuptools.packages.find]
|
|
70
|
+
where = ["src"]
|
|
71
|
+
|
|
72
|
+
[tool.setuptools.package-data]
|
|
73
|
+
niceemp_core = ["*.mo", "*.po"]
|
|
74
|
+
|
|
75
|
+
[tool.setuptools.dynamic]
|
|
76
|
+
version = { attr = "nsd_extension_framework.__version__" }
|
|
77
|
+
|
|
78
|
+
[dependency-groups]
|
|
79
|
+
typing = [
|
|
80
|
+
"django-stubs>=5.1.1",
|
|
81
|
+
"django-stubs-ext>=5.1.1",
|
|
82
|
+
"djangorestframework-stubs>=3.16.1",
|
|
83
|
+
"pyright>=1.1.390",
|
|
84
|
+
"mypy>=1.19.1",
|
|
85
|
+
]
|
|
86
|
+
dev = [
|
|
87
|
+
"behave>=1.3.3",
|
|
88
|
+
"pytest-bdd>=8.1.0",
|
|
89
|
+
"behave-django>=1.9.0",
|
|
90
|
+
"django-behave>=0.1.6",
|
|
91
|
+
"pytest-django>=4.12.0",
|
|
92
|
+
]
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
from django.apps import AppConfig as _AppConfig
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class AppConfig(_AppConfig):
|
|
6
|
+
name = "nsd_extension_framework"
|
|
7
|
+
|
|
8
|
+
def ready(self):
|
|
9
|
+
from django.conf import settings
|
|
10
|
+
if 'rest_framework' in settings.INSTALLED_APPS:
|
|
11
|
+
try:
|
|
12
|
+
from rest_framework import serializers
|
|
13
|
+
from nsd_extension_framework.db import ExtendedField
|
|
14
|
+
from nsd_extension_framework.drf import ExtendedDRFField
|
|
15
|
+
serializers.ModelSerializer.serializer_field_mapping[ExtendedField] = ExtendedDRFField
|
|
16
|
+
except ImportError:
|
|
17
|
+
pass
|