12 Commits

25 changed files with 348 additions and 109 deletions

View File

@@ -0,0 +1,20 @@
# Generated by Django 4.0.6 on 2022-07-15 16:08
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('metadata', '0004_alter_rollingstocktype_options_and_more'),
('consist', '0003_consist_image'),
]
operations = [
migrations.AlterField(
model_name='consist',
name='company',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='metadata.company'),
),
]

View File

@@ -13,9 +13,7 @@ class Consist(models.Model):
consist_address = models.SmallIntegerField( consist_address = models.SmallIntegerField(
default=None, null=True, blank=True default=None, null=True, blank=True
) )
company = models.ForeignKey( company = models.ForeignKey(Company, on_delete=models.CASCADE)
Company, on_delete=models.CASCADE, null=True, blank=True
)
era = models.CharField(max_length=32, blank=True) era = models.CharField(max_length=32, blank=True)
image = models.ImageField(upload_to="images/", null=True, blank=True) image = models.ImageField(upload_to="images/", null=True, blank=True)
notes = models.TextField(blank=True) notes = models.TextField(blank=True)
@@ -23,7 +21,7 @@ class Consist(models.Model):
updated_time = models.DateTimeField(auto_now=True) updated_time = models.DateTimeField(auto_now=True)
def __str__(self): def __str__(self):
return "{0}".format(self.identifier) return "{0} {1}".format(self.company, self.identifier)
def get_absolute_url(self): def get_absolute_url(self):
return reverse("consist", kwargs={"uuid": self.uuid}) return reverse("consist", kwargs={"uuid": self.uuid})

View File

@@ -9,11 +9,7 @@ class DriverConfigurationAdmin(SingletonModelAdmin):
fieldsets = ( fieldsets = (
( (
"General configuration", "General configuration",
{ {"fields": ("enabled",)},
"fields": (
"enabled",
)
},
), ),
( (
"Remote DCC-EX configuration", "Remote DCC-EX configuration",

View File

@@ -1,4 +1,6 @@
from django.contrib import admin from django.contrib import admin
from adminsortable2.admin import SortableAdminMixin
from metadata.models import ( from metadata.models import (
Property, Property,
Decoder, Decoder,
@@ -54,7 +56,7 @@ class TagAdmin(admin.ModelAdmin):
@admin.register(RollingStockType) @admin.register(RollingStockType)
class RollingStockTypeAdmin(admin.ModelAdmin): class RollingStockTypeAdmin(SortableAdminMixin, admin.ModelAdmin):
list_display = ("__str__",) list_display = ("__str__",)
list_filter = ("type", "category") list_filter = ("type", "category")
search_fields = list_display search_fields = list_display

View File

@@ -0,0 +1,23 @@
# Generated by Django 4.0.6 on 2022-07-14 14:46
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('metadata', '0003_property_private'),
]
operations = [
migrations.AlterModelOptions(
name='rollingstocktype',
options={'ordering': ['order']},
),
migrations.AddField(
model_name='rollingstocktype',
name='order',
field=models.PositiveSmallIntegerField(default=0),
preserve_default=False,
),
]

View File

@@ -63,7 +63,7 @@ class Decoder(models.Model):
manufacturer = models.ForeignKey( manufacturer = models.ForeignKey(
Manufacturer, Manufacturer,
on_delete=models.CASCADE, on_delete=models.CASCADE,
limit_choices_to={"category": "model"} limit_choices_to={"category": "model"},
) )
version = models.CharField(max_length=64, blank=True) version = models.CharField(max_length=64, blank=True)
interface = models.PositiveSmallIntegerField( interface = models.PositiveSmallIntegerField(
@@ -108,12 +108,14 @@ def tag_pre_save(sender, instance, **kwargs):
class RollingStockType(models.Model): class RollingStockType(models.Model):
type = models.CharField(max_length=64) type = models.CharField(max_length=64)
order = models.PositiveSmallIntegerField()
category = models.CharField( category = models.CharField(
max_length=64, choices=settings.ROLLING_STOCK_TYPES max_length=64, choices=settings.ROLLING_STOCK_TYPES
) )
class Meta(object): class Meta(object):
unique_together = ("category", "type") unique_together = ("category", "type")
ordering = ["order"]
def __str__(self): def __str__(self):
return "{0} {1}".format(self.type, self.category) return "{0} {1}".format(self.type, self.category)

View File

@@ -0,0 +1,18 @@
# Generated by Django 4.0.6 on 2022-07-15 12:07
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('portal', '0006_alter_siteconfiguration_site_name'),
]
operations = [
migrations.AddField(
model_name='siteconfiguration',
name='items_ordering',
field=models.CharField(choices=[('type', 'By rolling stock type'), ('company', 'By company name'), ('identifier', 'By rolling stock class')], default='type', max_length=10),
),
]

View File

@@ -16,6 +16,15 @@ class SiteConfiguration(SingletonModel):
choices=[(str(x * 3), str(x * 3)) for x in range(2, 11)], choices=[(str(x * 3), str(x * 3)) for x in range(2, 11)],
default="6", default="6",
) )
items_ordering = models.CharField(
max_length=10,
choices=[
("type", "By rolling stock type"),
("company", "By company name"),
("identifier", "By rolling stock class"),
],
default="type",
)
footer = models.TextField(blank=True) footer = models.TextField(blank=True)
footer_extended = models.TextField(blank=True) footer_extended = models.TextField(blank=True)
show_version = models.BooleanField(default=True) show_version = models.BooleanField(default=True)

View File

@@ -6,6 +6,11 @@
display: inline-block; display: inline-block;
} }
a.badge, a.badge:hover {
text-decoration: none;
color: #fff;
}
.tab-pane { .tab-pane {
min-height: 300px; min-height: 300px;
} }

View File

@@ -8,7 +8,7 @@
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="description" content=""> <meta name="description" content="{{ site_conf.about}}">
<meta name="author" content="{{ site_conf.site_author }}"> <meta name="author" content="{{ site_conf.site_author }}">
<meta name="generator" content="Django Framework"> <meta name="generator" content="Django Framework">
<title>{{ site_conf.site_name }}</title> <title>{{ site_conf.site_name }}</title>
@@ -85,8 +85,8 @@
<p class="card-text"><strong>{{ r }}</strong></p> <p class="card-text"><strong>{{ r }}</strong></p>
{% if r.tags.all %} {% if r.tags.all %}
<p class="card-text"><small>Tags:</small> <p class="card-text"><small>Tags:</small>
{% for t in r.tags.all %}<span class="badge bg-primary"> {% for t in r.tags.all %}<a href="{% url 'filtered' _filter="tag" search=t.slug %}" class="badge rounded-pill bg-primary">
{{ t.name }}</span>{# new line is required #} {{ t.name }}</a>{# new line is required #}
{% endfor %} {% endfor %}
</p> </p>
{% endif %} {% endif %}

View File

@@ -112,13 +112,17 @@
<span class="page-link">Previous</span> <span class="page-link">Previous</span>
</li> </li>
{% endif %} {% endif %}
{% for i in rolling_stock.paginator.page_range %} {% for i in page_range %}
{% if rolling_stock.number == i %} {% if rolling_stock.number == i %}
<li class="page-item active"> <li class="page-item active">
<span class="page-link">{{ i }}</span></span> <span class="page-link">{{ i }}</span></span>
</li> </li>
{% else %} {% else %}
<li class="page-item"><a class="page-link" href="{% url 'consist_pagination' uuid=consist.uuid page=i %}#rolling-stock">{{ i }}</a></li> {% if i == rolling_stock.paginator.ELLIPSIS %}
<li class="page-item"><span class="page-link">{{ i }}</span></li>
{% else %}
<li class="page-item"><a class="page-link" href="{% url 'consist_pagination' uuid=consist.uuid page=i %}#rolling-stock">{{ i }}</a></li>
{% endif %}
{% endif %} {% endif %}
{% endfor %} {% endfor %}
{% if rolling_stock.has_next %} {% if rolling_stock.has_next %}

View File

@@ -10,11 +10,11 @@
<div class="card shadow-sm"> <div class="card shadow-sm">
{% if c.image %}<a href="{{ c.get_absolute_url }}"><img src="{{ c.image.url }}" alt="Card image cap"></a>{% endif %} {% if c.image %}<a href="{{ c.get_absolute_url }}"><img src="{{ c.image.url }}" alt="Card image cap"></a>{% endif %}
<div class="card-body"> <div class="card-body">
<p class="card-text"><strong>{{ c.identifier }}</strong></p> <p class="card-text"><strong>{{ c }}</strong></p>
{% if c.tags.all %} {% if c.tags.all %}
<p class="card-text"><small>Tags:</small> <p class="card-text"><small>Tags:</small>
{% for t in c.tags.all %}<span class="badge bg-primary"> {% for t in c.tags.all %}<a href="{% url 'filtered' _filter="tag" search=t.slug %}" class="badge rounded-pill bg-primary">
{{ t.name }}</span>{# new line is required #} {{ t.name }}</a>{# new line is required #}
{% endfor %} {% endfor %}
</p> </p>
{% endif %} {% endif %}
@@ -70,13 +70,17 @@
<span class="page-link">Previous</span> <span class="page-link">Previous</span>
</li> </li>
{% endif %} {% endif %}
{% for i in consist.paginator.page_range %} {% for i in page_range %}
{% if consist.number == i %} {% if consist.number == i %}
<li class="page-item active"> <li class="page-item active">
<span class="page-link">{{ i }}</span></span> <span class="page-link">{{ i }}</span></span>
</li> </li>
{% else %} {% else %}
<li class="page-item"><a class="page-link" href="{% url 'consists_pagination' page=i %}#rolling-stock">{{ i }}</a></li> {% if i == rolling_stock.paginator.ELLIPSIS %}
<li class="page-item"><span class="page-link">{{ i }}</span></li>
{% else %}
<li class="page-item"><a class="page-link" href="{% url 'consists_pagination' page=i %}#rolling-stock">{{ i }}</a></li>
{% endif %}
{% endif %} {% endif %}
{% endfor %} {% endfor %}
{% if consist.has_next %} {% if consist.has_next %}

View File

@@ -19,13 +19,17 @@
<span class="page-link">Previous</span> <span class="page-link">Previous</span>
</li> </li>
{% endif %} {% endif %}
{% for i in rolling_stock.paginator.page_range %} {% for i in page_range %}
{% if rolling_stock.number == i %} {% if rolling_stock.number == i %}
<li class="page-item active"> <li class="page-item active">
<span class="page-link">{{ i }}</span></span> <span class="page-link">{{ i }}</span></span>
</li> </li>
{% else %} {% else %}
<li class="page-item"><a class="page-link" href="{% url 'index_pagination' page=i %}#rolling-stock">{{ i }}</a></li> {% if i == rolling_stock.paginator.ELLIPSIS %}
<li class="page-item"><span class="page-link">{{ i }}</span></li>
{% else %}
<li class="page-item"><a class="page-link" href="{% url 'index_pagination' page=i %}#rolling-stock">{{ i }}</a></li>
{% endif %}
{% endif %} {% endif %}
{% endfor %} {% endfor %}
{% if rolling_stock.has_next %} {% if rolling_stock.has_next %}

View File

@@ -1,5 +1,24 @@
<form class="d-flex" action="{% url 'search' %}" method="post"> <form class="d-flex needs-validation" action="{% url 'search' %}" method="post" novalidate>
<input class="form-control me-2" type="search" placeholder="Search" aria-label="Search" name="search"> <div class="input-group has-validation">
<button class="btn btn-outline-primary" type="submit">Search</button> <input class="form-control me-2" type="search" placeholder="Search" aria-label="Search" name="search" id="searchValidation" required>
<button class="btn btn-outline-primary" type="submit">Search</button>
</div>
</form> </form>
<script>
(function () {
'use strict'
// Fetch all the forms we want to apply custom Bootstrap validation styles to
var forms = document.querySelectorAll('.needs-validation')
// Loop over them and prevent submission
Array.prototype.slice.call(forms)
.forEach(function (form) {
form.addEventListener('submit', function (event) {
if (!form.checkValidity()) {
form.classList.add('was-validated')
event.preventDefault()
event.stopPropagation()
}
}, false)
})
})()
</script>

View File

@@ -5,8 +5,8 @@
<h1 class="fw-light">{{ rolling_stock }}</h1> <h1 class="fw-light">{{ rolling_stock }}</h1>
{% if rolling_stock.tags.all %} {% if rolling_stock.tags.all %}
<p><small>Tags:</small> <p><small>Tags:</small>
{% for t in rolling_stock.tags.all %}<span class="badge bg-primary"> {% for t in rolling_stock.tags.all %}<a href="{% url 'filtered' _filter="tag" search=t.slug %}" class="badge rounded-pill bg-primary">
{{ t.name }}</span>{# new line is required #} {{ t.name }}</a>{# new line is required #}
{% endfor %} {% endfor %}
</p> </p>
{% endif %} {% endif %}
@@ -72,7 +72,7 @@
<tbody> <tbody>
<tr> <tr>
<th width="35%" scope="row">Manufacturer</th> <th width="35%" scope="row">Manufacturer</th>
<td>{% if rolling_stock.manufacturer.website %}<a href="{{ rolling_stock.manufacturer.website }}">{% endif %}{{ rolling_stock.manufacturer }}{% if rolling_stock.manufacturer.website %}</a>{% endif %}</th> <td>{% if rolling_stock.manufacturer.website %}<a href="{{ rolling_stock.manufacturer.website }}">{% endif %}{{ rolling_stock.manufacturer|default_if_none:"" }}{% if rolling_stock.manufacturer.website %}</a>{% endif %}</th>
</tr> </tr>
<tr> <tr>
<th scope="row">Scale</th> <th scope="row">Scale</th>
@@ -114,7 +114,7 @@
<tbody> <tbody>
<tr> <tr>
<th width="35%" scope="row">Manufacturer</th> <th width="35%" scope="row">Manufacturer</th>
<td>{% if rolling_stock.manufacturer.website %}<a href="{{ rolling_stock.manufacturer.website }}">{% endif %}{{ rolling_stock.manufacturer }}{% if rolling_stock.manufacturer.website %}</a>{% endif %}</th> <td>{% if rolling_stock.manufacturer.website %}<a href="{{ rolling_stock.manufacturer.website }}">{% endif %}{{ rolling_stock.manufacturer|default_if_none:"" }}{% if rolling_stock.manufacturer.website %}</a>{% endif %}</th>
</tr> </tr>
<tr> <tr>
<th scope="row">Scale</th> <th scope="row">Scale</th>
@@ -182,7 +182,7 @@
</tr> </tr>
<tr> <tr>
<th scope="row">Manufacturer</th> <th scope="row">Manufacturer</th>
<td>{{ rolling_stock.rolling_class.manufacturer }}</td> <td>{{ rolling_stock.rolling_class.manufacturer|default_if_none:"" }}</td>
</tr> </tr>
</tbody> </tbody>
</table> </table>
@@ -222,7 +222,7 @@
</tr> </tr>
<tr> <tr>
<th scope="row">Manufacturer</th> <th scope="row">Manufacturer</th>
<td>{{ rolling_stock.decoder.manufacturer }}</td> <td>{{ rolling_stock.decoder.manufacturer|default_if_none:"" }}</td>
</tr> </tr>
<tr> <tr>
<th scope="row">Version</th> <th scope="row">Version</th>

View File

@@ -17,13 +17,17 @@
<span class="page-link">Previous</span> <span class="page-link">Previous</span>
</li> </li>
{% endif %} {% endif %}
{% for i in rolling_stock.paginator.page_range %} {% for i in page_range %}
{% if rolling_stock.number == i %} {% if rolling_stock.number == i %}
<li class="page-item active"> <li class="page-item active">
<span class="page-link">{{ i }}</span></span> <span class="page-link">{{ i }}</span></span>
</li> </li>
{% else %} {% else %}
<li class="page-item"><a class="page-link" href="{% url 'search_pagination' search=search page=i %}#rolling-stock">{{ i }}</a></li> {% if i == rolling_stock.paginator.ELLIPSIS %}
<li class="page-item"><span class="page-link">{{ i }}</span></li>
{% else %}
<li class="page-item"><a class="page-link" href="{% url 'index_pagination' page=i %}#rolling-stock">{{ i }}</a></li>
{% endif %}
{% endif %} {% endif %}
{% endfor %} {% endfor %}
{% if rolling_stock.has_next %} {% if rolling_stock.has_next %}

View File

@@ -24,8 +24,7 @@ urlpatterns = [
), ),
path("consists", Consists.as_view(), name="consists"), path("consists", Consists.as_view(), name="consists"),
path( path(
"consists/<int:page>", "consists/<int:page>", Consists.as_view(), name="consists_pagination"
Consists.as_view(), name="consists_pagination"
), ),
path("consist/<uuid:uuid>", GetConsist.as_view(), name="consist"), path("consist/<uuid:uuid>", GetConsist.as_view(), name="consist"),
path( path(

View File

@@ -13,20 +13,37 @@ from roster.models import RollingStock
from consist.models import Consist from consist.models import Consist
def order_by_fields():
order_by = get_site_conf().items_ordering
fields = [
"rolling_class__type",
"rolling_class__company",
"rolling_class__identifier",
"road_number_int",
]
if order_by == "type":
return (fields[0], fields[1], fields[2], fields[3])
elif order_by == "company":
return (fields[1], fields[0], fields[2], fields[3])
elif order_by == "identifier":
return (fields[2], fields[0], fields[1], fields[3])
class GetHome(View): class GetHome(View):
def get(self, request, page=1): def get(self, request, page=1):
site_conf = get_site_conf() site_conf = get_site_conf()
rolling_stock = RollingStock.objects.all() rolling_stock = RollingStock.objects.order_by(*order_by_fields())
paginator = Paginator(rolling_stock, site_conf.items_per_page) paginator = Paginator(rolling_stock, site_conf.items_per_page)
rolling_stock = paginator.get_page(page)
page_range = paginator.get_elided_page_range(rolling_stock.number)
try: return render(
rolling_stock = paginator.page(page) request,
except PageNotAnInteger: "home.html",
rolling_stock = paginator.page(1) {"rolling_stock": rolling_stock, "page_range": page_range},
except EmptyPage: )
rolling_stock = paginator.page(paginator.num_pages)
return render(request, "home.html", {"rolling_stock": rolling_stock})
class GetHomeFiltered(View): class GetHomeFiltered(View):
@@ -57,24 +74,25 @@ class GetHomeFiltered(View):
) )
elif _filter == "scale": elif _filter == "scale":
query = Q(scale__scale__icontains=search) query = Q(scale__scale__icontains=search)
elif _filter == "tag":
query = Q(tags__slug__icontains=search)
else: else:
raise Http404 raise Http404
rolling_stock = RollingStock.objects.filter(query) rolling_stock = RollingStock.objects.filter(query).order_by(
*order_by_fields()
)
matches = len(rolling_stock) matches = len(rolling_stock)
paginator = Paginator(rolling_stock, site_conf.items_per_page) paginator = Paginator(rolling_stock, site_conf.items_per_page)
rolling_stock = paginator.get_page(page)
page_range = paginator.get_elided_page_range(rolling_stock.number)
try: return rolling_stock, matches, page_range
rolling_stock = paginator.page(page)
except PageNotAnInteger:
rolling_stock = paginator.page(1)
except EmptyPage:
rolling_stock = paginator.page(paginator.num_pages)
return rolling_stock, matches
def get(self, request, search, _filter=None, page=1): def get(self, request, search, _filter=None, page=1):
rolling_stock, matches = self.run_search( rolling_stock, matches, page_range = self.run_search(
request, search, _filter, page) request, search, _filter, page
)
return render( return render(
request, request,
@@ -84,6 +102,7 @@ class GetHomeFiltered(View):
"filter": _filter, "filter": _filter,
"matches": matches, "matches": matches,
"rolling_stock": rolling_stock, "rolling_stock": rolling_stock,
"page_range": page_range,
}, },
) )
@@ -91,8 +110,9 @@ class GetHomeFiltered(View):
search = request.POST.get("search") search = request.POST.get("search")
if not search: if not search:
raise Http404 raise Http404
rolling_stock, matches = self.run_search( rolling_stock, matches, page_range = self.run_search(
request, search, _filter, page) request, search, _filter, page
)
return render( return render(
request, request,
@@ -102,6 +122,7 @@ class GetHomeFiltered(View):
"filter": _filter, "filter": _filter,
"matches": matches, "matches": matches,
"rolling_stock": rolling_stock, "rolling_stock": rolling_stock,
"page_range": page_range,
}, },
) )
@@ -114,15 +135,16 @@ class GetRollingStock(View):
raise Http404 raise Http404
class_properties = ( class_properties = (
rolling_stock.rolling_class.property.all() if rolling_stock.rolling_class.property.all()
request.user.is_authenticated else if request.user.is_authenticated
rolling_stock.rolling_class.property.filter( else rolling_stock.rolling_class.property.filter(
property__private=False) property__private=False
)
) )
rolling_stock_properties = ( rolling_stock_properties = (
rolling_stock.property.all() if rolling_stock.property.all()
request.user.is_authenticated else if request.user.is_authenticated
rolling_stock.property.filter(property__private=False) else rolling_stock.property.filter(property__private=False)
) )
return render( return render(
@@ -140,16 +162,16 @@ class Consists(View):
def get(self, request, page=1): def get(self, request, page=1):
site_conf = get_site_conf() site_conf = get_site_conf()
consist = Consist.objects.all() consist = Consist.objects.all()
paginator = Paginator(consist, site_conf.items_per_page) paginator = Paginator(consist, site_conf.items_per_page)
consist = paginator.get_page(page)
page_range = paginator.get_elided_page_range(consist.number)
try: return render(
consist = paginator.page(page) request,
except PageNotAnInteger: "consists.html",
consist = paginator.page(1) {"consist": consist, "page_range": page_range},
except EmptyPage: )
consist = paginator.page(paginator.num_pages)
return render(request, "consists.html", {"consist": consist})
class GetConsist(View): class GetConsist(View):
@@ -160,17 +182,17 @@ class GetConsist(View):
except ObjectDoesNotExist: except ObjectDoesNotExist:
raise Http404 raise Http404
rolling_stock = consist.consist_item.all() rolling_stock = consist.consist_item.all()
paginator = Paginator(rolling_stock, site_conf.items_per_page)
try: paginator = Paginator(rolling_stock, site_conf.items_per_page)
rolling_stock = paginator.page(page) rolling_stock = paginator.get_page(page)
except PageNotAnInteger: page_range = paginator.get_elided_page_range(rolling_stock.number)
rolling_stock = paginator.page(1)
except EmptyPage:
rolling_stock = paginator.page(paginator.num_pages)
return render( return render(
request, request,
"consist.html", "consist.html",
{"consist": consist, "rolling_stock": rolling_stock}, {
"consist": consist,
"rolling_stock": rolling_stock,
"page_range": page_range,
},
) )

View File

@@ -1,4 +1,4 @@
from ram.utils import git_suffix from ram.utils import git_suffix
__version__ = "0.0.5" __version__ = "0.0.6"
__version__ += git_suffix(__file__) __version__ += git_suffix(__file__)

View File

@@ -34,13 +34,21 @@ if settings.DEBUG:
from rest_framework.schemas import get_schema_view from rest_framework.schemas import get_schema_view
urlpatterns += [ urlpatterns += [
path('swagger/', TemplateView.as_view( path(
template_name='swagger.html', "swagger/",
extra_context={'schema_url': 'openapi-schema'} TemplateView.as_view(
), name='swagger'), template_name="swagger.html",
path('openapi', get_schema_view( extra_context={"schema_url": "openapi-schema"},
title="RAM - Railroad Assets Manager", ),
description="RAM API", name="swagger",
version="1.0.0" ),
), name='openapi-schema'), path(
"openapi",
get_schema_view(
title="RAM - Railroad Assets Manager",
description="RAM API",
version="1.0.0",
),
name="openapi-schema",
),
] ]

View File

@@ -0,0 +1,25 @@
# Generated by Django 4.0.6 on 2022-07-15 15:24
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('metadata', '0004_alter_rollingstocktype_options_and_more'),
('roster', '0006_alter_rollingclassproperty_rolling_class_and_more'),
]
operations = [
migrations.AlterField(
model_name='rollingclass',
name='company',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='metadata.company'),
),
migrations.AlterField(
model_name='rollingclass',
name='type',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='metadata.rollingstocktype'),
),
]

View File

@@ -0,0 +1,34 @@
# Generated by Django 4.0.6 on 2022-07-15 15:55
from django.db import migrations, models
def gen_road_number_cleaned(apps, schema_editor):
RollingStock = apps.get_model('roster', 'RollingStock')
for row in RollingStock.objects.all():
row.road_number_cleaned = row.road_number.lstrip('#').lstrip('0')
row.save(update_fields=['road_number_cleaned'])
class Migration(migrations.Migration):
dependencies = [
('roster', '0007_alter_rollingclass_company_alter_rollingclass_type'),
]
operations = [
migrations.AddField(
model_name='rollingstock',
name='road_number_cleaned',
field=models.CharField(default='', max_length=128),
preserve_default=False,
),
migrations.RunPython(
gen_road_number_cleaned,
reverse_code=migrations.RunPython.noop
),
migrations.AlterModelOptions(
name='rollingstock',
options={'ordering': ['rolling_class', 'road_number_cleaned'], 'verbose_name_plural': 'Rolling stock'},
),
]

View File

@@ -0,0 +1,41 @@
# Generated by Django 4.0.6 on 2022-07-16 15:38
import re
from django.db import migrations, models
def gen_road_number_cleaned(apps, schema_editor):
RollingStock = apps.get_model('roster', 'RollingStock')
for row in RollingStock.objects.all():
try:
row.road_number_int = int(re.findall(r"\d+", row.road_number)[0])
row.save(update_fields=['road_number_int'])
except IndexError:
pass
class Migration(migrations.Migration):
dependencies = [
('roster', '0008_rollingstock_road_number_cleaned'),
]
operations = [
migrations.AlterModelOptions(
name='rollingstock',
options={'ordering': ['rolling_class', 'road_number_int'], 'verbose_name_plural': 'Rolling stock'},
),
migrations.RemoveField(
model_name='rollingstock',
name='road_number_cleaned',
),
migrations.AddField(
model_name='rollingstock',
name='road_number_int',
field=models.PositiveSmallIntegerField(default=0),
),
migrations.RunPython(
gen_road_number_cleaned,
reverse_code=migrations.RunPython.noop
),
]

View File

@@ -1,10 +1,11 @@
import os import os
import re
from uuid import uuid4 from uuid import uuid4
from django.db import models from django.db import models
from django.urls import reverse from django.urls import reverse
from django.dispatch import receiver
# from django.core.files.storage import FileSystemStorage # from django.core.files.storage import FileSystemStorage
# from django.dispatch import receiver
from ram.utils import get_image_preview from ram.utils import get_image_preview
from metadata.models import ( from metadata.models import (
@@ -25,12 +26,8 @@ from metadata.models import (
class RollingClass(models.Model): class RollingClass(models.Model):
identifier = models.CharField(max_length=128, unique=False) identifier = models.CharField(max_length=128, unique=False)
type = models.ForeignKey( type = models.ForeignKey(RollingStockType, on_delete=models.CASCADE)
RollingStockType, on_delete=models.CASCADE, null=True, blank=True company = models.ForeignKey(Company, on_delete=models.CASCADE)
)
company = models.ForeignKey(
Company, on_delete=models.CASCADE, null=True, blank=True
)
description = models.CharField(max_length=256, blank=True) description = models.CharField(max_length=256, blank=True)
manufacturer = models.ForeignKey( manufacturer = models.ForeignKey(
Manufacturer, Manufacturer,
@@ -79,6 +76,7 @@ class RollingStock(models.Model):
verbose_name="Class", verbose_name="Class",
) )
road_number = models.CharField(max_length=128, unique=False) road_number = models.CharField(max_length=128, unique=False)
road_number_int = models.PositiveSmallIntegerField(default=0, unique=False)
manufacturer = models.ForeignKey( manufacturer = models.ForeignKey(
Manufacturer, Manufacturer,
on_delete=models.CASCADE, on_delete=models.CASCADE,
@@ -103,7 +101,7 @@ class RollingStock(models.Model):
updated_time = models.DateTimeField(auto_now=True) updated_time = models.DateTimeField(auto_now=True)
class Meta: class Meta:
ordering = ["rolling_class", "road_number"] ordering = ["rolling_class", "road_number_int"]
verbose_name_plural = "Rolling stock" verbose_name_plural = "Rolling stock"
def __str__(self): def __str__(self):
@@ -119,6 +117,16 @@ class RollingStock(models.Model):
return str(self.rolling_class.company) return str(self.rolling_class.company)
@receiver(models.signals.pre_save, sender=RollingStock)
def pre_save_running_number(sender, instance, *args, **kwargs):
try:
instance.road_number_int = int(
re.findall(r"\d+", instance.road_number)[0]
)
except IndexError:
pass
class RollingStockDocument(models.Model): class RollingStockDocument(models.Model):
rolling_stock = models.ForeignKey( rolling_stock = models.ForeignKey(
RollingStock, on_delete=models.CASCADE, related_name="document" RollingStock, on_delete=models.CASCADE, related_name="document"

View File

@@ -15,17 +15,13 @@ class RosterGet(RetrieveAPIView):
serializer_class = RollingStockSerializer serializer_class = RollingStockSerializer
lookup_field = "uuid" lookup_field = "uuid"
schema = AutoSchema( schema = AutoSchema(operation_id_base="retrieveRollingStockByUUID")
operation_id_base="retrieveRollingStockByUUID"
)
class RosterAddress(ListAPIView): class RosterAddress(ListAPIView):
serializer_class = RollingStockSerializer serializer_class = RollingStockSerializer
schema = AutoSchema( schema = AutoSchema(operation_id_base="retrieveRollingStockByAddress")
operation_id_base="retrieveRollingStockByAddress"
)
def get_queryset(self): def get_queryset(self):
address = self.kwargs["address"] address = self.kwargs["address"]
@@ -35,9 +31,7 @@ class RosterAddress(ListAPIView):
class RosterClass(ListAPIView): class RosterClass(ListAPIView):
serializer_class = RollingStockSerializer serializer_class = RollingStockSerializer
schema = AutoSchema( schema = AutoSchema(operation_id_base="retrieveRollingStockByClass")
operation_id_base="retrieveRollingStockByClass"
)
def get_queryset(self): def get_queryset(self):
_class = self.kwargs["class"] _class = self.kwargs["class"]