timetracker/games/forms.py

197 lines
6.0 KiB
Python
Raw Normal View History

2022-12-31 14:18:27 +01:00
from django import forms
from django.urls import reverse
2023-11-15 19:36:22 +01:00
2024-08-08 15:02:39 +02:00
from common.utils import safe_getattr
2025-01-29 22:05:06 +01:00
from games.models import Device, Game, Platform, Purchase, Session
2022-12-31 14:18:27 +01: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 12:40:02 +02:00
autofocus_input_widget = forms.TextInput(attrs={"autofocus": "autofocus"})
2022-12-31 14:18:27 +01:00
2025-02-08 17:54:03 +01:00
class MultipleGameChoiceField(forms.ModelMultipleChoiceField):
def label_from_instance(self, obj) -> str:
return f"{obj.sort_name} ({obj.platform}, {obj.year_released})"
class SingleGameChoiceField(forms.ModelChoiceField):
def label_from_instance(self, obj) -> str:
return f"{obj.sort_name} ({obj.platform}, {obj.year_released})"
2022-12-31 14:18:27 +01:00
class SessionForm(forms.ModelForm):
2025-02-08 17:54:03 +01:00
game = SingleGameChoiceField(
2025-01-29 22:05:06 +01:00
queryset=Game.objects.order_by("sort_name"),
widget=forms.Select(attrs={"autofocus": "autofocus"}),
2023-02-18 20:49:46 +01:00
)
device = forms.ModelChoiceField(queryset=Device.objects.order_by("name"))
2025-02-04 20:09:05 +01:00
mark_as_played = forms.BooleanField(
required=False,
initial={"mark_as_played": True},
label="Set game status to Played if Unplayed",
)
2022-12-31 14:18:27 +01:00
class Meta:
widgets = {
"timestamp_start": custom_datetime_widget,
"timestamp_end": custom_datetime_widget,
}
2022-12-31 14:18:27 +01:00
model = Session
fields = [
2025-01-29 22:05:06 +01:00
"game",
2022-12-31 14:18:27 +01:00
"timestamp_start",
"timestamp_end",
"duration_manual",
2025-01-29 13:43:35 +01:00
"emulated",
2023-02-18 21:12:18 +01:00
"device",
2022-12-31 14:18:27 +01:00
"note",
2025-02-04 20:09:05 +01:00
"mark_as_played",
2022-12-31 14:18:27 +01:00
]
2025-02-04 20:09:05 +01:00
def save(self, commit=True):
session = super().save(commit=False)
if self.cleaned_data.get("mark_as_played"):
game_instance = session.game
if game_instance.status == "u":
game_instance.status = "p"
if commit:
game_instance.save()
if commit:
session.save()
return session
2022-12-31 14:18:27 +01:00
class IncludePlatformSelect(forms.SelectMultiple):
def create_option(self, name, value, *args, **kwargs):
option = super().create_option(name, value, *args, **kwargs)
2024-06-03 18:19:11 +02:00
if platform_id := safe_getattr(value, "instance.platform.id"):
option["attrs"]["data-platform"] = platform_id
return option
2022-12-31 14:18:27 +01:00
class PurchaseForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# Automatically update related_purchase <select/>
2025-01-29 22:05:06 +01:00
# to only include purchases of the selected game.
related_purchase_by_game_url = reverse("related_purchase_by_game")
self.fields["games"].widget.attrs.update(
{
2023-11-16 19:03:16 +01:00
"hx-trigger": "load, click",
2025-01-29 22:05:06 +01:00
"hx-get": related_purchase_by_game_url,
"hx-target": "#id_related_purchase",
"hx-swap": "outerHTML",
}
)
2025-02-08 17:54:03 +01:00
games = MultipleGameChoiceField(
2025-01-29 22:05:06 +01:00
queryset=Game.objects.order_by("sort_name"),
widget=IncludePlatformSelect(attrs={"autoselect": "autoselect"}),
2023-09-30 12:40:02 +02:00
)
platform = forms.ModelChoiceField(queryset=Platform.objects.order_by("name"))
2023-11-14 19:27:00 +01:00
related_purchase = forms.ModelChoiceField(
queryset=Purchase.objects.filter(type=Purchase.GAME),
required=False,
2023-11-14 19:27:00 +01:00
)
2022-12-31 14:18:27 +01: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 14:18:27 +01:00
model = Purchase
2023-02-18 20:53:47 +01:00
fields = [
2025-01-29 22:05:06 +01:00
"games",
2023-02-18 20:53:47 +01:00
"platform",
"date_purchased",
"date_refunded",
"date_finished",
"date_dropped",
"infinite",
2023-02-18 20:53:47 +01:00
"price",
"price_currency",
"ownership_type",
2023-11-14 19:27:00 +01:00
"type",
"related_purchase",
"name",
2023-02-18 20:53:47 +01:00
]
2023-02-18 20:49:46 +01: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 20:49:46 +01: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 15:20:30 +01: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
2025-01-29 22:05:06 +01:00
class GameForm(forms.ModelForm):
platform = forms.ModelChoiceField(
queryset=Platform.objects.order_by("name"), required=False
)
2022-12-31 14:18:27 +01:00
class Meta:
model = Game
2025-02-04 20:09:05 +01:00
fields = [
"name",
"sort_name",
"platform",
"year_released",
"status",
"wikidata",
]
2023-09-30 12:40:02 +02:00
widgets = {"name": autofocus_input_widget}
2023-01-04 17:23:34 +01:00
class PlatformForm(forms.ModelForm):
class Meta:
model = Platform
fields = [
"name",
"icon",
"group",
]
2023-09-30 12:40:02 +02:00
widgets = {"name": autofocus_input_widget}
2023-02-18 21:12:18 +01:00
class DeviceForm(forms.ModelForm):
class Meta:
model = Device
fields = ["name", "type"]
2023-09-30 12:40:02 +02:00
widgets = {"name": autofocus_input_widget}