Refactor rolling stock

This commit is contained in:
2022-03-30 23:15:24 +02:00
parent 91e6dd0cac
commit fd76b2df28
25 changed files with 600 additions and 17 deletions

View File

@@ -134,3 +134,8 @@ DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
MEDIA_URL = 'media/' MEDIA_URL = 'media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media') MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
ROLLING_STOCK_TYPES = [
("engine", "Engine"), ("car", "Car"),
("equipment", "Equipment"), ("other", "Other")
]

View File

@@ -16,9 +16,7 @@ def addresschecker(f):
Check if DCC address does exist in the database Check if DCC address does exist in the database
""" """
def addresslookup(request, address, *args): def addresslookup(request, address, *args):
try: if not RollingStock.objects.filter(address=address):
RollingStock.objects.get(address=address)
except RollingStock.DoesNotExist:
raise Http404 raise Http404
return f(request, address, *args) return f(request, address, *args)
return addresslookup return addresslookup

View File

@@ -1,5 +1,6 @@
from django.contrib import admin from django.contrib import admin
from metadata.models import Decoder, Manufacturer, Company, Tag from metadata.models import (
Decoder, Manufacturer, Company, Tag, RollingStockType)
@admin.register(Decoder) @admin.register(Decoder)
@@ -20,3 +21,9 @@ class ManufacturerAdmin(admin.ModelAdmin):
@admin.register(Tag) @admin.register(Tag)
class TagAdmin(admin.ModelAdmin): class TagAdmin(admin.ModelAdmin):
readonly_fields = ('slug',) readonly_fields = ('slug',)
@admin.register(RollingStockType)
class RollingStockTypeAdmin(admin.ModelAdmin):
list_display = ('type', 'category')
list_filter = list_display

View File

@@ -0,0 +1,20 @@
# Generated by Django 4.0.2 on 2022-03-30 19:44
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('metadata', '0006_alter_tag_options'),
]
operations = [
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, unique=True)),
],
),
]

View File

@@ -0,0 +1,44 @@
# Generated by Django 4.0.2 on 2022-03-30 19:55
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('metadata', '0007_rollingstocktype'),
]
operations = [
migrations.CreateModel(
name='EngineType',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('type', models.CharField(max_length=64, unique=True)),
],
),
migrations.RemoveField(
model_name='rollingstocktype',
name='type',
),
migrations.CreateModel(
name='CarType',
fields=[
('enginetype_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='metadata.enginetype')),
],
bases=('metadata.enginetype',),
),
migrations.AddField(
model_name='rollingstocktype',
name='engine_type',
field=models.ForeignKey(default='0', on_delete=django.db.models.deletion.CASCADE, related_name='engine_type', to='metadata.enginetype'),
preserve_default=False,
),
migrations.AddField(
model_name='rollingstocktype',
name='car_type',
field=models.ForeignKey(default=None, on_delete=django.db.models.deletion.CASCADE, related_name='car_type', to='metadata.cartype'),
preserve_default=False,
),
]

View File

@@ -0,0 +1,51 @@
# Generated by Django 4.0.2 on 2022-03-30 20:01
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('metadata', '0008_enginetype_remove_rollingstocktype_type_cartype_and_more'),
]
operations = [
migrations.CreateModel(
name='TypeCategory',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('category', models.CharField(max_length=64, unique=True)),
],
),
migrations.AddField(
model_name='rollingstocktype',
name='type',
field=models.CharField(default='0', max_length=64),
preserve_default=False,
),
migrations.AddField(
model_name='rollingstocktype',
name='category',
field=models.ForeignKey(default=0, on_delete=django.db.models.deletion.CASCADE, to='metadata.typecategory'),
preserve_default=False,
),
migrations.AlterUniqueTogether(
name='rollingstocktype',
unique_together={('category', 'type')},
),
migrations.RemoveField(
model_name='rollingstocktype',
name='car_type',
),
migrations.RemoveField(
model_name='rollingstocktype',
name='engine_type',
),
migrations.DeleteModel(
name='CarType',
),
migrations.DeleteModel(
name='EngineType',
),
]

View File

@@ -0,0 +1,18 @@
# Generated by Django 4.0.2 on 2022-03-30 20:04
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('metadata', '0009_typecategory_rollingstocktype_type_and_more'),
]
operations = [
migrations.AlterField(
model_name='typecategory',
name='category',
field=models.CharField(choices=[('engine', 'Engine'), ('car', 'Car')], max_length=64, unique=True),
),
]

View File

@@ -0,0 +1,21 @@
# Generated by Django 4.0.2 on 2022-03-30 20:04
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('metadata', '0010_alter_typecategory_category'),
]
operations = [
migrations.AlterField(
model_name='rollingstocktype',
name='category',
field=models.CharField(choices=[('engine', 'Engine'), ('car', 'Car')], max_length=64, unique=True),
),
migrations.DeleteModel(
name='TypeCategory',
),
]

View File

@@ -0,0 +1,18 @@
# Generated by Django 4.0.2 on 2022-03-30 20:22
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('metadata', '0011_alter_rollingstocktype_category_delete_typecategory'),
]
operations = [
migrations.AlterField(
model_name='rollingstocktype',
name='category',
field=models.CharField(choices=[('engine', 'Engine'), ('car', 'Car'), ('equipment', 'Equipment'), ('other', 'Other')], max_length=64),
),
]

View File

@@ -1,4 +1,5 @@
from django.db import models from django.db import models
from django.conf import settings
from django.dispatch.dispatcher import receiver from django.dispatch.dispatcher import receiver
from django_countries.fields import CountryField from django_countries.fields import CountryField
@@ -81,3 +82,15 @@ class Tag(models.Model):
@receiver(models.signals.pre_save, sender=Tag) @receiver(models.signals.pre_save, sender=Tag)
def tag_pre_save(sender, instance, **kwargs): def tag_pre_save(sender, instance, **kwargs):
instance.slug = slugify(instance.name) 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)

View File

@@ -1,27 +1,42 @@
from django.contrib import admin from django.contrib import admin
from roster.models import RollingStock from roster.models import (
RollingStock, RollingStockImage, RollingStockDocument, Engine, Car,
Equipment, Other)
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',)
@admin.register(RollingStock)
class RollingStockAdmin(admin.ModelAdmin): class RollingStockAdmin(admin.ModelAdmin):
readonly_fields = ('image_thumbnail', 'creation_time', 'updated_time',) inlines = (RollingStockImageInline, RollingStockDocInline)
list_display = ('identifier', 'address', 'manufacturer', 'company') readonly_fields = ('creation_time', 'updated_time',)
list_display = ('identifier', 'manufacturer', 'sku', 'company')
list_filter = list_display list_filter = list_display
search_fields = list_display search_fields = list_display
fieldsets = ( fieldsets = (
(None, { (None, {
'fields': ('identifier', 'fields': ('identifier',
'type',
'tags', 'tags',
'address',
'manufacturer', 'manufacturer',
'sku',
'decoder', 'decoder',
'address',
'company', 'company',
'epoch', 'epoch',
'production_year', 'production_year',
'purchase_date', 'purchase_date',
'image',
'image_thumbnail',
'notes') 'notes')
}), }),
('Audit', { ('Audit', {
@@ -29,3 +44,23 @@ class RollingStockAdmin(admin.ModelAdmin):
'fields': ('creation_time', 'updated_time',) '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

View File

@@ -0,0 +1,38 @@
# Generated by Django 4.0.2 on 2022-03-29 19:38
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('roster', '0022_alter_rollingstock_address'),
]
operations = [
migrations.CreateModel(
name='Image',
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/')),
],
),
migrations.RemoveField(
model_name='rollingstock',
name='image',
),
migrations.CreateModel(
name='RollingStockImage',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('order', models.PositiveIntegerField()),
('image', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='roster.image')),
('rolling_stock', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='roster.rollingstock')),
],
options={
'ordering': ['order'],
'unique_together': {('rolling_stock', 'image')},
},
),
]

View File

@@ -0,0 +1,18 @@
# Generated by Django 4.0.2 on 2022-03-29 20:00
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('roster', '0023_image_remove_rollingstock_image_rollingstockimage'),
]
operations = [
migrations.AlterField(
model_name='rollingstockimage',
name='image',
field=models.ImageField(blank=True, null=True, upload_to='images/'),
),
]

View File

@@ -0,0 +1,21 @@
# Generated by Django 4.0.2 on 2022-03-29 20:02
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('roster', '0024_alter_rollingstockimage_image'),
]
operations = [
migrations.AlterModelOptions(
name='rollingstockimage',
options={},
),
migrations.RemoveField(
model_name='rollingstockimage',
name='order',
),
]

View File

@@ -0,0 +1,28 @@
# Generated by Django 4.0.2 on 2022-03-29 20:21
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('roster', '0025_alter_rollingstockimage_options_and_more'),
]
operations = [
migrations.CreateModel(
name='RollingStockDocument',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('file', models.ImageField(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.DeleteModel(
name='Image',
),
]

View File

@@ -0,0 +1,18 @@
# Generated by Django 4.0.2 on 2022-03-29 20:23
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('roster', '0026_rollingstockdocument_delete_image'),
]
operations = [
migrations.AlterField(
model_name='rollingstockdocument',
name='file',
field=models.FileField(blank=True, null=True, upload_to='files/'),
),
]

View File

@@ -0,0 +1,18 @@
# Generated by Django 4.0.2 on 2022-03-29 20:24
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('roster', '0027_alter_rollingstockdocument_file'),
]
operations = [
migrations.AddField(
model_name='rollingstockdocument',
name='description',
field=models.CharField(blank=True, max_length=128),
),
]

View File

@@ -0,0 +1,18 @@
# Generated by Django 4.0.2 on 2022-03-30 19:37
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('roster', '0028_rollingstockdocument_description'),
]
operations = [
migrations.AddField(
model_name='rollingstock',
name='sku',
field=models.CharField(blank=True, max_length=32),
),
]

View File

@@ -0,0 +1,25 @@
# Generated by Django 4.0.2 on 2022-03-30 19:40
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('roster', '0029_rollingstock_sku'),
]
operations = [
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')),
],
options={
'verbose_name_plural': 'Engines',
'ordering': ['address', 'identifier'],
},
bases=('roster.rollingstock',),
),
]

View File

@@ -0,0 +1,20 @@
# Generated by Django 4.0.2 on 2022-03-30 20:26
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('metadata', '0012_alter_rollingstocktype_category'),
('roster', '0030_engine'),
]
operations = [
migrations.AddField(
model_name='rollingstock',
name='type',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='metadata.rollingstocktype'),
),
]

View File

@@ -0,0 +1,17 @@
# Generated by Django 4.0.2 on 2022-03-30 20:49
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('roster', '0031_rollingstock_type'),
]
operations = [
migrations.AlterModelOptions(
name='engine',
options={},
),
]

View File

@@ -0,0 +1,35 @@
# Generated by Django 4.0.2 on 2022-03-30 20:57
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('roster', '0032_alter_engine_options'),
]
operations = [
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')),
],
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')),
],
bases=('roster.rollingstock',),
),
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')),
],
bases=('roster.rollingstock',),
),
]

View File

@@ -0,0 +1,39 @@
# Generated by Django 4.0.2 on 2022-03-30 20:59
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('metadata', '0012_alter_rollingstocktype_category'),
('roster', '0033_car_equipment_other'),
]
operations = [
migrations.RemoveField(
model_name='rollingstock',
name='type',
),
migrations.AddField(
model_name='car',
name='type',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='metadata.rollingstocktype'),
),
migrations.AddField(
model_name='engine',
name='type',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='metadata.rollingstocktype'),
),
migrations.AddField(
model_name='equipment',
name='type',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='metadata.rollingstocktype'),
),
migrations.AddField(
model_name='other',
name='type',
field=models.ForeignKey(blank=True, limit_choices_to={'category': 'roster.models'}, null=True, on_delete=django.db.models.deletion.CASCADE, to='metadata.rollingstocktype'),
),
]

View File

@@ -1,10 +1,12 @@
import os
from uuid import uuid4 from uuid import uuid4
from django.db import models from django.db import models
# from django.core.files.storage import FileSystemStorage # from django.core.files.storage import FileSystemStorage
# from django.dispatch import receiver # from django.dispatch import receiver
from dcc.utils import get_image_preview from dcc.utils import get_image_preview
from metadata.models import Manufacturer, Decoder, Company, Tag from metadata.models import (
Manufacturer, Decoder, Company, Tag, RollingStockType)
# class OverwriteMixin(FileSystemStorage): # class OverwriteMixin(FileSystemStorage):
# def get_available_name(self, name, max_length): # def get_available_name(self, name, max_length):
@@ -25,6 +27,7 @@ class RollingStock(models.Model):
manufacturer = models.ForeignKey( manufacturer = models.ForeignKey(
Manufacturer, on_delete=models.CASCADE, Manufacturer, on_delete=models.CASCADE,
null=True, blank=True) null=True, blank=True)
sku = models.CharField(max_length=32, blank=True)
decoder = models.ForeignKey( decoder = models.ForeignKey(
Decoder, on_delete=models.CASCADE, Decoder, on_delete=models.CASCADE,
null=True, blank=True) null=True, blank=True)
@@ -35,10 +38,6 @@ class RollingStock(models.Model):
production_year = models.SmallIntegerField(null=True, blank=True) production_year = models.SmallIntegerField(null=True, blank=True)
purchase_date = models.DateField(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) notes = models.TextField(blank=True)
creation_time = models.DateTimeField(auto_now_add=True) creation_time = models.DateTimeField(auto_now_add=True)
@@ -51,10 +50,69 @@ class RollingStock(models.Model):
def __str__(self): def __str__(self):
return "{0} {1}".format(self.manufacturer, self.identifier) 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): def image_thumbnail(self):
return get_image_preview(self.image.url) return get_image_preview(self.image.url)
image_thumbnail.short_description = "Preview" 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) # @receiver(models.signals.post_delete, sender=Cab)
# def post_save_image(sender, instance, *args, **kwargs): # def post_save_image(sender, instance, *args, **kwargs):

View File

@@ -15,7 +15,7 @@ class RosterGet(RetrieveAPIView):
lookup_field = 'uuid' lookup_field = 'uuid'
class RosterAddress(RetrieveAPIView): class RosterAddress(ListAPIView):
queryset = RollingStock.objects.all() queryset = RollingStock.objects.all()
serializer_class = RollingStockSerializer serializer_class = RollingStockSerializer
lookup_field = 'address' lookup_field = 'address'