Compare commits

...

2 Commits

Author SHA1 Message Date
2ab2d00585 Improve ordering 2026-01-03 00:54:21 +01:00
c95064ddec More templates modularization 2026-01-02 23:19:18 +01:00
16 changed files with 161 additions and 133 deletions

View File

@@ -20,6 +20,7 @@ class SiteConfigurationAdmin(SingletonModelAdmin):
"about", "about",
"items_per_page", "items_per_page",
"items_ordering", "items_ordering",
"featured_items_ordering",
"currency", "currency",
"footer", "footer",
"footer_extended", "footer_extended",

View File

@@ -0,0 +1,43 @@
# Generated by Django 6.0 on 2026-01-02 23:41
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("portal", "0020_alter_flatpage_options"),
]
operations = [
migrations.AddField(
model_name="siteconfiguration",
name="featured_items_ordering",
field=models.CharField(
choices=[
("type", "By rolling stock type and company"),
("class", "By rolling stock type and class"),
("company", "By company and type"),
("country", "By country and type"),
("cou+com", "By country and company"),
],
default="type",
max_length=11,
),
),
migrations.AlterField(
model_name="siteconfiguration",
name="items_ordering",
field=models.CharField(
choices=[
("type", "By rolling stock type and company"),
("class", "By rolling stock type and class"),
("company", "By company and type"),
("country", "By country and type"),
("cou+com", "By country and company"),
],
default="type",
max_length=11,
),
),
]

View File

@@ -22,14 +22,17 @@ class SiteConfiguration(SingletonModel):
default="6", default="6",
) )
items_ordering = models.CharField( items_ordering = models.CharField(
max_length=10, max_length=11,
choices=[ choices=[
("type", "By rolling stock type"), ("type", "By rolling stock type and company"),
("company", "By company name"), ("class", "By rolling stock type and class"),
("identifier", "By rolling stock class"), ("company", "By company and type"),
("country", "By country and type"),
("cou+com", "By country and company"),
], ],
default="type", default="type",
) )
featured_items_ordering = items_ordering.clone()
currency = models.CharField(max_length=3, default="EUR") currency = models.CharField(max_length=3, default="EUR")
footer = tinymce.HTMLField(blank=True) footer = tinymce.HTMLField(blank=True)
footer_extended = tinymce.HTMLField(blank=True) footer_extended = tinymce.HTMLField(blank=True)

View File

@@ -0,0 +1,26 @@
{% if documents %}
<table class="table table-striped">
<thead>
<tr>
<th colspan="3" scope="row">{{ header|default:"Documents" }}</th>
</tr>
</thead>
<tbody class="table-group-divider">
{% for d in documents.all %}
<tr>
<td class="w-33">{{ d.description }}</td>
<td class="text-nowrap">
{% if d.private %}
<i class="bi bi-file-earmark-lock2"></i>
{% else %}
<i class="bi bi-file-earmark-text"></i>
{% endif %}
<a href="{{ d.file.url }}" target="_blank">{{ d.filename }}</a>
</td>
<td class="text-end">{{ d.file.size | filesizeformat }}</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endif %}

View File

@@ -0,0 +1,18 @@
{% if properties %}
<table class="table table-striped">
<thead>
<tr>
<th colspan="2" scope="row">Properties</th>
</tr>
</thead>
<tbody class="table-group-divider">
{% for p in properties %}
<tr>
<th class="w-33" scope="row">{{ p.property }}</th>
<td>{{ p.value }}</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endif %}

View File

@@ -0,0 +1,29 @@
{% if request.user.is_staff %}
{% if data.shop or data.purchase_date or data.price %}
<table class="table table-striped">
<thead>
<tr>
<th colspan="2" scope="row">Purchase</th>
</tr>
</thead>
<tbody class="table-group-divider">
<tr>
<th class="w-33" scope="row">Shop</th>
<td>
{{ data.shop|default:"-" }}
{% if data.shop.website %} <a href="{{ data.shop.website }}" target="_blank"><i class="bi bi-box-arrow-up-right"></i></a>{% endif %}
</td>
</tr>
<tr>
<th class="w-33" scope="row">Purchase date</th>
<td>{{ data.purchase_date|default:"-" }}</td>
</tr>
<tr>
<th scope="row">Price ({{ site_conf.currency }})</th>
<td>{{ data.price|default:"-" }}</td>
</tr>
</tbody>
</table>
{% endif %}
{% endif %}

View File

@@ -148,7 +148,7 @@
<strong>{{ site_conf.site_name }}</strong> <strong>{{ site_conf.site_name }}</strong>
</a> </a>
</div> </div>
{% include 'includes/login.html' %} {% include '_includes/login.html' %}
</div> </div>
</nav> </nav>
</header> </header>
@@ -186,7 +186,7 @@
{% show_bookshelf_menu %} {% show_bookshelf_menu %}
{% show_flatpages_menu user %} {% show_flatpages_menu user %}
</ul> </ul>
{% include 'includes/search.html' %} {% include '_includes/search.html' %}
</div> </div>
</div> </div>
</nav> </nav>
@@ -211,9 +211,9 @@
<div class="container">{% block pagination %}{% endblock %}</div> <div class="container">{% block pagination %}{% endblock %}</div>
</div> </div>
{% block extra_content %}{% endblock %} {% block extra_content %}{% endblock %}
{% include 'includes/symbols.html' %} {% include '_includes/symbols.html' %}
</main> </main>
{% include 'includes/footer.html' %} {% include '_includes/footer.html' %}
{% if site_conf.use_cdn %} {% if site_conf.use_cdn %}
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/js/bootstrap.bundle.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/js/bootstrap.bundle.min.js"></script>
{% else %} {% else %}

View File

@@ -147,49 +147,8 @@
{% endif %} {% endif %}
</tbody> </tbody>
</table> </table>
{% if request.user.is_staff %} {% include "_modules/purchase_data.html" %}
<table class="table table-striped"> {% include "_modules/properties.html" %}
<thead>
<tr>
<th colspan="2" scope="row">Purchase</th>
</tr>
</thead>
<tbody class="table-group-divider">
<tr>
<th class="w-33" scope="row">Shop</th>
<td>
{{ data.shop|default:"-" }}
{% if data.shop.website %} <a href="{{ data.shop.website }}" target="_blank"><i class="bi bi-box-arrow-up-right"></i></a>{% endif %}
</td>
</tr>
<tr>
<th class="w-33" scope="row">Purchase date</th>
<td>{{ data.purchase_date|default:"-" }}</td>
</tr>
<tr>
<th scope="row">Price ({{ site_conf.currency }})</th>
<td>{{ data.price|default:"-" }}</td>
</tr>
</tbody>
</table>
{% endif %}
{% if properties %}
<table class="table table-striped">
<thead>
<tr>
<th colspan="2" scope="row">Properties</th>
</tr>
</thead>
<tbody class="table-group-divider">
{% for p in properties %}
<tr>
<th class="w-33" scope="row">{{ p.property }}</th>
<td>{{ p.value }}</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endif %}
</div> </div>
<div class="tab-pane table-responsive" id="nav-toc" role="tabpanel" aria-labelledby="nav-toc-tab"> <div class="tab-pane table-responsive" id="nav-toc" role="tabpanel" aria-labelledby="nav-toc-tab">
<table class="table table-striped"> <table class="table table-striped">
@@ -216,7 +175,7 @@
</table> </table>
</div> </div>
<div class="tab-pane" id="nav-documents" role="tabpanel" aria-labelledby="nav-documents-tab"> <div class="tab-pane" id="nav-documents" role="tabpanel" aria-labelledby="nav-documents-tab">
{% include "includes/documents.html" %} {% include "_modules/documents.html" %}
</div> </div>
</div> </div>
<div class="d-grid gap-2 d-md-flex justify-content-md-end"> <div class="d-grid gap-2 d-md-flex justify-content-md-end">

View File

@@ -217,49 +217,8 @@
{% endif %} {% endif %}
</tbody> </tbody>
</table> </table>
{% if request.user.is_staff %} {% include "_modules/purchase_data.html" with data=rolling_stock %}
<table class="table table-striped"> {% include "_modules/properties.html" %}
<thead>
<tr>
<th colspan="2" scope="row">Purchase</th>
</tr>
</thead>
<tbody class="table-group-divider">
<tr>
<th class="w-33" scope="row">Shop</th>
<td>
{{ rolling_stock.shop | default:"-" }}
{% if rolling_stock.shop.website %} <a href="{{ rolling_stock.shop.website }}" target="_blank"><i class="bi bi-box-arrow-up-right"></i></a>{% endif %}
</td>
</tr>
<tr>
<th class="w-33" scope="row">Purchase date</th>
<td>{{ rolling_stock.purchase_date | default:"-" }}</td>
</tr>
<tr>
<th scope="row">Price ({{ site_conf.currency }})</th>
<td>{{ rolling_stock.price | default:"-" }}</td>
</tr>
</tbody>
</table>
{% endif %}
{% if properties %}
<table class="table table-striped">
<thead>
<tr>
<th colspan="2" scope="row">Properties</th>
</tr>
</thead>
<tbody class="table-group-divider">
{% for p in properties %}
<tr>
<th class="w-33" scope="row">{{ p.property }}</th>
<td>{{ p.value }}</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endif %}
</div> </div>
<div class="tab-pane" id="nav-class" role="tabpanel" aria-labelledby="nav-class-tab"> <div class="tab-pane" id="nav-class" role="tabpanel" aria-labelledby="nav-class-tab">
<table class="table table-striped"> <table class="table table-striped">
@@ -296,23 +255,7 @@
{% endif %} {% endif %}
</tbody> </tbody>
</table> </table>
{% if class_properties %} {% include "_modules/properties.html" with properties=class_properties %}
<table class="table table-striped">
<thead>
<tr>
<th colspan="2" scope="row">Properties</th>
</tr>
</thead>
<tbody class="table-group-divider">
{% for p in class_properties %}
<tr>
<th class="w-33" scope="row">{{ p.property }}</th>
<td>{{ p.value }}</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endif %}
</div> </div>
<div class="tab-pane" id="nav-company" role="tabpanel" aria-labelledby="nav-company-tab"> <div class="tab-pane" id="nav-company" role="tabpanel" aria-labelledby="nav-company-tab">
<table class="table table-striped"> <table class="table table-striped">
@@ -403,8 +346,8 @@
</table> </table>
</div> </div>
<div class="tab-pane table-responsive" id="nav-documents" role="tabpanel" aria-labelledby="nav-documents-tab"> <div class="tab-pane table-responsive" id="nav-documents" role="tabpanel" aria-labelledby="nav-documents-tab">
{% include "includes/documents.html" %} {% include "_modules/documents.html" %}
{% include "includes/documents.html" with documents=decoder_documents header="Decoder documents" %} {% include "_modules/documents.html" with documents=decoder_documents header="Decoder documents" %}
</div> </div>
<div class="tab-pane" id="nav-journal" role="tabpanel" aria-labelledby="nav-journal-tab"> <div class="tab-pane" id="nav-journal" role="tabpanel" aria-labelledby="nav-journal-tab">
<table class="table table-striped"> <table class="table table-striped">

View File

@@ -36,25 +36,29 @@ def get_items_per_page():
return int(items_per_page) return int(items_per_page)
def get_order_by_field(): def get_items_ordering(config="items_ordering"):
try: try:
order_by = get_site_conf().items_ordering order_by = getattr(get_site_conf(), config)
except (OperationalError, ProgrammingError): except (OperationalError, ProgrammingError):
order_by = "type" order_by = "type"
fields = [ fields = [
"rolling_class__type", "rolling_class__type", # 0
"rolling_class__company", "rolling_class__company", # 1
"rolling_class__identifier", "rolling_class__company__country", # 2
"road_number_int", "rolling_class__identifier", # 3
"road_number_int", # 4
] ]
if order_by == "type": order_map = {
return (fields[0], fields[1], fields[2], fields[3]) "type": (0, 1, 3, 4),
elif order_by == "company": "company": (1, 0, 3, 4),
return (fields[1], fields[0], fields[2], fields[3]) "country": (2, 0, 1, 3, 4),
elif order_by == "identifier": "cou+com": (2, 1, 0, 3, 4),
return (fields[2], fields[0], fields[1], fields[3]) "class": (0, 3, 1, 4),
}
return tuple(fields[i] for i in order_map.get(order_by, "type"))
class Render404(View): class Render404(View):
@@ -70,7 +74,7 @@ class GetData(View):
def get_data(self, request): def get_data(self, request):
return ( return (
RollingStock.objects.get_published(request.user) RollingStock.objects.get_published(request.user)
.order_by(*get_order_by_field()) .order_by(*get_items_ordering())
.filter(self.filter) .filter(self.filter)
) )
@@ -107,7 +111,9 @@ class GetHome(GetData):
return ( return (
RollingStock.objects.get_published(request.user) RollingStock.objects.get_published(request.user)
.filter(featured=True) .filter(featured=True)
.order_by(*get_order_by_field())[:max_items] .order_by(*get_items_ordering(config="featured_items_ordering"))[
:max_items
]
) or super().get_data(request) ) or super().get_data(request)
@@ -174,7 +180,7 @@ class SearchObjects(View):
RollingStock.objects.get_published(request.user) RollingStock.objects.get_published(request.user)
.filter(query) .filter(query)
.distinct() .distinct()
.order_by(*get_order_by_field()) .order_by(*get_items_ordering())
) )
data = list(roster) data = list(roster)
@@ -301,7 +307,7 @@ class GetManufacturerItem(View):
if search != "all": if search != "all":
roster = get_list_or_404( roster = get_list_or_404(
RollingStock.objects.get_published(request.user).order_by( RollingStock.objects.get_published(request.user).order_by(
*get_order_by_field() *get_items_ordering()
), ),
Q( Q(
Q(manufacturer=manufacturer) Q(manufacturer=manufacturer)
@@ -323,7 +329,7 @@ class GetManufacturerItem(View):
| Q(rolling_class__manufacturer=manufacturer) | Q(rolling_class__manufacturer=manufacturer)
) )
.distinct() .distinct()
.order_by(*get_order_by_field()) .order_by(*get_items_ordering())
) )
catalogs = Catalog.objects.get_published(request.user).filter( catalogs = Catalog.objects.get_published(request.user).filter(
manufacturer=manufacturer manufacturer=manufacturer
@@ -376,7 +382,7 @@ class GetObjectsFiltered(View):
RollingStock.objects.get_published(request.user) RollingStock.objects.get_published(request.user)
.filter(query) .filter(query)
.distinct() .distinct()
.order_by(*get_order_by_field()) .order_by(*get_items_ordering())
) )
data = list(roster) data = list(roster)
@@ -480,7 +486,7 @@ class GetRollingStock(View):
& Q(set=True) & Q(set=True)
) )
) )
.order_by(*get_order_by_field()) .order_by(*get_items_ordering())
) )
return render( return render(