From 9a832bca82062b1268bd38dbe34e4f8f9dae3271 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniele=20Vigan=C3=B2?= Date: Mon, 4 Nov 2024 22:27:23 +0100 Subject: [PATCH] Improve sorting --- ...er_options_alter_scale_options_and_more.py | 69 +++++++++++++++++++ ram/metadata/models.py | 56 +++++++++++---- ram/ram/__init__.py | 2 +- 3 files changed, 111 insertions(+), 16 deletions(-) create mode 100644 ram/metadata/migrations/0018_alter_decoder_options_alter_scale_options_and_more.py diff --git a/ram/metadata/migrations/0018_alter_decoder_options_alter_scale_options_and_more.py b/ram/metadata/migrations/0018_alter_decoder_options_alter_scale_options_and_more.py new file mode 100644 index 0000000..ff1bc74 --- /dev/null +++ b/ram/metadata/migrations/0018_alter_decoder_options_alter_scale_options_and_more.py @@ -0,0 +1,69 @@ +# Generated by Django 5.1.2 on 2024-11-04 21:17 + +import django.db.migrations.operations.special +import metadata.models +from django.db import migrations, models + + +def gen_ratio(apps, schema_editor): + Scale = apps.get_model('metadata', 'Scale') + for row in Scale.objects.all(): + row.ratio_int = metadata.models.calculate_ratio(row.ratio) + row.save(update_fields=['ratio_int']) + + +def convert_tarcks(apps, schema_editor): + Scale = apps.get_model("metadata", "Scale") + for row in Scale.objects.all(): + row.tracks = "".join( + filter( + lambda x: str.isdigit(x) or x == "." or x == ",", + row.tracks + ) + ) + row.save(update_fields=["tracks"]) + + +class Migration(migrations.Migration): + + dependencies = [ + ('metadata', '0017_alter_property_private'), + ] + + operations = [ + migrations.AlterModelOptions( + name='decoder', + options={'ordering': ['manufacturer__name', 'name']}, + ), + migrations.AlterModelOptions( + name='scale', + options={'ordering': ['ratio_int', 'scale']}, + ), + migrations.AddField( + model_name='scale', + name='ratio_int', + field=models.SmallIntegerField(default=0, editable=False), + ), + migrations.RunPython( + code=gen_ratio, + reverse_code=django.db.migrations.operations.special.RunPython.noop, + ), + migrations.AlterField( + model_name='scale', + name='ratio', + field=models.CharField(max_length=16, validators=[metadata.models.calculate_ratio]), + ), + migrations.AlterModelOptions( + name='scale', + options={'ordering': ['-ratio_int', '-tracks', 'scale']}, + ), + migrations.RunPython( + code=convert_tarcks, + reverse_code=django.db.migrations.operations.special.RunPython.noop, + ), + migrations.AlterField( + model_name='scale', + name='tracks', + field=models.FloatField(help_text='Distance between model tracks in mm'), + ), + ] diff --git a/ram/metadata/models.py b/ram/metadata/models.py index 982927c..01c9a35 100644 --- a/ram/metadata/models.py +++ b/ram/metadata/models.py @@ -3,6 +3,7 @@ from django.db import models from django.urls import reverse from django.conf import settings from django.dispatch.dispatcher import receiver +from django.core.exceptions import ValidationError from django_countries.fields import CountryField from ram.models import Document @@ -49,10 +50,11 @@ class Manufacturer(models.Model): def get_absolute_url(self): return reverse( - "filtered", kwargs={ + "filtered", + kwargs={ "_filter": "manufacturer", "search": self.slug, - } + }, ) def logo_thumbnail(self): @@ -83,10 +85,11 @@ class Company(models.Model): def get_absolute_url(self): return reverse( - "filtered", kwargs={ + "filtered", + kwargs={ "_filter": "company", "search": self.slug, - } + }, ) def extended_name_pp(self): @@ -115,7 +118,7 @@ class Decoder(models.Model): ) class Meta(object): - ordering = ["manufacturer", "name"] + ordering = ["manufacturer__name", "name"] def __str__(self): return "{0} - {1}".format(self.manufacturer, self.name) @@ -135,28 +138,49 @@ class DecoderDocument(Document): unique_together = ("decoder", "file") +def calculate_ratio(ratio): + try: + num, den = ratio.split(":") + return int(num) / float(den) * 10000 + except (ValueError, ZeroDivisionError): + raise ValidationError("Invalid ratio format") + + class Scale(models.Model): scale = models.CharField(max_length=32, unique=True) slug = models.CharField(max_length=32, unique=True, editable=False) - ratio = models.CharField(max_length=16, blank=True) - gauge = models.CharField(max_length=16, blank=True) - tracks = models.CharField(max_length=16, blank=True) + ratio = models.CharField(max_length=16, validators=[calculate_ratio]) + ratio_int = models.SmallIntegerField(editable=False, default=0) + tracks = models.FloatField( + help_text="Distance between model tracks in mm", + ) + gauge = models.CharField( + max_length=16, + blank=True, + help_text="Distance between real tracks. Please specify the unit (mm, in, ...)", # noqa: E501 + ) class Meta: - ordering = ["scale"] + ordering = ["-ratio_int", "-tracks", "scale"] def get_absolute_url(self): return reverse( - "filtered", kwargs={ + "filtered", + kwargs={ "_filter": "scale", "search": self.slug, - } + }, ) def __str__(self): return str(self.scale) +@receiver(models.signals.pre_save, sender=Scale) +def scale_save(sender, instance, **kwargs): + instance.ratio_int = calculate_ratio(instance.ratio) + + class RollingStockType(models.Model): type = models.CharField(max_length=64) order = models.PositiveSmallIntegerField() @@ -171,10 +195,11 @@ class RollingStockType(models.Model): def get_absolute_url(self): return reverse( - "filtered", kwargs={ + "filtered", + kwargs={ "_filter": "type", "search": self.slug, - } + }, ) def __str__(self): @@ -193,10 +218,11 @@ class Tag(models.Model): def get_absolute_url(self): return reverse( - "filtered", kwargs={ + "filtered", + kwargs={ "_filter": "tag", "search": self.slug, - } + }, ) diff --git a/ram/ram/__init__.py b/ram/ram/__init__.py index fc31aca..5f04d76 100644 --- a/ram/ram/__init__.py +++ b/ram/ram/__init__.py @@ -1,4 +1,4 @@ from ram.utils import git_suffix -__version__ = "0.13.2" +__version__ = "0.13.3" __version__ += git_suffix(__file__)