mirror of
https://github.com/daniviga/django-ram.git
synced 2025-08-03 20:57:50 +02:00
Complete Catalogs with code refactoring
This commit is contained in:
@@ -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")
|
||||
|
@@ -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",
|
||||
),
|
||||
|
@@ -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()])
|
||||
|
@@ -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>
|
||||
|
@@ -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">
|
||||
|
@@ -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 %}
|
||||
|
@@ -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>
|
||||
|
19
ram/portal/templatetags/dynamic_url.py
Normal file
19
ram/portal/templatetags/dynamic_url.py
Normal 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])
|
@@ -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"]),
|
||||
|
@@ -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:
|
||||
|
Reference in New Issue
Block a user