From d16e00d66b74c3244287ea7b782c86b87c9c821e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniele=20Vigan=C3=B2?= Date: Mon, 27 Jan 2025 00:34:44 +0100 Subject: [PATCH] Add shop field (from properties) (#48) * Add shop field (from properties) * Update template --- arduino/dcc-ex.github.io | 2 +- arduino/vim-arduino | 2 +- ram/bookshelf/admin.py | 7 ++- .../migrations/0022_basebook_shop.py | 46 +++++++++++++++++++ ram/bookshelf/models.py | 6 ++- ram/bookshelf/serializers.py | 2 +- ram/metadata/admin.py | 8 ++++ ram/metadata/migrations/0023_shop.py | 40 ++++++++++++++++ ram/metadata/models.py | 14 ++++++ ram/portal/templates/bookshelf/book.html | 7 +++ ram/portal/templates/rollingstock.html | 7 +++ ram/ram/__init__.py | 2 +- ram/roster/admin.py | 5 +- .../migrations/0034_rollingstock_shop.py | 46 +++++++++++++++++++ ram/roster/models.py | 4 ++ ram/roster/serializers.py | 2 +- 16 files changed, 191 insertions(+), 9 deletions(-) create mode 100644 ram/bookshelf/migrations/0022_basebook_shop.py create mode 100644 ram/metadata/migrations/0023_shop.py create mode 100644 ram/roster/migrations/0034_rollingstock_shop.py diff --git a/arduino/dcc-ex.github.io b/arduino/dcc-ex.github.io index e661bb0..9acc446 160000 --- a/arduino/dcc-ex.github.io +++ b/arduino/dcc-ex.github.io @@ -1 +1 @@ -Subproject commit e661bb0fab8dbe6a43c899ee2929bd2faa81a9f8 +Subproject commit 9acc446358e24a62d1ec1616bc32e0de9d5b4f3a diff --git a/arduino/vim-arduino b/arduino/vim-arduino index 2ded67c..111db61 160000 --- a/arduino/vim-arduino +++ b/arduino/vim-arduino @@ -1 +1 @@ -Subproject commit 2ded67cdf09bb07c4805d9e93d478095ed3d8606 +Subproject commit 111db616db21d4f925691f1517792953f7671647 diff --git a/ram/bookshelf/admin.py b/ram/bookshelf/admin.py index b5efe57..d506558 100644 --- a/ram/bookshelf/admin.py +++ b/ram/bookshelf/admin.py @@ -59,7 +59,7 @@ class BookAdmin(SortableAdminBase, admin.ModelAdmin): "number_of_pages", "published", ) - autocomplete_fields = ("authors", "publisher") + autocomplete_fields = ("authors", "publisher", "shop") readonly_fields = ("creation_time", "updated_time") search_fields = ("title", "publisher__name", "authors__last_name") list_filter = ("publisher__name", "authors") @@ -86,6 +86,7 @@ class BookAdmin(SortableAdminBase, admin.ModelAdmin): "Purchase data", { "fields": ( + "shop", "purchase_date", "price", ) @@ -133,6 +134,7 @@ class BookAdmin(SortableAdminBase, admin.ModelAdmin): "Publication Year", "Description", "Tags", + "Shop", "Purchase Date", "Price ({})".format(get_site_conf().currency), "Notes", @@ -158,6 +160,7 @@ class BookAdmin(SortableAdminBase, admin.ModelAdmin): settings.CSV_SEPARATOR_ALT.join( t.name for t in obj.tags.all() ), + obj.shop, obj.purchase_date, obj.price, html.unescape(strip_tags(obj.notes)), @@ -274,6 +277,7 @@ class CatalogAdmin(SortableAdminBase, admin.ModelAdmin): "Description", "Tags", "Purchase Date", + "Shop", "Price ({})".format(get_site_conf().currency), "Notes", "Properties", @@ -299,6 +303,7 @@ class CatalogAdmin(SortableAdminBase, admin.ModelAdmin): settings.CSV_SEPARATOR_ALT.join( t.name for t in obj.tags.all() ), + obj.shop, obj.purchase_date, obj.price, html.unescape(strip_tags(obj.notes)), diff --git a/ram/bookshelf/migrations/0022_basebook_shop.py b/ram/bookshelf/migrations/0022_basebook_shop.py new file mode 100644 index 0000000..5457845 --- /dev/null +++ b/ram/bookshelf/migrations/0022_basebook_shop.py @@ -0,0 +1,46 @@ +# Generated by Django 5.1.4 on 2025-01-26 14:32 + +import django.db.models.deletion +from django.db import migrations, models + + +def shop_from_property(apps, schema_editor): + basebook = apps.get_model("bookshelf", "BaseBook") + shop_model = apps.get_model("metadata", "Shop") + for row in basebook.objects.all(): + property = row.property.filter( + property__name__icontains="shop" + ).first() + if property: + shop, created = shop_model.objects.get_or_create( + name=property.value, + defaults={"on_line": False} + ) + + row.shop = shop + row.save() + + +class Migration(migrations.Migration): + + dependencies = [ + ("bookshelf", "0021_basebookdocument_creation_time_and_more"), + ("metadata", "0023_shop"), + ] + + operations = [ + migrations.AddField( + model_name="basebook", + name="shop", + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.CASCADE, + to="metadata.shop", + ), + ), + migrations.RunPython( + shop_from_property, + reverse_code=migrations.RunPython.noop + ), + ] diff --git a/ram/bookshelf/models.py b/ram/bookshelf/models.py index 6fbb3cf..0b81d7c 100644 --- a/ram/bookshelf/models.py +++ b/ram/bookshelf/models.py @@ -7,10 +7,9 @@ from django_countries.fields import CountryField from tinymce import models as tinymce -from metadata.models import Tag from ram.utils import DeduplicatedStorage from ram.models import BaseModel, Image, Document, PropertyInstance -from metadata.models import Scale, Manufacturer +from metadata.models import Scale, Manufacturer, Shop, Tag class Publisher(models.Model): @@ -50,6 +49,9 @@ class BaseBook(BaseModel): number_of_pages = models.SmallIntegerField(null=True, blank=True) publication_year = models.SmallIntegerField(null=True, blank=True) description = tinymce.HTMLField(blank=True) + shop = models.ForeignKey( + Shop, on_delete=models.CASCADE, null=True, blank=True + ) price = models.DecimalField( max_digits=10, decimal_places=2, diff --git a/ram/bookshelf/serializers.py b/ram/bookshelf/serializers.py index 88811ea..74c9bef 100644 --- a/ram/bookshelf/serializers.py +++ b/ram/bookshelf/serializers.py @@ -26,7 +26,7 @@ class BookSerializer(serializers.ModelSerializer): class Meta: model = Book - exclude = ("purchase_date", "price",) + exclude = ("shop", "purchase_date", "price",) read_only_fields = ("creation_time", "updated_time") diff --git a/ram/metadata/admin.py b/ram/metadata/admin.py index 5cdfec0..4592d4c 100644 --- a/ram/metadata/admin.py +++ b/ram/metadata/admin.py @@ -8,6 +8,7 @@ from metadata.models import ( Decoder, DecoderDocument, Scale, + Shop, Manufacturer, Company, Tag, @@ -130,3 +131,10 @@ class GenericDocumentAdmin(admin.ModelAdmin): ), ) actions = [publish, unpublish] + + +@admin.register(Shop) +class ShopAdmin(admin.ModelAdmin): + list_display = ("name", "on_line", "active") + list_filter = ("on_line", "active") + search_fields = ("name",) diff --git a/ram/metadata/migrations/0023_shop.py b/ram/metadata/migrations/0023_shop.py new file mode 100644 index 0000000..68583a2 --- /dev/null +++ b/ram/metadata/migrations/0023_shop.py @@ -0,0 +1,40 @@ +# Generated by Django 5.1.4 on 2025-01-26 14:27 + +import django_countries.fields +import django.db.models.functions.text +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("metadata", "0022_decoderdocument_creation_time_and_more"), + ] + + operations = [ + migrations.CreateModel( + name="Shop", + fields=[ + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("name", models.CharField(max_length=128, unique=True)), + ( + "country", + django_countries.fields.CountryField(blank=True, max_length=2), + ), + ("website", models.URLField(blank=True)), + ("on_line", models.BooleanField(default=True)), + ("active", models.BooleanField(default=True)), + ], + options={ + "ordering": [django.db.models.functions.text.Lower("name")], + }, + ), + ] diff --git a/ram/metadata/models.py b/ram/metadata/models.py index 0a5e880..be193f1 100644 --- a/ram/metadata/models.py +++ b/ram/metadata/models.py @@ -247,6 +247,20 @@ class GenericDocument(Document): verbose_name_plural = "Generic Documents" +class Shop(models.Model): + name = models.CharField(max_length=128, unique=True) + country = CountryField(blank=True) + website = models.URLField(blank=True) + on_line = models.BooleanField(default=True) + active = models.BooleanField(default=True) + + class Meta: + ordering = [models.functions.Lower("name"),] + + def __str__(self): + return self.name + + @receiver(models.signals.pre_save, sender=Manufacturer) @receiver(models.signals.pre_save, sender=Company) @receiver(models.signals.pre_save, sender=Scale) diff --git a/ram/portal/templates/bookshelf/book.html b/ram/portal/templates/bookshelf/book.html index 05661d7..3be6e17 100644 --- a/ram/portal/templates/bookshelf/book.html +++ b/ram/portal/templates/bookshelf/book.html @@ -128,6 +128,13 @@ + + Shop + + {{ book.shop|default:"-" }} + {% if book.shop.website %} {% endif %} + + Purchase date {{ book.purchase_date|default:"-" }} diff --git a/ram/portal/templates/rollingstock.html b/ram/portal/templates/rollingstock.html index f95eda6..fbba043 100644 --- a/ram/portal/templates/rollingstock.html +++ b/ram/portal/templates/rollingstock.html @@ -214,6 +214,13 @@ + + Shop + + {{ rolling_stock.shop|default:"-" }} + {% if rolling_stock.shop.website %} {% endif %} + + Purchase date {{ rolling_stock.purchase_date|default:"-" }} diff --git a/ram/ram/__init__.py b/ram/ram/__init__.py index 0270948..10b4281 100644 --- a/ram/ram/__init__.py +++ b/ram/ram/__init__.py @@ -1,4 +1,4 @@ from ram.utils import git_suffix -__version__ = "0.16.4" +__version__ = "0.16.5" __version__ += git_suffix(__file__) diff --git a/ram/roster/admin.py b/ram/roster/admin.py index 026c56e..86e52c7 100644 --- a/ram/roster/admin.py +++ b/ram/roster/admin.py @@ -151,7 +151,7 @@ class RollingStockAdmin(SortableAdminBase, admin.ModelAdmin): RollingStockDocInline, RollingStockJournalInline, ) - autocomplete_fields = ("rolling_class",) + autocomplete_fields = ("rolling_class", "shop") readonly_fields = ("preview", "creation_time", "updated_time") list_display = ( "__str__", @@ -220,6 +220,7 @@ class RollingStockAdmin(SortableAdminBase, admin.ModelAdmin): "Purchase data", { "fields": ( + "shop", "purchase_date", "price", ) @@ -266,6 +267,7 @@ class RollingStockAdmin(SortableAdminBase, admin.ModelAdmin): "Decoder Interface", "Decoder", "Address", + "Shop", "Purchase Date", "Price ({})".format(get_site_conf().currency), "Properties", @@ -297,6 +299,7 @@ class RollingStockAdmin(SortableAdminBase, admin.ModelAdmin): obj.decoder, obj.address, obj.purchase_date, + obj.shop, obj.price, properties, ] diff --git a/ram/roster/migrations/0034_rollingstock_shop.py b/ram/roster/migrations/0034_rollingstock_shop.py new file mode 100644 index 0000000..c229a93 --- /dev/null +++ b/ram/roster/migrations/0034_rollingstock_shop.py @@ -0,0 +1,46 @@ +# Generated by Django 5.1.4 on 2025-01-26 14:32 + +import django.db.models.deletion +from django.db import migrations, models + + +def shop_from_property(apps, schema_editor): + rolling_stock = apps.get_model("roster", "RollingStock") + shop_model = apps.get_model("metadata", "Shop") + for row in rolling_stock.objects.all(): + property = row.property.filter( + property__name__icontains="shop" + ).first() + if property: + shop, created = shop_model.objects.get_or_create( + name=property.value, + defaults={"on_line": False} + ) + + row.shop = shop + row.save() + + +class Migration(migrations.Migration): + + dependencies = [ + ("metadata", "0023_shop"), + ("roster", "0033_rename_manufacturer_rollingclass_manufacturer_old"), + ] + + operations = [ + migrations.AddField( + model_name="rollingstock", + name="shop", + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.CASCADE, + to="metadata.shop", + ), + ), + migrations.RunPython( + shop_from_property, + reverse_code=migrations.RunPython.noop + ), + ] diff --git a/ram/roster/models.py b/ram/roster/models.py index 479ad5c..288c54b 100644 --- a/ram/roster/models.py +++ b/ram/roster/models.py @@ -14,6 +14,7 @@ from ram.managers import PublicManager from metadata.models import ( Scale, Manufacturer, + Shop, Decoder, Company, Tag, @@ -102,6 +103,9 @@ class RollingStock(BaseModel): help_text="Era or epoch of the model", ) production_year = models.SmallIntegerField(null=True, blank=True) + shop = models.ForeignKey( + Shop, on_delete=models.CASCADE, null=True, blank=True + ) purchase_date = models.DateField(null=True, blank=True) price = models.DecimalField( max_digits=10, diff --git a/ram/roster/serializers.py b/ram/roster/serializers.py index e5d5aed..89de92a 100644 --- a/ram/roster/serializers.py +++ b/ram/roster/serializers.py @@ -29,5 +29,5 @@ class RollingStockSerializer(serializers.ModelSerializer): class Meta: model = RollingStock - exclude = ("purchase_date", "price",) + exclude = ("shop", "purchase_date", "price",) read_only_fields = ("creation_time", "updated_time")