Add support for manufacturer filters

This commit is contained in:
2023-01-06 01:25:55 +01:00
parent 9b8ec6ba6b
commit aff1d20260
9 changed files with 173 additions and 13 deletions

View File

@@ -1,3 +1,5 @@
from urllib.parse import quote_plus
from django.db import models from django.db import models
from django.conf import settings from django.conf import settings
from django.dispatch.dispatcher import receiver from django.dispatch.dispatcher import receiver
@@ -34,6 +36,9 @@ class Manufacturer(models.Model):
def __str__(self): def __str__(self):
return self.name return self.name
def safe_name(self):
return quote_plus(self.name, safe="&")
def logo_thumbnail(self): def logo_thumbnail(self):
return get_image_preview(self.logo.url) return get_image_preview(self.logo.url)
@@ -56,6 +61,9 @@ class Company(models.Model):
def __str__(self): def __str__(self):
return self.name return self.name
def safe_name(self):
return quote_plus(self.name, safe="&")
def logo_thumbnail(self): def logo_thumbnail(self):
return get_image_preview(self.logo.url) return get_image_preview(self.logo.url)

View File

@@ -88,6 +88,15 @@
<li class="nav-item"> <li class="nav-item">
<a class="nav-link" href="{% url 'scales' %}">Scales</a> <a class="nav-link" href="{% url 'scales' %}">Scales</a>
</li> </li>
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" id="navbarDropdownMenuLink" role="button" data-bs-toggle="dropdown" aria-expanded="false">
Manufacturers
</a>
<ul class="dropdown-menu" aria-labelledby="navbarDropdownMenuLink">
<li><a class="dropdown-item" href="{% url 'manufacturers' category='model' %}">Models</a></li>
<li><a class="dropdown-item" href="{% url 'manufacturers' category='real' %}">Real</a></li>
</ul>
</li>
{% show_menu %} {% show_menu %}
</ul> </ul>
{% include 'includes/search.html' %} {% include 'includes/search.html' %}

View File

@@ -35,7 +35,7 @@
<tr> <tr>
<th scope="row">Company</th> <th scope="row">Company</th>
<td> <td>
<a href="{% url 'filtered' _filter="company" search=r.rolling_class.company %}"><abbr title="{{ r.rolling_class.company.extended_name }}">{{ r.rolling_class.company }}</abbr></a> <a href="{% url 'filtered' _filter="company" search=r.rolling_class.company.safe_name %}"><abbr title="{{ r.rolling_class.company.extended_name }}">{{ r.rolling_class.company }}</abbr></a>
</td> </td>
</tr> </tr>
<tr> <tr>
@@ -52,7 +52,9 @@
</tr> </tr>
<tr> <tr>
<th width="35%" scope="row">Manufacturer</th> <th width="35%" scope="row">Manufacturer</th>
<td>{{ r.manufacturer|default_if_none:"" }}{% if r.manufacturer.website %} <a href="{{ r.manufacturer.website }}" target="_blank"><i class="bi bi-box-arrow-up-right"></i></a>{% endif %}</td> <td>{%if r.manufacturer %}
<a href="{% url 'filtered' _filter="manufacturer" search=r.manufacturer.safe_name %}">{{ r.manufacturer }}{% if r.manufacturer.website %}</a> <a href="{{ r.manufacturer.website }}" target="_blank"><i class="bi bi-box-arrow-up-right"></i></a>{% endif %}
{% endif %}</td>
</tr> </tr>
<tr> <tr>
<th scope="row">Scale</th> <th scope="row">Scale</th>

View File

@@ -73,7 +73,9 @@
</tr> </tr>
<tr> <tr>
<th width="35%" scope="row">Manufacturer</th> <th width="35%" scope="row">Manufacturer</th>
<td>{{ r.rolling_stock.manufacturer|default_if_none:"" }}{% if r.rolling_stock.manufacturer.website %} <a href="{{ r.rolling_stock.manufacturer.website }}" target="_blank"><i class="bi bi-box-arrow-up-right"></i></a>{% endif %}</td> <td>{%if r.rolling_stock.manufacturer %}
<a href="{% url 'filtered' _filter="manufacturer" search=r.rolling_stock.manufacturer.safe_name %}">{{ r.rolling_stock.manufacturer }}{% if r.rolling_stock.manufacturer.website %}</a> <a href="{{ r.rolling_stock.manufacturer.website }}" target="_blank"><i class="bi bi-box-arrow-up-right"></i></a>{% endif %}
{% endif %}</td>
</tr> </tr>
<tr> <tr>
<th scope="row">Scale</th> <th scope="row">Scale</th>

View File

@@ -1,7 +1,7 @@
{% if menu %} {% if menu %}
<li class="nav-item dropdown"> <li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" id="navbarDropdownMenuLink" role="button" data-bs-toggle="dropdown" aria-expanded="false"> <a class="nav-link dropdown-toggle" href="#" id="navbarDropdownMenuLink" role="button" data-bs-toggle="dropdown" aria-expanded="false">
More ... Articles
</a> </a>
<ul class="dropdown-menu" aria-labelledby="navbarDropdownMenuLink"> <ul class="dropdown-menu" aria-labelledby="navbarDropdownMenuLink">
{% for m in menu %} {% for m in menu %}

View File

@@ -0,0 +1,83 @@
{% extends "cards.html" %}
{% block cards %}
{% for m in manufacturers %}
<div class="col">
<div class="card shadow-sm">
<div class="card-body">
<p class="card-text" style="position: relative;">
<strong>{{ m.name }}</strong>
</p>
<table class="table table-striped">
<thead>
<tr>
<th colspan="2" scope="row">Manufacturer</th>
</tr>
</thead>
<tbody>
{% if m.logo %}
<tr>
<th width="35%" scope="row">Logo</th>
<td><img style="max-height: 48px" src="{{ m.logo.url }}" /></td>
</tr>
{% endif %}
{% if m.website %}
<tr>
<th width="35%" scope="row">Website</th>
<td><a href="{{ m.website }}" target="_blank"><i class="bi bi-box-arrow-up-right"></i></a></td>
</tr>
{% endif %}
<tr>
<th width="35%" scope="row">Category</th>
<td>{{ m.category | title }}</td>
</tr>
</tbody>
</table>
<div class="d-grid gap-2 mb-1 d-md-block">
<a class="btn btn-sm btn-outline-primary" href="{% url 'filtered' _filter="manufacturer" search=m.safe_name %}">Show all rolling stock</a>
{% if request.user.is_staff %}<a class="btn btn-sm btn-outline-danger" href="{% url 'admin:metadata_manufacturer_change' m.pk %}">Edit</a>{% endif %}
</div>
</div>
</div>
</div>
{% endfor %}
{% endblock %}
{% block pagination %}
{% if manufacturers.has_other_pages %}
<nav aria-label="Page navigation example">
<ul class="pagination justify-content-center mt-4 mb-0">
{% if manufacturers.has_previous %}
<li class="page-item">
<a class="page-link" href="{% url 'manufacturers_pagination' category=category page=manufacturers.previous_page_number %}#rolling-stock" tabindex="-1">Previous</a>
</li>
{% else %}
<li class="page-item disabled">
<span class="page-link">Previous</span>
</li>
{% endif %}
{% for i in page_range %}
{% if manufacturers.number == i %}
<li class="page-item active">
<span class="page-link">{{ i }}</span></span>
</li>
{% else %}
{% if i == manufacturers.paginator.ELLIPSIS %}
<li class="page-item"><span class="page-link">{{ i }}</span></li>
{% else %}
<li class="page-item"><a class="page-link" href="{% url 'manufacturers_pagination' category=category page=i %}#rolling-stock">{{ i }}</a></li>
{% endif %}
{% endif %}
{% endfor %}
{% if manufacturers.has_next %}
<li class="page-item">
<a class="page-link" href="{% url 'manufacturers_pagination' category=category page=manufacturers.next_page_number %}#rolling-stock" tabindex="-1">Next</a>
</li>
{% else %}
<li class="page-item disabled">
<span class="page-link">Next</span>
</li>
{% endif %}
</ul>
</nav>
{% endif %}
{% endblock %}

View File

@@ -70,7 +70,7 @@
<tr> <tr>
<th scope="row">Company</th> <th scope="row">Company</th>
<td> <td>
<a href="{% url 'filtered' _filter="company" search=rolling_stock.rolling_class.company %}"><abbr title="{{ rolling_stock.rolling_class.company.extended_name }}">{{ rolling_stock.rolling_class.company }}</abbr></a> <a href="{% url 'filtered' _filter="company" search=rolling_stock.rolling_class.company.safe_name %}"><abbr title="{{ rolling_stock.rolling_class.company.extended_name }}">{{ rolling_stock.rolling_class.company }}</abbr></a>
</td> </td>
</tr> </tr>
<tr> <tr>
@@ -96,7 +96,9 @@
<tbody> <tbody>
<tr> <tr>
<th width="35%" scope="row">Manufacturer</th> <th width="35%" scope="row">Manufacturer</th>
<td>{{ rolling_stock.manufacturer|default_if_none:"" }}{% if rolling_stock.manufacturer.website %} <a href="{{ rolling_stock.manufacturer.website }}" target="_blank"><i class="bi bi-box-arrow-up-right"></i></a>{% endif %}</td> <td>{%if rolling_stock.manufacturer %}
<a href="{% url 'filtered' _filter="manufacturer" search=rolling_stock.manufacturer.safe_name %}">{{ rolling_stock.manufacturer }}{% if rolling_stock.manufacturer.website %}</a> <a href="{{ rolling_stock.manufacturer.website }}" target="_blank"><i class="bi bi-box-arrow-up-right"></i></a>{% endif %}
{% endif %}</td>
</tr> </tr>
<tr> <tr>
<th scope="row">Scale</th> <th scope="row">Scale</th>
@@ -144,11 +146,13 @@
<tbody> <tbody>
<tr> <tr>
<th width="35%" scope="row">Manufacturer</th> <th width="35%" scope="row">Manufacturer</th>
<td>{{ rolling_stock.manufacturer|default_if_none:"" }}{% if rolling_stock.manufacturer.website %} <a href="{{ rolling_stock.manufacturer.website }}" target="_blank"><i class="bi bi-box-arrow-up-right"></i></a>{% endif %}</td> <td>{%if rolling_stock.manufacturer %}
<a href="{% url 'filtered' _filter="manufacturer" search=rolling_stock.manufacturer.safe_name %}">{{ rolling_stock.manufacturer }}{% if rolling_stock.manufacturer.website %}</a> <a href="{{ rolling_stock.manufacturer.website }}" target="_blank"><i class="bi bi-box-arrow-up-right"></i></a>{% endif %}
{% endif %}</td>
</tr> </tr>
<tr> <tr>
<th scope="row">Scale</th> <th scope="row">Scale</th>
<td><abbr title="{{ rolling_stock.scale.ratio }} - {{ rolling_stock.scale.tracks }}">{{ rolling_stock.scale }}</abbr></td> <td><a href="{% url 'filtered' _filter="scale" search=rolling_stock.scale %}"><abbr title="{{ rolling_stock.scale.ratio }} - {{ rolling_stock.scale.tracks }}">{{ rolling_stock.scale }}</abbr></a></td>
</tr> </tr>
<tr> <tr>
<th scope="row">SKU</th> <th scope="row">SKU</th>
@@ -204,7 +208,9 @@
</tr> </tr>
<tr> <tr>
<th scope="row">Company</th> <th scope="row">Company</th>
<td>{{ rolling_stock.rolling_class.company }} ({{ rolling_stock.rolling_class.company.extended_name }})</td> <td>
<a href="{% url 'filtered' _filter="company" search=rolling_stock.rolling_class.company.safe_name %}">{{ rolling_stock.rolling_class.company }}</a> ({{ rolling_stock.rolling_class.company.extended_name }})
</td>
</tr> </tr>
<tr> <tr>
<th scope="row">Country</th> <th scope="row">Country</th>
@@ -212,7 +218,9 @@
</tr> </tr>
<tr> <tr>
<th scope="row">Manufacturer</th> <th scope="row">Manufacturer</th>
<td>{{ rolling_stock.rolling_class.manufacturer|default_if_none:"" }}</td> <td>{%if rolling_stock.rolling_class.manufacturer %}
<a href="{% url 'filtered' _filter="manufacturer" search=rolling_stock.rolling_class.manufacturer.safe_name %}">{{ rolling_stock.rolling_class.manufacturer }}{% if rolling_stock.rolling_class.manufacturer.website %}</a> <a href="{{ rolling_stock.rolling_class.manufacturer.website }}" target="_blank"><i class="bi bi-box-arrow-up-right"></i></a>{% endif %}
{% endif %}</td>
</tr> </tr>
</tbody> </tbody>
</table> </table>

View File

@@ -8,6 +8,7 @@ from portal.views import (
GetConsist, GetConsist,
Consists, Consists,
Companies, Companies,
Manufacturers,
Scales, Scales,
) )
@@ -40,6 +41,16 @@ urlpatterns = [
Companies.as_view(), Companies.as_view(),
name="companies_pagination", name="companies_pagination",
), ),
path(
"manufacturers/<str:category>",
Manufacturers.as_view(),
name="manufacturers"
),
path(
"manufacturers/<str:category>/<int:page>",
Manufacturers.as_view(),
name="manufacturers_pagination",
),
path("scales", Scales.as_view(), name="scales"), path("scales", Scales.as_view(), name="scales"),
path("scales/<int:page>", Scales.as_view(), name="scales_pagination"), path("scales/<int:page>", Scales.as_view(), name="scales_pagination"),
path( path(

View File

@@ -1,5 +1,6 @@
import operator import operator
from functools import reduce from functools import reduce
from urllib.parse import quote_plus, unquote_plus
from django.views import View from django.views import View
from django.http import Http404 from django.http import Http404
@@ -12,7 +13,7 @@ from portal.utils import get_site_conf
from portal.models import Flatpage from portal.models import Flatpage
from roster.models import RollingStock from roster.models import RollingStock
from consist.models import Consist from consist.models import Consist
from metadata.models import Company, Scale from metadata.models import Company, Manufacturer, Scale
def order_by_fields(): def order_by_fields():
@@ -81,6 +82,11 @@ class GetHomeFiltered(View):
Q(rolling_class__company__name__icontains=search) Q(rolling_class__company__name__icontains=search)
| Q(rolling_class__company__extended_name__icontains=search) | Q(rolling_class__company__extended_name__icontains=search)
) )
elif _filter == "manufacturer":
query = Q(
Q(manufacturer__name__iexact=search)
| Q(rolling_class__manufacturer__name__icontains=search)
)
elif _filter == "scale": elif _filter == "scale":
query = Q(scale__scale__iexact=search) query = Q(scale__scale__iexact=search)
elif _filter == "tag": elif _filter == "tag":
@@ -103,16 +109,19 @@ class GetHomeFiltered(View):
return rolling_stock, matches, page_range return rolling_stock, matches, page_range
def get(self, request, search, _filter="search", page=1): def get(self, request, search, _filter="search", page=1):
search_unsafe = unquote_plus(search) # expected to be encoded
rolling_stock, matches, page_range = self.run_search( rolling_stock, matches, page_range = self.run_search(
request, search, _filter, page request, search_unsafe, _filter, page
) )
return render( return render(
request, request,
"search.html", "search.html",
{ {
"title": "{0}: {1}".format(_filter.capitalize(), search), "title": "{0}: {1}".format(
_filter.capitalize(), search_unsafe),
"search": search, "search": search,
"search_unsafe": search_unsafe,
"filter": _filter, "filter": _filter,
"matches": matches, "matches": matches,
"rolling_stock": rolling_stock, "rolling_stock": rolling_stock,
@@ -122,6 +131,8 @@ class GetHomeFiltered(View):
def post(self, request, _filter="search", page=1): def post(self, request, _filter="search", page=1):
search = request.POST.get("search") search = request.POST.get("search")
# search = quote_plus(request.POST.get("search"), safe="&")
# search_unsafe = unquote_plus(search)
if not search: if not search:
raise Http404 raise Http404
rolling_stock, matches, page_range = self.run_search( rolling_stock, matches, page_range = self.run_search(
@@ -134,6 +145,7 @@ class GetHomeFiltered(View):
{ {
"title": "{0}: {1}".format(_filter.capitalize(), search), "title": "{0}: {1}".format(_filter.capitalize(), search),
"search": search, "search": search,
# "search_unsafe": search_unsafe,
"filter": _filter, "filter": _filter,
"matches": matches, "matches": matches,
"rolling_stock": rolling_stock, "rolling_stock": rolling_stock,
@@ -230,6 +242,31 @@ class GetConsist(View):
) )
class Manufacturers(View):
def get(self, request, category, page=1):
site_conf = get_site_conf()
if category not in ("real", "model"):
raise Http404
manufacturers = Manufacturer.objects.filter(category=category)
paginator = Paginator(manufacturers, site_conf.items_per_page)
manufacturers = paginator.get_page(page)
page_range = paginator.get_elided_page_range(
manufacturers.number, on_each_side=2, on_ends=1
)
return render(
request,
"manufacturers.html",
{
"title": "Manufacturers",
"category": category,
"manufacturers": manufacturers,
"page_range": page_range,
},
)
class Companies(View): class Companies(View):
def get(self, request, page=1): def get(self, request, page=1):
site_conf = get_site_conf() site_conf = get_site_conf()