diff --git a/dcc/dcc/settings.py b/dcc/dcc/settings.py index 4daef69..6eaa721 100644 --- a/dcc/dcc/settings.py +++ b/dcc/dcc/settings.py @@ -134,3 +134,8 @@ DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' MEDIA_URL = 'media/' MEDIA_ROOT = os.path.join(BASE_DIR, 'media') + +ROLLING_STOCK_TYPES = [ + ("engine", "Engine"), ("car", "Car"), + ("equipment", "Equipment"), ("other", "Other") +] diff --git a/dcc/dcc/utils.py b/dcc/dcc/utils.py index 1c3efea..a2b6f59 100644 --- a/dcc/dcc/utils.py +++ b/dcc/dcc/utils.py @@ -1,7 +1,16 @@ from django.utils.html import format_html +from django.utils.text import slugify as django_slugify def get_image_preview(url): return format_html( '' % url) + + +def slugify(string, custom_separator=None): + # Make slug 'flat', both '-' and '_' are replaced with '-' + string = django_slugify(string).replace('_', '-') + if custom_separator is not None: + string = string.replace('-', custom_separator) + return string diff --git a/dcc/driver/migrations/0001_initial.py b/dcc/driver/migrations/0001_initial.py index 361b620..ca9c7bf 100644 --- a/dcc/driver/migrations/0001_initial.py +++ b/dcc/driver/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 4.0 on 2021-12-31 10:41 +# Generated by Django 4.0.2 on 2022-04-01 20:25 from django.db import migrations, models @@ -17,9 +17,10 @@ class Migration(migrations.Migration): ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('remote_host', models.GenericIPAddressField(default='192.168.4.1', protocol='IPv4')), ('remote_port', models.SmallIntegerField(default=2560)), + ('timeout', models.SmallIntegerField(default=250)), ], options={ - 'verbose_name': 'Driver Configuration', + 'verbose_name': 'Configuration', }, ), ] diff --git a/dcc/driver/migrations/0002_alter_driverconfiguration_options_and_more.py b/dcc/driver/migrations/0002_alter_driverconfiguration_options_and_more.py deleted file mode 100644 index f6d0609..0000000 --- a/dcc/driver/migrations/0002_alter_driverconfiguration_options_and_more.py +++ /dev/null @@ -1,22 +0,0 @@ -# Generated by Django 4.0 on 2022-01-03 19:53 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('driver', '0001_initial'), - ] - - operations = [ - migrations.AlterModelOptions( - name='driverconfiguration', - options={'verbose_name': 'Configuration'}, - ), - migrations.AddField( - model_name='driverconfiguration', - name='timeout', - field=models.SmallIntegerField(default=250), - ), - ] diff --git a/dcc/driver/views.py b/dcc/driver/views.py index fa86425..1b9236b 100644 --- a/dcc/driver/views.py +++ b/dcc/driver/views.py @@ -8,7 +8,7 @@ from dcc.parsers import PlainTextParser from driver.connector import Connector from driver.serializers import ( FunctionSerializer, CabSerializer, InfraSerializer) -from roster.models import Cab as CabModel +from roster.models import RollingStock def addresschecker(f): @@ -16,9 +16,7 @@ def addresschecker(f): Check if DCC address does exist in the database """ def addresslookup(request, address, *args): - try: - CabModel.objects.get(address=address) - except CabModel.DoesNotExist: + if not RollingStock.objects.filter(address=address): raise Http404 return f(request, address, *args) return addresslookup diff --git a/dcc/metadata/admin.py b/dcc/metadata/admin.py index 19430b7..98bd15f 100644 --- a/dcc/metadata/admin.py +++ b/dcc/metadata/admin.py @@ -1,5 +1,6 @@ from django.contrib import admin -from metadata.models import Decoder, Manufacturer, Company +from metadata.models import ( + Decoder, Manufacturer, Company, Tag, RollingStockType) @admin.register(Decoder) @@ -15,3 +16,14 @@ class CompanyAdmin(admin.ModelAdmin): @admin.register(Manufacturer) class ManufacturerAdmin(admin.ModelAdmin): readonly_fields = ('logo_thumbnail',) + + +@admin.register(Tag) +class TagAdmin(admin.ModelAdmin): + readonly_fields = ('slug',) + + +@admin.register(RollingStockType) +class RollingStockTypeAdmin(admin.ModelAdmin): + list_display = ('type', 'category') + list_filter = list_display diff --git a/dcc/metadata/migrations/0001_initial.py b/dcc/metadata/migrations/0001_initial.py index 5d00089..c3e1d3c 100644 --- a/dcc/metadata/migrations/0001_initial.py +++ b/dcc/metadata/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 4.0 on 2021-12-20 21:37 +# Generated by Django 4.0.2 on 2022-04-01 20:25 from django.db import migrations, models import django.db.models.deletion @@ -19,6 +19,7 @@ class Migration(migrations.Migration): ('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(max_length=2)), + ('logo', models.ImageField(blank=True, null=True, upload_to='images/')), ], options={ 'verbose_name_plural': 'Companies', @@ -29,13 +30,36 @@ class Migration(migrations.Migration): fields=[ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('name', models.CharField(max_length=128, unique=True)), + ('logo', models.ImageField(blank=True, null=True, upload_to='images/')), ], ), + migrations.CreateModel( + name='Tag', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=128, unique=True)), + ('slug', models.CharField(max_length=128, unique=True)), + ], + ), + migrations.CreateModel( + name='RollingStockType', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('type', models.CharField(max_length=64)), + ('category', models.CharField(choices=[('engine', 'Engine'), ('car', 'Car'), ('equipment', 'Equipment'), ('other', 'Other')], max_length=64)), + ], + options={ + 'unique_together': {('category', 'type')}, + }, + ), migrations.CreateModel( name='Decoder', fields=[ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('name', models.CharField(max_length=128, unique=True)), + ('version', models.CharField(blank=True, max_length=64)), + ('interface', models.PositiveSmallIntegerField(blank=True, choices=[(1, 'NEM651'), (2, 'NEM652'), (3, 'PluX'), (4, '21MTC'), (5, 'Next18/Next18S')], null=True)), + ('image', models.ImageField(blank=True, null=True, upload_to='images/')), ('manufacturer', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='metadata.manufacturer')), ], ), diff --git a/dcc/metadata/migrations/0002_decoder_version.py b/dcc/metadata/migrations/0002_decoder_version.py deleted file mode 100644 index d5c2e1d..0000000 --- a/dcc/metadata/migrations/0002_decoder_version.py +++ /dev/null @@ -1,18 +0,0 @@ -# Generated by Django 4.0 on 2021-12-20 21:42 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('metadata', '0001_initial'), - ] - - operations = [ - migrations.AddField( - model_name='decoder', - name='version', - field=models.CharField(blank=True, max_length=64), - ), - ] diff --git a/dcc/metadata/migrations/0003_metadata_extend.py b/dcc/metadata/migrations/0003_metadata_extend.py deleted file mode 100644 index 84bfead..0000000 --- a/dcc/metadata/migrations/0003_metadata_extend.py +++ /dev/null @@ -1,35 +0,0 @@ -# Generated by Django 4.0.1 on 2022-01-29 18:41 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - replaces = [('metadata', '0003_company_logo_decoder_image_manufacturer_logo'), ('metadata', '0004_decoder_interface'), ('metadata', '0005_alter_decoder_interface'), ('metadata', '0006_alter_decoder_interface')] - - dependencies = [ - ('metadata', '0002_decoder_version'), - ] - - operations = [ - migrations.AddField( - model_name='company', - name='logo', - field=models.ImageField(blank=True, null=True, upload_to='images/'), - ), - migrations.AddField( - model_name='decoder', - name='image', - field=models.ImageField(blank=True, null=True, upload_to='images/'), - ), - migrations.AddField( - model_name='manufacturer', - name='logo', - field=models.ImageField(blank=True, null=True, upload_to='images/'), - ), - migrations.AddField( - model_name='decoder', - name='interface', - field=models.PositiveSmallIntegerField(blank=True, choices=[(1, 'NEM651'), (2, 'NEM652'), (3, 'PluX'), (4, '21MTC'), (5, 'Next18/Next18S')], null=True), - ), - ] diff --git a/dcc/metadata/models.py b/dcc/metadata/models.py index ca02885..5243bf4 100644 --- a/dcc/metadata/models.py +++ b/dcc/metadata/models.py @@ -1,7 +1,9 @@ from django.db import models +from django.conf import settings +from django.dispatch.dispatcher import receiver from django_countries.fields import CountryField -from dcc.utils import get_image_preview +from dcc.utils import get_image_preview, slugify class Manufacturer(models.Model): @@ -67,3 +69,28 @@ class Decoder(models.Model): def image_thumbnail(self): return get_image_preview(self.image.url) image_thumbnail.short_description = "Preview" + + +class Tag(models.Model): + name = models.CharField(max_length=128, unique=True) + slug = models.CharField(max_length=128, unique=True) + + def __str__(self): + return self.name + + +@receiver(models.signals.pre_save, sender=Tag) +def tag_pre_save(sender, instance, **kwargs): + instance.slug = slugify(instance.name) + + +class RollingStockType(models.Model): + type = models.CharField(max_length=64) + category = models.CharField( + max_length=64, choices=settings.ROLLING_STOCK_TYPES) + + class Meta(object): + unique_together = ('category', 'type') + + def __str__(self): + return "{0}".format(self.type) diff --git a/dcc/roster/admin.py b/dcc/roster/admin.py index 5889b18..40766c4 100644 --- a/dcc/roster/admin.py +++ b/dcc/roster/admin.py @@ -1,26 +1,42 @@ from django.contrib import admin -from roster.models import Cab +from roster.models import ( + RollingStock, RollingStockImage, RollingStockDocument, Engine, Car, + Equipment, Other) -@admin.register(Cab) -class CabAdmin(admin.ModelAdmin): - readonly_fields = ('image_thumbnail', 'creation_time', 'updated_time',) - list_display = ('identifier', 'address', 'manufacturer', 'company') +class RollingStockDocInline(admin.TabularInline): + model = RollingStockDocument + min_num = 0 + extra = 0 + + +class RollingStockImageInline(admin.TabularInline): + model = RollingStockImage + min_num = 0 + extra = 0 + readonly_fields = ('image_thumbnail',) + + +class RollingStockAdmin(admin.ModelAdmin): + inlines = (RollingStockImageInline, RollingStockDocInline) + readonly_fields = ('creation_time', 'updated_time',) + list_display = ('identifier', 'manufacturer', 'sku', 'company') list_filter = list_display search_fields = list_display fieldsets = ( (None, { 'fields': ('identifier', - 'address', + 'type', + 'tags', 'manufacturer', + 'sku', 'decoder', + 'address', 'company', 'epoch', 'production_year', 'purchase_date', - 'image', - 'image_thumbnail', 'notes') }), ('Audit', { @@ -28,3 +44,23 @@ class CabAdmin(admin.ModelAdmin): 'fields': ('creation_time', 'updated_time',) }), ) + + +@admin.register(Engine) +class Engine(RollingStockAdmin): + list_display = ('identifier', 'address', 'manufacturer', 'sku', 'company') + + +@admin.register(Car) +class Car(RollingStockAdmin): + pass + + +@admin.register(Equipment) +class Equipment(RollingStockAdmin): + pass + + +@admin.register(Other) +class Other(RollingStockAdmin): + pass diff --git a/dcc/roster/migrations/0001_initial.py b/dcc/roster/migrations/0001_initial.py index fba407c..2152455 100644 --- a/dcc/roster/migrations/0001_initial.py +++ b/dcc/roster/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 4.0 on 2021-12-15 22:16 +# Generated by Django 4.0.2 on 2022-04-01 20:25 from django.db import migrations, models import django.db.models.deletion @@ -10,28 +10,86 @@ class Migration(migrations.Migration): initial = True dependencies = [ + ('metadata', '0001_initial'), ] operations = [ migrations.CreateModel( - name='Manufacturer', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('name', models.CharField(max_length=128, unique=True)), - ], - ), - migrations.CreateModel( - name='Cab', + name='RollingStock', fields=[ ('uuid', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)), ('identifier', models.CharField(max_length=128)), - ('address', models.SmallIntegerField(default=3)), + ('address', models.SmallIntegerField(blank=True, default=3, null=True)), + ('sku', models.CharField(blank=True, max_length=32)), + ('epoch', models.CharField(blank=True, max_length=32)), + ('production_year', models.SmallIntegerField(blank=True, null=True)), + ('purchase_date', models.DateField(blank=True, null=True)), + ('notes', models.TextField(blank=True)), ('creation_time', models.DateTimeField(auto_now_add=True)), ('updated_time', models.DateTimeField(auto_now=True)), - ('manufacturer', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='roster.manufacturer')), + ('company', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='metadata.company')), + ('decoder', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='metadata.decoder')), + ('manufacturer', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='metadata.manufacturer')), + ('tags', models.ManyToManyField(blank=True, related_name='rolling_stock', to='metadata.Tag')), ], options={ + 'verbose_name_plural': 'Rolling stock', 'ordering': ['address', 'identifier'], }, ), + migrations.CreateModel( + name='RollingStockImage', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('image', models.ImageField(blank=True, null=True, upload_to='images/')), + ('rolling_stock', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='roster.rollingstock')), + ], + options={ + 'unique_together': {('rolling_stock', 'image')}, + }, + ), + migrations.CreateModel( + name='RollingStockDocument', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('description', models.CharField(blank=True, max_length=128)), + ('file', models.FileField(blank=True, null=True, upload_to='files/')), + ('rolling_stock', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='roster.rollingstock')), + ], + options={ + 'unique_together': {('rolling_stock', 'file')}, + }, + ), + migrations.CreateModel( + name='Other', + fields=[ + ('rollingstock_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='roster.rollingstock')), + ('type', models.ForeignKey(blank=True, limit_choices_to={'category': 'other'}, null=True, on_delete=django.db.models.deletion.CASCADE, to='metadata.rollingstocktype')), + ], + bases=('roster.rollingstock',), + ), + migrations.CreateModel( + name='Equipment', + fields=[ + ('rollingstock_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='roster.rollingstock')), + ('type', models.ForeignKey(blank=True, limit_choices_to={'category': 'equipment'}, null=True, on_delete=django.db.models.deletion.CASCADE, to='metadata.rollingstocktype')), + ], + bases=('roster.rollingstock',), + ), + migrations.CreateModel( + name='Engine', + fields=[ + ('rollingstock_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='roster.rollingstock')), + ('type', models.ForeignKey(blank=True, limit_choices_to={'category': 'engine'}, null=True, on_delete=django.db.models.deletion.CASCADE, to='metadata.rollingstocktype')), + ], + bases=('roster.rollingstock',), + ), + migrations.CreateModel( + name='Car', + fields=[ + ('rollingstock_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='roster.rollingstock')), + ('type', models.ForeignKey(blank=True, limit_choices_to={'category': 'car'}, null=True, on_delete=django.db.models.deletion.CASCADE, to='metadata.rollingstocktype')), + ], + bases=('roster.rollingstock',), + ), ] diff --git a/dcc/roster/migrations/0002_cab_notes_cab_production_date_cab_production_year.py b/dcc/roster/migrations/0002_cab_notes_cab_production_date_cab_production_year.py deleted file mode 100644 index 35aa44b..0000000 --- a/dcc/roster/migrations/0002_cab_notes_cab_production_date_cab_production_year.py +++ /dev/null @@ -1,28 +0,0 @@ -# Generated by Django 4.0 on 2021-12-15 22:24 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('roster', '0001_initial'), - ] - - operations = [ - migrations.AddField( - model_name='cab', - name='notes', - field=models.TextField(blank=True), - ), - migrations.AddField( - model_name='cab', - name='production_date', - field=models.SmallIntegerField(null=True), - ), - migrations.AddField( - model_name='cab', - name='production_year', - field=models.SmallIntegerField(null=True), - ), - ] diff --git a/dcc/roster/migrations/0003_remove_cab_production_date_cab_purchase_date.py b/dcc/roster/migrations/0003_remove_cab_production_date_cab_purchase_date.py deleted file mode 100644 index 95b2471..0000000 --- a/dcc/roster/migrations/0003_remove_cab_production_date_cab_purchase_date.py +++ /dev/null @@ -1,22 +0,0 @@ -# Generated by Django 4.0 on 2021-12-15 22:27 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('roster', '0002_cab_notes_cab_production_date_cab_production_year'), - ] - - operations = [ - migrations.RemoveField( - model_name='cab', - name='production_date', - ), - migrations.AddField( - model_name='cab', - name='purchase_date', - field=models.DateField(null=True), - ), - ] diff --git a/dcc/roster/migrations/0004_alter_cab_manufacturer_alter_cab_production_year_and_more.py b/dcc/roster/migrations/0004_alter_cab_manufacturer_alter_cab_production_year_and_more.py deleted file mode 100644 index 100e04c..0000000 --- a/dcc/roster/migrations/0004_alter_cab_manufacturer_alter_cab_production_year_and_more.py +++ /dev/null @@ -1,29 +0,0 @@ -# Generated by Django 4.0 on 2021-12-15 22:28 - -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - dependencies = [ - ('roster', '0003_remove_cab_production_date_cab_purchase_date'), - ] - - operations = [ - migrations.AlterField( - model_name='cab', - name='manufacturer', - field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='roster.manufacturer'), - ), - migrations.AlterField( - model_name='cab', - name='production_year', - field=models.SmallIntegerField(blank=True, null=True), - ), - migrations.AlterField( - model_name='cab', - name='purchase_date', - field=models.DateField(blank=True, null=True), - ), - ] diff --git a/dcc/roster/migrations/0005_alter_cab_manufacturer.py b/dcc/roster/migrations/0005_alter_cab_manufacturer.py deleted file mode 100644 index f347d2a..0000000 --- a/dcc/roster/migrations/0005_alter_cab_manufacturer.py +++ /dev/null @@ -1,19 +0,0 @@ -# Generated by Django 4.0 on 2021-12-15 22:29 - -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - dependencies = [ - ('roster', '0004_alter_cab_manufacturer_alter_cab_production_year_and_more'), - ] - - operations = [ - migrations.AlterField( - model_name='cab', - name='manufacturer', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='roster.manufacturer'), - ), - ] diff --git a/dcc/roster/migrations/0006_cab_image.py b/dcc/roster/migrations/0006_cab_image.py deleted file mode 100644 index a8f744e..0000000 --- a/dcc/roster/migrations/0006_cab_image.py +++ /dev/null @@ -1,18 +0,0 @@ -# Generated by Django 4.0 on 2021-12-15 22:32 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('roster', '0005_alter_cab_manufacturer'), - ] - - operations = [ - migrations.AddField( - model_name='cab', - name='image', - field=models.ImageField(blank=True, upload_to=''), - ), - ] diff --git a/dcc/roster/migrations/0007_alter_cab_image.py b/dcc/roster/migrations/0007_alter_cab_image.py deleted file mode 100644 index dde5ee7..0000000 --- a/dcc/roster/migrations/0007_alter_cab_image.py +++ /dev/null @@ -1,18 +0,0 @@ -# Generated by Django 4.0 on 2021-12-15 22:43 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('roster', '0006_cab_image'), - ] - - operations = [ - migrations.AlterField( - model_name='cab', - name='image', - field=models.ImageField(blank=True, null=True, upload_to='images/'), - ), - ] diff --git a/dcc/roster/migrations/0008_cab_epoch.py b/dcc/roster/migrations/0008_cab_epoch.py deleted file mode 100644 index d9a05d7..0000000 --- a/dcc/roster/migrations/0008_cab_epoch.py +++ /dev/null @@ -1,18 +0,0 @@ -# Generated by Django 4.0 on 2021-12-15 23:05 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('roster', '0007_alter_cab_image'), - ] - - operations = [ - migrations.AddField( - model_name='cab', - name='epoch', - field=models.CharField(blank=True, max_length=32), - ), - ] diff --git a/dcc/roster/migrations/0009_cab_decoder_manufacturer_cab_decoder_model_and_more.py b/dcc/roster/migrations/0009_cab_decoder_manufacturer_cab_decoder_model_and_more.py deleted file mode 100644 index a9ee418..0000000 --- a/dcc/roster/migrations/0009_cab_decoder_manufacturer_cab_decoder_model_and_more.py +++ /dev/null @@ -1,29 +0,0 @@ -# Generated by Django 4.0 on 2021-12-16 09:11 - -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - dependencies = [ - ('roster', '0008_cab_epoch'), - ] - - operations = [ - migrations.AddField( - model_name='cab', - name='decoder_manufacturer', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(class)s_decoder', to='roster.manufacturer'), - ), - migrations.AddField( - model_name='cab', - name='decoder_model', - field=models.CharField(blank=True, max_length=128), - ), - migrations.AlterField( - model_name='cab', - name='manufacturer', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(class)s_manufacturer', to='roster.manufacturer'), - ), - ] diff --git a/dcc/roster/migrations/0010_remove_cab_decoder_manufacturer_and_more.py b/dcc/roster/migrations/0010_remove_cab_decoder_manufacturer_and_more.py deleted file mode 100644 index 3dab61a..0000000 --- a/dcc/roster/migrations/0010_remove_cab_decoder_manufacturer_and_more.py +++ /dev/null @@ -1,31 +0,0 @@ -# Generated by Django 4.0 on 2021-12-16 09:15 - -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - dependencies = [ - ('roster', '0009_cab_decoder_manufacturer_cab_decoder_model_and_more'), - ] - - operations = [ - migrations.RemoveField( - model_name='cab', - name='decoder_manufacturer', - ), - migrations.AlterField( - model_name='cab', - name='manufacturer', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='roster.manufacturer'), - ), - migrations.CreateModel( - name='Decoder', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('name', models.CharField(max_length=128, unique=True)), - ('manufacturer', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='roster.manufacturer')), - ], - ), - ] diff --git a/dcc/roster/migrations/0011_remove_cab_decoder_model_cab_decoder.py b/dcc/roster/migrations/0011_remove_cab_decoder_model_cab_decoder.py deleted file mode 100644 index 44d0fa5..0000000 --- a/dcc/roster/migrations/0011_remove_cab_decoder_model_cab_decoder.py +++ /dev/null @@ -1,23 +0,0 @@ -# Generated by Django 4.0 on 2021-12-16 09:18 - -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - dependencies = [ - ('roster', '0010_remove_cab_decoder_manufacturer_and_more'), - ] - - operations = [ - migrations.RemoveField( - model_name='cab', - name='decoder_model', - ), - migrations.AddField( - model_name='cab', - name='decoder', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='roster.decoder'), - ), - ] diff --git a/dcc/roster/migrations/0012_company.py b/dcc/roster/migrations/0012_company.py deleted file mode 100644 index aeb4fd5..0000000 --- a/dcc/roster/migrations/0012_company.py +++ /dev/null @@ -1,22 +0,0 @@ -# Generated by Django 4.0 on 2021-12-16 21:26 - -from django.db import migrations, models -import django_countries.fields - - -class Migration(migrations.Migration): - - dependencies = [ - ('roster', '0011_remove_cab_decoder_model_cab_decoder'), - ] - - operations = [ - migrations.CreateModel( - name='Company', - 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(max_length=2)), - ], - ), - ] diff --git a/dcc/roster/migrations/0013_cab_company.py b/dcc/roster/migrations/0013_cab_company.py deleted file mode 100644 index 1b9a7ee..0000000 --- a/dcc/roster/migrations/0013_cab_company.py +++ /dev/null @@ -1,19 +0,0 @@ -# Generated by Django 4.0 on 2021-12-16 21:27 - -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - dependencies = [ - ('roster', '0012_company'), - ] - - operations = [ - migrations.AddField( - model_name='cab', - name='company', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='roster.company'), - ), - ] diff --git a/dcc/roster/migrations/0014_alter_company_options_alter_cab_image.py b/dcc/roster/migrations/0014_alter_company_options_alter_cab_image.py deleted file mode 100644 index 9a35e0b..0000000 --- a/dcc/roster/migrations/0014_alter_company_options_alter_cab_image.py +++ /dev/null @@ -1,22 +0,0 @@ -# Generated by Django 4.0 on 2021-12-17 23:21 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('roster', '0013_cab_company'), - ] - - operations = [ - migrations.AlterModelOptions( - name='company', - options={'verbose_name_plural': 'Companies'}, - ), - migrations.AlterField( - model_name='cab', - name='image', - field=models.ImageField(blank=True, null=True, upload_to='media/images/'), - ), - ] diff --git a/dcc/roster/migrations/0015_remove_decoder_manufacturer_alter_cab_company_and_more.py b/dcc/roster/migrations/0015_remove_decoder_manufacturer_alter_cab_company_and_more.py deleted file mode 100644 index a5cae8e..0000000 --- a/dcc/roster/migrations/0015_remove_decoder_manufacturer_alter_cab_company_and_more.py +++ /dev/null @@ -1,43 +0,0 @@ -# Generated by Django 4.0 on 2021-12-20 21:37 - -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - dependencies = [ - ('metadata', '0001_initial'), - ('roster', '0014_alter_company_options_alter_cab_image'), - ] - - operations = [ - migrations.RemoveField( - model_name='decoder', - name='manufacturer', - ), - migrations.AlterField( - model_name='cab', - name='company', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='metadata.company'), - ), - migrations.AlterField( - model_name='cab', - name='decoder', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='metadata.decoder'), - ), - migrations.AlterField( - model_name='cab', - name='manufacturer', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='metadata.manufacturer'), - ), - migrations.DeleteModel( - name='Company', - ), - migrations.DeleteModel( - name='Decoder', - ), - migrations.DeleteModel( - name='Manufacturer', - ), - ] diff --git a/dcc/roster/migrations/0016_alter_cab_image.py b/dcc/roster/migrations/0016_alter_cab_image.py deleted file mode 100644 index e93689d..0000000 --- a/dcc/roster/migrations/0016_alter_cab_image.py +++ /dev/null @@ -1,18 +0,0 @@ -# Generated by Django 4.0.1 on 2022-01-29 18:05 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('roster', '0015_remove_decoder_manufacturer_alter_cab_company_and_more'), - ] - - operations = [ - migrations.AlterField( - model_name='cab', - name='image', - field=models.ImageField(blank=True, null=True, upload_to='images/'), - ), - ] diff --git a/dcc/roster/models.py b/dcc/roster/models.py index ca82fc2..e641df8 100644 --- a/dcc/roster/models.py +++ b/dcc/roster/models.py @@ -1,10 +1,12 @@ +import os from uuid import uuid4 from django.db import models # from django.core.files.storage import FileSystemStorage # from django.dispatch import receiver from dcc.utils import get_image_preview -from metadata.models import Manufacturer, Decoder, Company +from metadata.models import ( + Manufacturer, Decoder, Company, Tag, RollingStockType) # class OverwriteMixin(FileSystemStorage): # def get_available_name(self, name, max_length): @@ -12,15 +14,20 @@ from metadata.models import Manufacturer, Decoder, Company # return name -class Cab(models.Model): +class RollingStock(models.Model): uuid = models.UUIDField( primary_key=True, default=uuid4, editable=False) identifier = models.CharField(max_length=128, unique=False) - address = models.SmallIntegerField(default=3) + tags = models.ManyToManyField( + Tag, + related_name='rolling_stock', + blank=True) + address = models.SmallIntegerField(default=3, null=True, blank=True) manufacturer = models.ForeignKey( Manufacturer, on_delete=models.CASCADE, null=True, blank=True) + sku = models.CharField(max_length=32, blank=True) decoder = models.ForeignKey( Decoder, on_delete=models.CASCADE, null=True, blank=True) @@ -31,10 +38,6 @@ class Cab(models.Model): production_year = models.SmallIntegerField(null=True, blank=True) purchase_date = models.DateField(null=True, blank=True) - image = models.ImageField( - upload_to='images/', - null=True, - blank=True) notes = models.TextField(blank=True) creation_time = models.DateTimeField(auto_now_add=True) @@ -42,14 +45,74 @@ class Cab(models.Model): class Meta: ordering = ['address', 'identifier'] + verbose_name_plural = "Rolling stock" def __str__(self): return "{0} {1}".format(self.manufacturer, self.identifier) + +class Engine(RollingStock): + type = models.ForeignKey( + RollingStockType, on_delete=models.CASCADE, + limit_choices_to={'category': 'engine'}, + null=True, blank=True) + + +class Car(RollingStock): + type = models.ForeignKey( + RollingStockType, on_delete=models.CASCADE, + limit_choices_to={'category': 'car'}, + null=True, blank=True) + + +class Equipment(RollingStock): + type = models.ForeignKey( + RollingStockType, on_delete=models.CASCADE, + limit_choices_to={'category': 'equipment'}, + null=True, blank=True) + + +class Other(RollingStock): + type = models.ForeignKey( + RollingStockType, on_delete=models.CASCADE, + limit_choices_to={'category': 'other'}, + null=True, blank=True) + + +class RollingStockDocument(models.Model): + rolling_stock = models.ForeignKey( + RollingStock, on_delete=models.CASCADE) + description = models.CharField(max_length=128, blank=True) + file = models.FileField( + upload_to='files/', + null=True, + blank=True) + + class Meta(object): + unique_together = ('rolling_stock', 'file') + + def __str__(self): + return "{0}".format(os.path.basename(self.file.name)) + # return "{0}".format(self.description) + + +class RollingStockImage(models.Model): + rolling_stock = models.ForeignKey( + RollingStock, on_delete=models.CASCADE) + image = models.ImageField( + upload_to='images/', + null=True, + blank=True) + def image_thumbnail(self): return get_image_preview(self.image.url) image_thumbnail.short_description = "Preview" + class Meta(object): + unique_together = ('rolling_stock', 'image') + + def __str__(self): + return "{0}".format(os.path.basename(self.image.name)) # @receiver(models.signals.post_delete, sender=Cab) # def post_save_image(sender, instance, *args, **kwargs): diff --git a/dcc/roster/serializers.py b/dcc/roster/serializers.py index 628972b..1d345ee 100644 --- a/dcc/roster/serializers.py +++ b/dcc/roster/serializers.py @@ -1,15 +1,15 @@ from rest_framework import serializers -from roster.models import Cab +from roster.models import RollingStock from metadata.serializers import ( ManufacturerSerializer, CompanySerializer, DecoderSerializer) -class CabSerializer(serializers.ModelSerializer): +class RollingStockSerializer(serializers.ModelSerializer): manufacturer = ManufacturerSerializer() decoder = DecoderSerializer() company = CompanySerializer() class Meta: - model = Cab + model = RollingStock fields = "__all__" read_only_fields = ("creation_time", "updated_time") diff --git a/dcc/roster/views.py b/dcc/roster/views.py index 4d9286e..6a29409 100644 --- a/dcc/roster/views.py +++ b/dcc/roster/views.py @@ -1,27 +1,27 @@ from rest_framework.generics import ListAPIView, RetrieveAPIView -from roster.models import Cab -from roster.serializers import CabSerializer +from roster.models import RollingStock +from roster.serializers import RollingStockSerializer class RosterList(ListAPIView): - queryset = Cab.objects.all() - serializer_class = CabSerializer + queryset = RollingStock.objects.all() + serializer_class = RollingStockSerializer class RosterGet(RetrieveAPIView): - queryset = Cab.objects.all() - serializer_class = CabSerializer + queryset = RollingStock.objects.all() + serializer_class = RollingStockSerializer lookup_field = 'uuid' -class RosterAddress(RetrieveAPIView): - queryset = Cab.objects.all() - serializer_class = CabSerializer +class RosterAddress(ListAPIView): + queryset = RollingStock.objects.all() + serializer_class = RollingStockSerializer lookup_field = 'address' class RosterIdentifier(RetrieveAPIView): - queryset = Cab.objects.all() - serializer_class = CabSerializer + queryset = RollingStock.objects.all() + serializer_class = RollingStockSerializer lookup_field = 'identifier'