Name and related_purchase validation for non-games
This commit is contained in:
parent
9a1d24dbfd
commit
8783d1fc8e
|
@ -72,6 +72,10 @@ textarea:disabled {
|
||||||
@apply dark:bg-slate-700 dark:text-slate-400;
|
@apply dark:bg-slate-700 dark:text-slate-400;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.errorlist {
|
||||||
|
@apply mt-4 mb-1 pl-3 py-2 bg-red-600 text-slate-200 w-[300px];
|
||||||
|
}
|
||||||
|
|
||||||
@media screen and (min-width: 768px) {
|
@media screen and (min-width: 768px) {
|
||||||
form input,
|
form input,
|
||||||
select,
|
select,
|
||||||
|
|
|
@ -58,7 +58,8 @@ class PurchaseForm(forms.ModelForm):
|
||||||
related_purchase = forms.ModelChoiceField(
|
related_purchase = forms.ModelChoiceField(
|
||||||
queryset=Purchase.objects.filter(type=Purchase.GAME).order_by(
|
queryset=Purchase.objects.filter(type=Purchase.GAME).order_by(
|
||||||
"edition__sort_name"
|
"edition__sort_name"
|
||||||
)
|
),
|
||||||
|
required=False,
|
||||||
)
|
)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
|
@ -82,6 +83,27 @@ class PurchaseForm(forms.ModelForm):
|
||||||
"name",
|
"name",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
|
||||||
class IncludeNameSelect(forms.Select):
|
class IncludeNameSelect(forms.Select):
|
||||||
def create_option(self, name, value, *args, **kwargs):
|
def create_option(self, name, value, *args, **kwargs):
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
# Generated by Django 4.1.5 on 2023-11-15 12:04
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
("games", "0029_alter_purchase_related_purchase"),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name="purchase",
|
||||||
|
name="name",
|
||||||
|
field=models.CharField(blank=True, default="", max_length=255, null=True),
|
||||||
|
),
|
||||||
|
]
|
|
@ -2,6 +2,7 @@ from common.time import format_duration
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.db import models
|
from django.db import models
|
||||||
|
from django.core.exceptions import ValidationError
|
||||||
from django.db.models import F, Manager, Sum
|
from django.db.models import F, Manager, Sum
|
||||||
from zoneinfo import ZoneInfo
|
from zoneinfo import ZoneInfo
|
||||||
|
|
||||||
|
@ -118,9 +119,7 @@ class Purchase(models.Model):
|
||||||
max_length=2, choices=OWNERSHIP_TYPES, default=DIGITAL
|
max_length=2, choices=OWNERSHIP_TYPES, default=DIGITAL
|
||||||
)
|
)
|
||||||
type = models.CharField(max_length=255, choices=TYPES, default=GAME)
|
type = models.CharField(max_length=255, choices=TYPES, default=GAME)
|
||||||
name = models.CharField(
|
name = models.CharField(max_length=255, default="", null=True, blank=True)
|
||||||
max_length=255, default="Unknown Name", null=True, blank=True
|
|
||||||
)
|
|
||||||
related_purchase = models.ForeignKey(
|
related_purchase = models.ForeignKey(
|
||||||
"Purchase",
|
"Purchase",
|
||||||
on_delete=models.SET_NULL,
|
on_delete=models.SET_NULL,
|
||||||
|
@ -147,6 +146,10 @@ class Purchase(models.Model):
|
||||||
def save(self, *args, **kwargs):
|
def save(self, *args, **kwargs):
|
||||||
if self.type == Purchase.GAME:
|
if self.type == Purchase.GAME:
|
||||||
self.name = ""
|
self.name = ""
|
||||||
|
elif self.type != Purchase.GAME and not self.related_purchase:
|
||||||
|
raise ValidationError(
|
||||||
|
f"{self.get_type_display()} must have a related purchase."
|
||||||
|
)
|
||||||
super().save(*args, **kwargs)
|
super().save(*args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1231,6 +1231,19 @@ textarea:disabled) {
|
||||||
color: rgb(148 163 184 / var(--tw-text-opacity));
|
color: rgb(148 163 184 / var(--tw-text-opacity));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.errorlist {
|
||||||
|
margin-top: 1rem;
|
||||||
|
margin-bottom: 0.25rem;
|
||||||
|
width: 300px;
|
||||||
|
--tw-bg-opacity: 1;
|
||||||
|
background-color: rgb(220 38 38 / var(--tw-bg-opacity));
|
||||||
|
padding-top: 0.5rem;
|
||||||
|
padding-bottom: 0.5rem;
|
||||||
|
padding-left: 0.75rem;
|
||||||
|
--tw-text-opacity: 1;
|
||||||
|
color: rgb(226 232 240 / var(--tw-text-opacity));
|
||||||
|
}
|
||||||
|
|
||||||
@media screen and (min-width: 768px) {
|
@media screen and (min-width: 768px) {
|
||||||
form input,
|
form input,
|
||||||
select,
|
select,
|
||||||
|
|
Loading…
Reference in New Issue