Fix readability and avoid instantiating too many TypeAdapter

This commit is contained in:
Antoine Bartuccio 2024-10-28 18:08:13 +01:00
parent e583e78a4e
commit a6b32fcad1
6 changed files with 62 additions and 41 deletions

View File

@ -1,3 +1,5 @@
from pydantic import TypeAdapter
from accounting.models import ClubAccount, Company from accounting.models import ClubAccount, Company
from accounting.schemas import ClubAccountSchema, CompanySchema from accounting.schemas import ClubAccountSchema, CompanySchema
from core.views.widgets.select import AutoCompleteSelect, AutoCompleteSelectMultiple from core.views.widgets.select import AutoCompleteSelect, AutoCompleteSelectMultiple
@ -8,7 +10,7 @@ _js = ["webpack/accounting/components/ajax-select-index.ts"]
class AutoCompleteSelectClubAccount(AutoCompleteSelect): class AutoCompleteSelectClubAccount(AutoCompleteSelect):
component_name = "club-account-ajax-select" component_name = "club-account-ajax-select"
model = ClubAccount model = ClubAccount
schema = ClubAccountSchema adapter = TypeAdapter(list[ClubAccountSchema])
js = _js js = _js
@ -16,7 +18,7 @@ class AutoCompleteSelectClubAccount(AutoCompleteSelect):
class AutoCompleteSelectMultipleClubAccount(AutoCompleteSelectMultiple): class AutoCompleteSelectMultipleClubAccount(AutoCompleteSelectMultiple):
component_name = "club-account-ajax-select" component_name = "club-account-ajax-select"
model = ClubAccount model = ClubAccount
schema = ClubAccountSchema adapter = TypeAdapter(list[ClubAccountSchema])
js = _js js = _js
@ -24,7 +26,7 @@ class AutoCompleteSelectMultipleClubAccount(AutoCompleteSelectMultiple):
class AutoCompleteSelectCompany(AutoCompleteSelect): class AutoCompleteSelectCompany(AutoCompleteSelect):
component_name = "company-ajax-select" component_name = "company-ajax-select"
model = Company model = Company
schema = CompanySchema adapter = TypeAdapter(list[CompanySchema])
js = _js js = _js
@ -32,6 +34,6 @@ class AutoCompleteSelectCompany(AutoCompleteSelect):
class AutoCompleteSelectMultipleCompany(AutoCompleteSelectMultiple): class AutoCompleteSelectMultipleCompany(AutoCompleteSelectMultiple):
component_name = "company-ajax-select" component_name = "company-ajax-select"
model = Company model = Company
schema = CompanySchema adapter = TypeAdapter(list[CompanySchema])
js = _js js = _js

View File

@ -1,3 +1,5 @@
from pydantic import TypeAdapter
from club.models import Club from club.models import Club
from club.schemas import ClubSchema from club.schemas import ClubSchema
from core.views.widgets.select import AutoCompleteSelect, AutoCompleteSelectMultiple from core.views.widgets.select import AutoCompleteSelect, AutoCompleteSelectMultiple
@ -8,7 +10,7 @@ _js = ["webpack/club/components/ajax-select-index.ts"]
class AutoCompleteSelectClub(AutoCompleteSelect): class AutoCompleteSelectClub(AutoCompleteSelect):
component_name = "club-ajax-select" component_name = "club-ajax-select"
model = Club model = Club
schema = ClubSchema adapter = TypeAdapter(list[ClubSchema])
js = _js js = _js
@ -16,6 +18,6 @@ class AutoCompleteSelectClub(AutoCompleteSelect):
class AutoCompleteSelectMultipleClub(AutoCompleteSelectMultiple): class AutoCompleteSelectMultipleClub(AutoCompleteSelectMultiple):
component_name = "club-ajax-select" component_name = "club-ajax-select"
model = Club model = Club
schema = ClubSchema adapter = TypeAdapter(list[ClubSchema])
js = _js js = _js

View File

@ -5,9 +5,19 @@
<link-once rel="stylesheet" type="text/css" href="{{ css }}" defer></link-once> <link-once rel="stylesheet" type="text/css" href="{{ css }}" defer></link-once>
{% endfor %} {% endfor %}
<{{ component }} name="{{ widget.name }}"{% include "django/forms/widgets/attrs.html" %}>{% for group_name, group_choices, group_index in widget.optgroups %}{% if group_name %} <{{ component }} name="{{ widget.name }}"{% include "django/forms/widgets/attrs.html" %}>
<optgroup label="{{ group_name }}">{% endif %}{% for widget in group_choices %} {% for group_name, group_choices, group_index in widget.optgroups %}
{% include widget.template_name %}{% endfor %}{% if group_name %} {% if group_name %}
</optgroup>{% endif %}{% endfor %} <optgroup label="{{ group_name }}">
{% if initial %}<slot style="display:none" name="initial">{{ initial }}</slot>{% endif %} {% endif %}
{% for widget in group_choices %}
{% include widget.template_name %}
{% endfor %}
{% if group_name %}
</optgroup>
{% endif %}
{% endfor %}
{% if initial %}
<slot style="display:none" name="initial">{{ initial }}</slot>
{% endif %}
</{{ component }}> </{{ component }}>

View File

@ -1,5 +1,8 @@
from collections.abc import Collection
from typing import Any
from django.contrib.staticfiles.storage import staticfiles_storage from django.contrib.staticfiles.storage import staticfiles_storage
from django.db.models import Model from django.db.models import Model, QuerySet
from django.forms import Select, SelectMultiple from django.forms import Select, SelectMultiple
from ninja import ModelSchema from ninja import ModelSchema
from pydantic import TypeAdapter from pydantic import TypeAdapter
@ -11,8 +14,8 @@ from core.schemas import GroupSchema, SithFileSchema, UserProfileSchema
class AutoCompleteSelectMixin: class AutoCompleteSelectMixin:
component_name = "autocomplete-select" component_name = "autocomplete-select"
template_name = "core/widgets/autocomplete_select.jinja" template_name = "core/widgets/autocomplete_select.jinja"
model: Model | None = None model: type[Model] | None = None
schema: ModelSchema | None = None adapter: TypeAdapter[Collection[ModelSchema]] | None = None
pk = "id" pk = "id"
js = [ js = [
@ -23,6 +26,17 @@ class AutoCompleteSelectMixin:
"core/components/ajax-select.scss", "core/components/ajax-select.scss",
] ]
def get_queryset(self, pks: Collection[Any]) -> QuerySet:
return self.model.objects.filter(
**{
f"{self.pk}__in": [
pk
for pk in pks
if str(pk).isdigit() # We filter empty values for create views
]
}
).all()
def __init__(self, attrs=None, choices=()): def __init__(self, attrs=None, choices=()):
if self.is_ajax: if self.is_ajax:
choices = () # Avoid computing anything when in ajax mode choices = () # Avoid computing anything when in ajax mode
@ -30,7 +44,7 @@ class AutoCompleteSelectMixin:
@property @property
def is_ajax(self): def is_ajax(self):
return self.model and self.schema return self.adapter and self.model
def optgroups(self, name, value, attrs=None): def optgroups(self, name, value, attrs=None):
"""Don't create option groups when doing ajax""" """Don't create option groups when doing ajax"""
@ -47,20 +61,9 @@ class AutoCompleteSelectMixin:
"css": [staticfiles_storage.url(file) for file in self.css], "css": [staticfiles_storage.url(file) for file in self.css],
} }
if self.is_ajax: if self.is_ajax:
adapter = TypeAdapter(list[self.schema]) context["initial"] = self.adapter.dump_json(
context["initial"] = adapter.dump_json( self.adapter.validate_python(
adapter.validate_python( self.get_queryset(context["widget"]["value"])
self.model.objects.filter(
**{
f"{self.pk}__in": [
pk
for pk in context["widget"]["value"]
if str(
pk
).isdigit() # We filter empty values for create views
]
}
).all()
) )
).decode("utf-8") ).decode("utf-8")
return context return context
@ -75,34 +78,34 @@ class AutoCompleteSelectMultiple(AutoCompleteSelectMixin, SelectMultiple): ...
class AutoCompleteSelectUser(AutoCompleteSelect): class AutoCompleteSelectUser(AutoCompleteSelect):
component_name = "user-ajax-select" component_name = "user-ajax-select"
model = User model = User
schema = UserProfileSchema adapter = TypeAdapter(list[UserProfileSchema])
class AutoCompleteSelectMultipleUser(AutoCompleteSelectMultiple): class AutoCompleteSelectMultipleUser(AutoCompleteSelectMultiple):
component_name = "user-ajax-select" component_name = "user-ajax-select"
model = User model = User
schema = UserProfileSchema adapter = TypeAdapter(list[UserProfileSchema])
class AutoCompleteSelectGroup(AutoCompleteSelect): class AutoCompleteSelectGroup(AutoCompleteSelect):
component_name = "group-ajax-select" component_name = "group-ajax-select"
model = Group model = Group
schema = GroupSchema adapter = TypeAdapter(list[GroupSchema])
class AutoCompleteSelectMultipleGroup(AutoCompleteSelectMultiple): class AutoCompleteSelectMultipleGroup(AutoCompleteSelectMultiple):
component_name = "group-ajax-select" component_name = "group-ajax-select"
model = Group model = Group
schema = GroupSchema adapter = TypeAdapter(list[GroupSchema])
class AutoCompleteSelectSithFile(AutoCompleteSelect): class AutoCompleteSelectSithFile(AutoCompleteSelect):
component_name = "sith-file-ajax-select" component_name = "sith-file-ajax-select"
model = SithFile model = SithFile
schema = SithFileSchema adapter = TypeAdapter(list[SithFileSchema])
class AutoCompleteSelectMultipleSithFile(AutoCompleteSelectMultiple): class AutoCompleteSelectMultipleSithFile(AutoCompleteSelectMultiple):
component_name = "sith-file-ajax-select" component_name = "sith-file-ajax-select"
model = SithFile model = SithFile
schema = SithFileSchema adapter = TypeAdapter(list[SithFileSchema])

View File

@ -1,3 +1,5 @@
from pydantic import TypeAdapter
from core.views.widgets.select import AutoCompleteSelect, AutoCompleteSelectMultiple from core.views.widgets.select import AutoCompleteSelect, AutoCompleteSelectMultiple
from counter.models import Counter, Product from counter.models import Counter, Product
from counter.schemas import ProductSchema, SimplifiedCounterSchema from counter.schemas import ProductSchema, SimplifiedCounterSchema
@ -8,26 +10,26 @@ _js = ["webpack/counter/components/ajax-select-index.ts"]
class AutoCompleteSelectCounter(AutoCompleteSelect): class AutoCompleteSelectCounter(AutoCompleteSelect):
component_name = "counter-ajax-select" component_name = "counter-ajax-select"
model = Counter model = Counter
schema = SimplifiedCounterSchema adapter = TypeAdapter(list[SimplifiedCounterSchema])
js = _js js = _js
class AutoCompleteSelectMultipleCounter(AutoCompleteSelectMultiple): class AutoCompleteSelectMultipleCounter(AutoCompleteSelectMultiple):
component_name = "counter-ajax-select" component_name = "counter-ajax-select"
model = Counter model = Counter
schema = SimplifiedCounterSchema adapter = TypeAdapter(list[SimplifiedCounterSchema])
js = _js js = _js
class AutoCompleteSelectProduct(AutoCompleteSelect): class AutoCompleteSelectProduct(AutoCompleteSelect):
component_name = "product-ajax-select" component_name = "product-ajax-select"
model = Product model = Product
schema = ProductSchema adapter = TypeAdapter(list[ProductSchema])
js = _js js = _js
class AutoCompleteSelectMultipleProduct(AutoCompleteSelectMultiple): class AutoCompleteSelectMultipleProduct(AutoCompleteSelectMultiple):
component_name = "product-ajax-select" component_name = "product-ajax-select"
model = Product model = Product
schema = ProductSchema adapter = TypeAdapter(list[ProductSchema])
js = _js js = _js

View File

@ -1,3 +1,5 @@
from pydantic import TypeAdapter
from core.views.widgets.select import ( from core.views.widgets.select import (
AutoCompleteSelect, AutoCompleteSelect,
AutoCompleteSelectMultiple, AutoCompleteSelectMultiple,
@ -11,7 +13,7 @@ _js = ["webpack/sas/components/ajax-select-index.ts"]
class AutoCompleteSelectAlbum(AutoCompleteSelect): class AutoCompleteSelectAlbum(AutoCompleteSelect):
component_name = "album-ajax-select" component_name = "album-ajax-select"
model = Album model = Album
schema = AlbumSchema adapter = TypeAdapter(list[AlbumSchema])
js = _js js = _js
@ -19,6 +21,6 @@ class AutoCompleteSelectAlbum(AutoCompleteSelect):
class AutoCompleteSelectMultipleAlbum(AutoCompleteSelectMultiple): class AutoCompleteSelectMultipleAlbum(AutoCompleteSelectMultiple):
component_name = "album-ajax-select" component_name = "album-ajax-select"
model = Album model = Album
schema = AlbumSchema adapter = TypeAdapter(list[AlbumSchema])
js = _js js = _js