timetracker/games/forms.py

176 lines
5.6 KiB
Python
Raw Permalink Normal View History

2022-12-31 13:18:27 +00:00
from django import forms
from django.urls import reverse
2023-11-15 18:36:22 +00:00
2024-08-08 13:02:39 +00:00
from common.utils import safe_getattr
2023-11-15 18:36:22 +00:00
from games.models import Device, Edition, Game, Platform, Purchase, Session
2022-12-31 13:18:27 +00:00
custom_date_widget = forms.DateInput(attrs={"type": "date"})
custom_datetime_widget = forms.DateTimeInput(
attrs={"type": "datetime-local"}, format="%Y-%m-%d %H:%M"
)
2023-09-30 10:40:02 +00:00
autofocus_input_widget = forms.TextInput(attrs={"autofocus": "autofocus"})
2022-12-31 13:18:27 +00:00
class SessionForm(forms.ModelForm):
# purchase = forms.ModelChoiceField(
# queryset=Purchase.objects.filter(date_refunded=None).order_by("edition__name")
# )
2023-02-18 19:49:46 +00:00
purchase = forms.ModelChoiceField(
queryset=Purchase.objects.order_by("edition__sort_name"),
widget=forms.Select(attrs={"autofocus": "autofocus"}),
2023-02-18 19:49:46 +00:00
)
device = forms.ModelChoiceField(queryset=Device.objects.order_by("name"))
2022-12-31 13:18:27 +00:00
class Meta:
widgets = {
"timestamp_start": custom_datetime_widget,
"timestamp_end": custom_datetime_widget,
}
2022-12-31 13:18:27 +00:00
model = Session
fields = [
"purchase",
"timestamp_start",
"timestamp_end",
"duration_manual",
2023-02-18 20:12:18 +00:00
"device",
2022-12-31 13:18:27 +00:00
"note",
]
class EditionChoiceField(forms.ModelChoiceField):
def label_from_instance(self, obj) -> str:
return f"{obj.sort_name} ({obj.platform}, {obj.year_released})"
class IncludePlatformSelect(forms.Select):
def create_option(self, name, value, *args, **kwargs):
option = super().create_option(name, value, *args, **kwargs)
2024-06-03 16:19:11 +00:00
if platform_id := safe_getattr(value, "instance.platform.id"):
option["attrs"]["data-platform"] = platform_id
return option
2022-12-31 13:18:27 +00:00
class PurchaseForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# Automatically update related_purchase <select/>
# to only include purchases of the selected edition.
related_purchase_by_edition_url = reverse("related_purchase_by_edition")
self.fields["edition"].widget.attrs.update(
{
2023-11-16 18:03:16 +00:00
"hx-trigger": "load, click",
"hx-get": related_purchase_by_edition_url,
"hx-target": "#id_related_purchase",
"hx-swap": "outerHTML",
}
)
2023-09-30 10:40:02 +00:00
edition = EditionChoiceField(
queryset=Edition.objects.order_by("sort_name"),
widget=IncludePlatformSelect(attrs={"autoselect": "autoselect"}),
2023-09-30 10:40:02 +00:00
)
platform = forms.ModelChoiceField(queryset=Platform.objects.order_by("name"))
2023-11-14 18:27:00 +00:00
related_purchase = forms.ModelChoiceField(
queryset=Purchase.objects.filter(type=Purchase.GAME).order_by(
"edition__sort_name"
),
required=False,
2023-11-14 18:27:00 +00:00
)
2022-12-31 13:18:27 +00:00
class Meta:
widgets = {
"date_purchased": custom_date_widget,
"date_refunded": custom_date_widget,
"date_finished": custom_date_widget,
"date_dropped": custom_date_widget,
}
2022-12-31 13:18:27 +00:00
model = Purchase
2023-02-18 19:53:47 +00:00
fields = [
"edition",
"platform",
"date_purchased",
"date_refunded",
"date_finished",
"date_dropped",
"infinite",
2023-02-18 19:53:47 +00:00
"price",
"price_currency",
"ownership_type",
2023-11-14 18:27:00 +00:00
"type",
"related_purchase",
"name",
2023-02-18 19:53:47 +00:00
]
2023-02-18 19:49:46 +00:00
def clean(self):
cleaned_data = super().clean()
purchase_type = cleaned_data.get("type")
related_purchase = cleaned_data.get("related_purchase")
name = cleaned_data.get("name")
# Set the type on the instance to use get_type_display()
# This is safe because we're not saving the instance.
self.instance.type = purchase_type
if purchase_type != Purchase.GAME:
type_display = self.instance.get_type_display()
if not related_purchase:
self.add_error(
"related_purchase",
f"{type_display} must have a related purchase.",
)
if not name:
self.add_error("name", f"{type_display} must have a name.")
return cleaned_data
2023-02-18 19:49:46 +00:00
class IncludeNameSelect(forms.Select):
def create_option(self, name, value, *args, **kwargs):
option = super().create_option(name, value, *args, **kwargs)
if value:
option["attrs"]["data-name"] = value.instance.name
2023-11-09 14:20:30 +00:00
option["attrs"]["data-year"] = value.instance.year_released
return option
class GameModelChoiceField(forms.ModelChoiceField):
def label_from_instance(self, obj):
# Use sort_name as the label for the option
return obj.sort_name
2023-02-18 19:49:46 +00:00
class EditionForm(forms.ModelForm):
game = GameModelChoiceField(
queryset=Game.objects.order_by("sort_name"),
widget=IncludeNameSelect(attrs={"autofocus": "autofocus"}),
2023-09-30 10:40:02 +00:00
)
platform = forms.ModelChoiceField(
queryset=Platform.objects.order_by("name"), required=False
)
2023-02-18 19:49:46 +00:00
class Meta:
model = Edition
fields = ["game", "name", "sort_name", "platform", "year_released", "wikidata"]
2022-12-31 13:18:27 +00:00
class GameForm(forms.ModelForm):
class Meta:
model = Game
fields = ["name", "sort_name", "year_released", "wikidata"]
2023-09-30 10:40:02 +00:00
widgets = {"name": autofocus_input_widget}
2023-01-04 16:23:34 +00:00
class PlatformForm(forms.ModelForm):
class Meta:
model = Platform
fields = ["name", "group"]
2023-09-30 10:40:02 +00:00
widgets = {"name": autofocus_input_widget}
2023-02-18 20:12:18 +00:00
class DeviceForm(forms.ModelForm):
class Meta:
model = Device
fields = ["name", "type"]
2023-09-30 10:40:02 +00:00
widgets = {"name": autofocus_input_widget}