Complete Catalogs with code refactoring

This commit is contained in:
2024-12-22 18:53:47 +01:00
parent 64f616d89f
commit cbf6c942b9
10 changed files with 118 additions and 59 deletions

View File

@@ -35,6 +35,7 @@ class BookAdmin(SortableAdminBase, admin.ModelAdmin):
"number_of_pages",
"published",
)
autocomplete_fields = ("authors", "publisher")
readonly_fields = ("creation_time", "updated_time")
search_fields = ("title", "publisher__name", "authors__last_name")
list_filter = ("publisher__name", "authors")
@@ -101,6 +102,7 @@ class CatalogAdmin(SortableAdminBase, admin.ModelAdmin):
"get_scales",
"published",
)
autocomplete_fields = ("manufacturer",)
readonly_fields = ("creation_time", "updated_time")
search_fields = ("manufacturer__name", "years", "scales__scale")
list_filter = ("manufacturer__name", "publication_year", "scales__scale")

View File

@@ -127,8 +127,6 @@ class Migration(migrations.Migration):
(
"manufacturer",
models.ForeignKey(
blank=True,
null=True,
on_delete=django.db.models.deletion.CASCADE,
to="metadata.manufacturer",
),

View File

@@ -108,15 +108,16 @@ class Book(BaseBook):
return self.publisher.name
def get_absolute_url(self):
return reverse("book", kwargs={"uuid": self.uuid})
return reverse(
"bookshelf_item",
kwargs={"selector": "book", "uuid": self.uuid}
)
class Catalog(BaseBook):
manufacturer = models.ForeignKey(
Manufacturer,
on_delete=models.CASCADE,
null=True,
blank=True,
)
years = models.CharField(max_length=12)
scales = models.ManyToManyField(Scale)
@@ -125,8 +126,15 @@ class Catalog(BaseBook):
ordering = ["manufacturer", "publication_year"]
def __str__(self):
scales = "/".join([s.scale for s in self.scales.all()])
scales = self.get_scales
return "%s %s %s" % (self.manufacturer.name, self.years, scales)
def get_absolute_url(self):
return reverse("catalog", kwargs={"uuid": self.uuid})
return reverse(
"bookshelf_item",
kwargs={"selector": "catalog", "uuid": self.uuid}
)
@property
def get_scales(self):
return "/".join([s.scale for s in self.scales.all()])

View File

@@ -1,4 +1,5 @@
{% extends 'base.html' %}
{% load dynamic_url %}
{% block header %}
{% if book.tags.all %}
@@ -57,24 +58,39 @@
{{ book.description | safe }}
<thead>
<tr>
{% if type == "catalog" %}
<th colspan="2" scope="row">Catalog</th>
{% elif type == "book" %}
<th colspan="2" scope="row">Book</th>
{% endif %}
</tr>
</thead>
<tbody class="table-group-divider">
{% if type == "catalog" %}
<tr>
<th class="w-33" scope="row">Manufacturer</th>
<td>{{ book.manufacturer }}</td>
</tr>
<tr>
<th class="w-33" scope="row">Scales</th>
<td>{{ book.get_scales }}</td>
</tr>
{% elif type == "book" %}
<tr>
<th class="w-33" scope="row">Title</th>
<td>{{ book.title }}</td>
</tr>
<tr>
<th scope="row">Authors</th>
<td>
<ul class="mb-0 list-unstyled">{% for a in book.authors.all %}<li>{{ a }}</li>{% endfor %}</ul>
</td>
<th class="w-33" scope="row">Authors</th>
<td>
<ul class="mb-0 list-unstyled">{% for a in book.authors.all %}<li>{{ a }}</li>{% endfor %}</ul>
</td>
</tr>
<tr>
<th scope="row">Publisher</th>
<th class="w-33" scope="row">Publisher</th>
<td>{{ book.publisher }}</td>
</tr>
{% endif %}
<tr>
<th scope="row">ISBN</th>
<td>{{ book.ISBN|default:"-" }}</td>
@@ -120,7 +136,8 @@
</div>
</div>
<div class="d-grid gap-2 d-md-flex justify-content-md-end">
{% if request.user.is_staff %}<a class="btn btn-sm btn-outline-danger" href="{% url 'admin:bookshelf_book_change' book.pk %}">Edit</a>{% endif %}
FIXME: {{ type }}
{% if request.user.is_staff %}<a class="btn btn-sm btn-outline-danger" href="{% dynamic_admin_url 'bookshelf' type book.pk %}">Edit</a>{% endif %}
</div>
</div>
</div>

View File

@@ -1,11 +1,13 @@
{% extends "cards.html" %}
{% load dynamic_url %}
{% block pagination %}
{% if data.has_other_pages %}
<nav aria-label="Page navigation example">
<ul class="pagination flex-wrap justify-content-center mt-4 mb-0">
{% if data.has_previous %}
<li class="page-item">
<a class="page-link" href="{% url 'books_pagination' page=data.previous_page_number %}#main-content" tabindex="-1"><i class="bi bi-chevron-left"></i></a>
<a class="page-link" href="{% dynamic_pagination type page=data.previous_page_number %}#main-content" tabindex="-1"><i class="bi bi-chevron-left"></i></a>
</li>
{% else %}
<li class="page-item disabled">
@@ -21,13 +23,13 @@
{% if i == data.paginator.ELLIPSIS %}
<li class="page-item"><span class="page-link">{{ i }}</span></li>
{% else %}
<li class="page-item"><a class="page-link" href="{% url 'books_pagination' page=i %}#main-content">{{ i }}</a></li>
<li class="page-item"><a class="page-link" href="{% dynamic_pagination type page=i %}#main-content">{{ i }}</a></li>
{% endif %}
{% endif %}
{% endfor %}
{% if data.has_next %}
<li class="page-item">
<a class="page-link" href="{% url 'books_pagination' page=data.next_page_number %}#main-content" tabindex="-1"><i class="bi bi-chevron-right"></i></a>
<a class="page-link" href="{% dynamic_pagination type page=data.next_page_number %}#main-content" tabindex="-1"><i class="bi bi-chevron-right"></i></a>
</li>
{% else %}
<li class="page-item disabled">

View File

@@ -18,7 +18,7 @@
{% include "cards/consist.html" %}
{% elif d.type == "manufacturer" %}
{% include "cards/manufacturer.html" %}
{% elif d.type == "book" %}
{% elif d.type == "book" or d.type == "catalog" %}
{% include "cards/book.html" %}
{% endif %}
{% endfor %}

View File

@@ -1,3 +1,4 @@
{% load dynamic_url %}
<div class="col">
<div class="card shadow-sm">
{% if d.item.image.exists %}
@@ -18,10 +19,24 @@
<table class="table table-striped">
<thead>
<tr>
{% if d.type == "catalog" %}
<th colspan="2" scope="row">Catalog</th>
{% elif d.type == "book" %}
<th colspan="2" scope="row">Book</th>
{% endif %}
</tr>
</thead>
<tbody class="table-group-divider">
{% if d.type == "catalog" %}
<tr>
<th class="w-33" scope="row">Manufacturer</th>
<td>{{ d.item.manufacturer }}</td>
</tr>
<tr>
<th class="w-33" scope="row">Scales</th>
<td>{{ d.item.get_scales }}</td>
</tr>
{% elif d.type == "book" %}
<tr>
<th class="w-33" scope="row">Authors</th>
<td>
@@ -32,6 +47,7 @@
<th class="w-33" scope="row">Publisher</th>
<td>{{ d.item.publisher }}</td>
</tr>
{% endif %}
<tr>
<th scope="row">Language</th>
<td>{{ d.item.get_language_display }}</td>
@@ -48,7 +64,7 @@
</table>
<div class="d-grid gap-2 mb-1 d-md-block">
<a class="btn btn-sm btn-outline-primary" href="{{ d.item.get_absolute_url }}">Show all data</a>
{% if request.user.is_staff %}<a class="btn btn-sm btn-outline-danger" href="{% url 'admin:bookshelf_book_change' d.item.pk %}">Edit</a>{% endif %}
{% if request.user.is_staff %}<a class="btn btn-sm btn-outline-danger" href="{% dynamic_admin_url 'bookshelf' d.type d.item.pk %}">Edit</a>{% endif %}
</div>
</div>
</div>

View File

@@ -0,0 +1,19 @@
from django import template
from django.urls import reverse
register = template.Library()
@register.simple_tag
def dynamic_admin_url(app_name, model_name, object_id=None):
if object_id:
return reverse(
f'admin:{app_name}_{model_name}_change',
args=[object_id]
)
return reverse(f'admin:{app_name}_{model_name}_changelist')
@register.simple_tag
def dynamic_pagination(model_name, page):
return reverse(f'{model_name}s_pagination', args=[page])

View File

@@ -14,9 +14,8 @@ from portal.views import (
Scales,
Types,
Books,
GetBook,
Catalogs,
GetCatalog,
GetBookCatalog,
SearchObjects,
)
@@ -99,7 +98,11 @@ urlpatterns = [
Books.as_view(template="bookshelf/books.html"),
name="books_pagination"
),
path("bookshelf/book/<uuid:uuid>", GetBook.as_view(), name="book"),
path(
"bookshelf/<str:selector>/<uuid:uuid>",
GetBookCatalog.as_view(),
name="bookshelf_item"
),
path(
"bookshelf/catalogs",
Catalogs.as_view(template="bookshelf/books.html"),
@@ -110,11 +113,6 @@ urlpatterns = [
Catalogs.as_view(template="bookshelf/books.html"),
name="catalogs_pagination"
),
path(
"bookshelf/catalog/<uuid:uuid>",
GetCatalog.as_view(),
name="catalog"
),
path(
"search",
SearchObjects.as_view(http_method_names=["post"]),

View File

@@ -1,5 +1,6 @@
import base64
import operator
from itertools import chain
from functools import reduce
from urllib.parse import unquote
@@ -77,7 +78,8 @@ class GetData(View):
for item in self.get_data(request):
data.append({"type": self.item_type, "item": item})
paginator = Paginator(data, get_items_per_page())
paginator = Paginator(data, 3)
# paginator = Paginator(data, get_items_per_page())
data = paginator.get_page(page)
page_range = paginator.get_elided_page_range(
data.number, on_each_side=1, on_ends=1
@@ -148,6 +150,8 @@ class SearchObjects(View):
raise Http404
# FIXME duplicated code!
# FIXME see if it makes sense to filter calatogs and books by scale
# and manufacturer as well
data = []
rolling_stock = (
RollingStock.objects.get_published(request.user)
@@ -157,6 +161,7 @@ class SearchObjects(View):
)
for item in rolling_stock:
data.append({"type": "rolling_stock", "item": item})
if _filter is None:
consists = (
Consist.objects.get_published(request.user)
@@ -175,7 +180,12 @@ class SearchObjects(View):
.filter(title__icontains=search)
.distinct()
)
for item in books:
catalogs = (
Catalog.objects.get_published(request.user)
.filter(manufacturer__name__icontains=search)
.distinct()
)
for item in list(chain(books, catalogs)):
data.append({"type": "book", "item": item})
paginator = Paginator(data, get_items_per_page())
@@ -517,10 +527,26 @@ class Books(GetData):
return Book.objects.get_published(request.user).all()
class GetBook(View):
def get(self, request, uuid):
class Catalogs(GetData):
title = "Catalogs"
item_type = "catalog"
def get_data(self, request):
return Catalog.objects.get_published(request.user).all()
class GetBookCatalog(View):
def get_object(self, request, uuid, selector):
if selector == "book":
return Book.objects.get_published(request.user).get(uuid=uuid)
elif selector == "catalog":
return Catalog.objects.get_published(request.user).get(uuid=uuid)
else:
raise Http404
def get(self, request, uuid, selector):
try:
book = Book.objects.get_published(request.user).get(uuid=uuid)
book = self.get_object(request, uuid, selector)
except ObjectDoesNotExist:
raise Http404
@@ -532,38 +558,11 @@ class GetBook(View):
"title": book,
"book_properties": book_properties,
"book": book,
"type": selector
},
)
class Catalogs(GetData):
title = "Catalogs"
item_type = "book"
def get_data(self, request):
return Catalog.objects.get_published(request.user).all()
class GetCatalog(View):
def get(self, request, uuid):
try:
catalog = Catalog.objects.get_published(request.user).get(uuid=uuid)
except ObjectDoesNotExist:
raise Http404
catalog_properties = catalog.property.get_public(request.user)
return render(
request,
"bookshelf/book.html",
{
"title": catalog,
"catalog_properties": catalog_properties,
"book": catalog,
},
)
class GetFlatpage(View):
def get(self, request, flatpage):
try: