mirror of
https://github.com/daniviga/django-ram.git
synced 2025-08-04 13:17: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",
|
"number_of_pages",
|
||||||
"published",
|
"published",
|
||||||
)
|
)
|
||||||
|
autocomplete_fields = ("authors", "publisher")
|
||||||
readonly_fields = ("creation_time", "updated_time")
|
readonly_fields = ("creation_time", "updated_time")
|
||||||
search_fields = ("title", "publisher__name", "authors__last_name")
|
search_fields = ("title", "publisher__name", "authors__last_name")
|
||||||
list_filter = ("publisher__name", "authors")
|
list_filter = ("publisher__name", "authors")
|
||||||
@@ -101,6 +102,7 @@ class CatalogAdmin(SortableAdminBase, admin.ModelAdmin):
|
|||||||
"get_scales",
|
"get_scales",
|
||||||
"published",
|
"published",
|
||||||
)
|
)
|
||||||
|
autocomplete_fields = ("manufacturer",)
|
||||||
readonly_fields = ("creation_time", "updated_time")
|
readonly_fields = ("creation_time", "updated_time")
|
||||||
search_fields = ("manufacturer__name", "years", "scales__scale")
|
search_fields = ("manufacturer__name", "years", "scales__scale")
|
||||||
list_filter = ("manufacturer__name", "publication_year", "scales__scale")
|
list_filter = ("manufacturer__name", "publication_year", "scales__scale")
|
||||||
|
@@ -127,8 +127,6 @@ class Migration(migrations.Migration):
|
|||||||
(
|
(
|
||||||
"manufacturer",
|
"manufacturer",
|
||||||
models.ForeignKey(
|
models.ForeignKey(
|
||||||
blank=True,
|
|
||||||
null=True,
|
|
||||||
on_delete=django.db.models.deletion.CASCADE,
|
on_delete=django.db.models.deletion.CASCADE,
|
||||||
to="metadata.manufacturer",
|
to="metadata.manufacturer",
|
||||||
),
|
),
|
||||||
|
@@ -108,15 +108,16 @@ class Book(BaseBook):
|
|||||||
return self.publisher.name
|
return self.publisher.name
|
||||||
|
|
||||||
def get_absolute_url(self):
|
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):
|
class Catalog(BaseBook):
|
||||||
manufacturer = models.ForeignKey(
|
manufacturer = models.ForeignKey(
|
||||||
Manufacturer,
|
Manufacturer,
|
||||||
on_delete=models.CASCADE,
|
on_delete=models.CASCADE,
|
||||||
null=True,
|
|
||||||
blank=True,
|
|
||||||
)
|
)
|
||||||
years = models.CharField(max_length=12)
|
years = models.CharField(max_length=12)
|
||||||
scales = models.ManyToManyField(Scale)
|
scales = models.ManyToManyField(Scale)
|
||||||
@@ -125,8 +126,15 @@ class Catalog(BaseBook):
|
|||||||
ordering = ["manufacturer", "publication_year"]
|
ordering = ["manufacturer", "publication_year"]
|
||||||
|
|
||||||
def __str__(self):
|
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)
|
return "%s %s %s" % (self.manufacturer.name, self.years, scales)
|
||||||
|
|
||||||
def get_absolute_url(self):
|
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' %}
|
{% extends 'base.html' %}
|
||||||
|
{% load dynamic_url %}
|
||||||
|
|
||||||
{% block header %}
|
{% block header %}
|
||||||
{% if book.tags.all %}
|
{% if book.tags.all %}
|
||||||
@@ -57,24 +58,39 @@
|
|||||||
{{ book.description | safe }}
|
{{ book.description | safe }}
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
|
{% if type == "catalog" %}
|
||||||
|
<th colspan="2" scope="row">Catalog</th>
|
||||||
|
{% elif type == "book" %}
|
||||||
<th colspan="2" scope="row">Book</th>
|
<th colspan="2" scope="row">Book</th>
|
||||||
|
{% endif %}
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody class="table-group-divider">
|
<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>
|
<tr>
|
||||||
<th class="w-33" scope="row">Title</th>
|
<th class="w-33" scope="row">Title</th>
|
||||||
<td>{{ book.title }}</td>
|
<td>{{ book.title }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<th scope="row">Authors</th>
|
<th class="w-33" scope="row">Authors</th>
|
||||||
<td>
|
<td>
|
||||||
<ul class="mb-0 list-unstyled">{% for a in book.authors.all %}<li>{{ a }}</li>{% endfor %}</ul>
|
<ul class="mb-0 list-unstyled">{% for a in book.authors.all %}<li>{{ a }}</li>{% endfor %}</ul>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<th scope="row">Publisher</th>
|
<th class="w-33" scope="row">Publisher</th>
|
||||||
<td>{{ book.publisher }}</td>
|
<td>{{ book.publisher }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
{% endif %}
|
||||||
<tr>
|
<tr>
|
||||||
<th scope="row">ISBN</th>
|
<th scope="row">ISBN</th>
|
||||||
<td>{{ book.ISBN|default:"-" }}</td>
|
<td>{{ book.ISBN|default:"-" }}</td>
|
||||||
@@ -120,7 +136,8 @@
|
|||||||
</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">
|
||||||
{% 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>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@@ -1,11 +1,13 @@
|
|||||||
{% extends "cards.html" %}
|
{% extends "cards.html" %}
|
||||||
|
{% load dynamic_url %}
|
||||||
|
|
||||||
{% block pagination %}
|
{% block pagination %}
|
||||||
{% if data.has_other_pages %}
|
{% if data.has_other_pages %}
|
||||||
<nav aria-label="Page navigation example">
|
<nav aria-label="Page navigation example">
|
||||||
<ul class="pagination flex-wrap justify-content-center mt-4 mb-0">
|
<ul class="pagination flex-wrap justify-content-center mt-4 mb-0">
|
||||||
{% if data.has_previous %}
|
{% if data.has_previous %}
|
||||||
<li class="page-item">
|
<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>
|
</li>
|
||||||
{% else %}
|
{% else %}
|
||||||
<li class="page-item disabled">
|
<li class="page-item disabled">
|
||||||
@@ -21,13 +23,13 @@
|
|||||||
{% if i == data.paginator.ELLIPSIS %}
|
{% if i == data.paginator.ELLIPSIS %}
|
||||||
<li class="page-item"><span class="page-link">{{ i }}</span></li>
|
<li class="page-item"><span class="page-link">{{ i }}</span></li>
|
||||||
{% else %}
|
{% 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 %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
{% if data.has_next %}
|
{% if data.has_next %}
|
||||||
<li class="page-item">
|
<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>
|
</li>
|
||||||
{% else %}
|
{% else %}
|
||||||
<li class="page-item disabled">
|
<li class="page-item disabled">
|
||||||
|
@@ -18,7 +18,7 @@
|
|||||||
{% include "cards/consist.html" %}
|
{% include "cards/consist.html" %}
|
||||||
{% elif d.type == "manufacturer" %}
|
{% elif d.type == "manufacturer" %}
|
||||||
{% include "cards/manufacturer.html" %}
|
{% include "cards/manufacturer.html" %}
|
||||||
{% elif d.type == "book" %}
|
{% elif d.type == "book" or d.type == "catalog" %}
|
||||||
{% include "cards/book.html" %}
|
{% include "cards/book.html" %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
@@ -1,3 +1,4 @@
|
|||||||
|
{% load dynamic_url %}
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<div class="card shadow-sm">
|
<div class="card shadow-sm">
|
||||||
{% if d.item.image.exists %}
|
{% if d.item.image.exists %}
|
||||||
@@ -18,10 +19,24 @@
|
|||||||
<table class="table table-striped">
|
<table class="table table-striped">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
|
{% if d.type == "catalog" %}
|
||||||
|
<th colspan="2" scope="row">Catalog</th>
|
||||||
|
{% elif d.type == "book" %}
|
||||||
<th colspan="2" scope="row">Book</th>
|
<th colspan="2" scope="row">Book</th>
|
||||||
|
{% endif %}
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody class="table-group-divider">
|
<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>
|
<tr>
|
||||||
<th class="w-33" scope="row">Authors</th>
|
<th class="w-33" scope="row">Authors</th>
|
||||||
<td>
|
<td>
|
||||||
@@ -32,6 +47,7 @@
|
|||||||
<th class="w-33" scope="row">Publisher</th>
|
<th class="w-33" scope="row">Publisher</th>
|
||||||
<td>{{ d.item.publisher }}</td>
|
<td>{{ d.item.publisher }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
{% endif %}
|
||||||
<tr>
|
<tr>
|
||||||
<th scope="row">Language</th>
|
<th scope="row">Language</th>
|
||||||
<td>{{ d.item.get_language_display }}</td>
|
<td>{{ d.item.get_language_display }}</td>
|
||||||
@@ -48,7 +64,7 @@
|
|||||||
</table>
|
</table>
|
||||||
<div class="d-grid gap-2 mb-1 d-md-block">
|
<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>
|
<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>
|
</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,
|
Scales,
|
||||||
Types,
|
Types,
|
||||||
Books,
|
Books,
|
||||||
GetBook,
|
|
||||||
Catalogs,
|
Catalogs,
|
||||||
GetCatalog,
|
GetBookCatalog,
|
||||||
SearchObjects,
|
SearchObjects,
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -99,7 +98,11 @@ urlpatterns = [
|
|||||||
Books.as_view(template="bookshelf/books.html"),
|
Books.as_view(template="bookshelf/books.html"),
|
||||||
name="books_pagination"
|
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(
|
path(
|
||||||
"bookshelf/catalogs",
|
"bookshelf/catalogs",
|
||||||
Catalogs.as_view(template="bookshelf/books.html"),
|
Catalogs.as_view(template="bookshelf/books.html"),
|
||||||
@@ -110,11 +113,6 @@ urlpatterns = [
|
|||||||
Catalogs.as_view(template="bookshelf/books.html"),
|
Catalogs.as_view(template="bookshelf/books.html"),
|
||||||
name="catalogs_pagination"
|
name="catalogs_pagination"
|
||||||
),
|
),
|
||||||
path(
|
|
||||||
"bookshelf/catalog/<uuid:uuid>",
|
|
||||||
GetCatalog.as_view(),
|
|
||||||
name="catalog"
|
|
||||||
),
|
|
||||||
path(
|
path(
|
||||||
"search",
|
"search",
|
||||||
SearchObjects.as_view(http_method_names=["post"]),
|
SearchObjects.as_view(http_method_names=["post"]),
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
import base64
|
import base64
|
||||||
import operator
|
import operator
|
||||||
|
from itertools import chain
|
||||||
from functools import reduce
|
from functools import reduce
|
||||||
from urllib.parse import unquote
|
from urllib.parse import unquote
|
||||||
|
|
||||||
@@ -77,7 +78,8 @@ class GetData(View):
|
|||||||
for item in self.get_data(request):
|
for item in self.get_data(request):
|
||||||
data.append({"type": self.item_type, "item": item})
|
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)
|
data = paginator.get_page(page)
|
||||||
page_range = paginator.get_elided_page_range(
|
page_range = paginator.get_elided_page_range(
|
||||||
data.number, on_each_side=1, on_ends=1
|
data.number, on_each_side=1, on_ends=1
|
||||||
@@ -148,6 +150,8 @@ class SearchObjects(View):
|
|||||||
raise Http404
|
raise Http404
|
||||||
|
|
||||||
# FIXME duplicated code!
|
# FIXME duplicated code!
|
||||||
|
# FIXME see if it makes sense to filter calatogs and books by scale
|
||||||
|
# and manufacturer as well
|
||||||
data = []
|
data = []
|
||||||
rolling_stock = (
|
rolling_stock = (
|
||||||
RollingStock.objects.get_published(request.user)
|
RollingStock.objects.get_published(request.user)
|
||||||
@@ -157,6 +161,7 @@ class SearchObjects(View):
|
|||||||
)
|
)
|
||||||
for item in rolling_stock:
|
for item in rolling_stock:
|
||||||
data.append({"type": "rolling_stock", "item": item})
|
data.append({"type": "rolling_stock", "item": item})
|
||||||
|
|
||||||
if _filter is None:
|
if _filter is None:
|
||||||
consists = (
|
consists = (
|
||||||
Consist.objects.get_published(request.user)
|
Consist.objects.get_published(request.user)
|
||||||
@@ -175,7 +180,12 @@ class SearchObjects(View):
|
|||||||
.filter(title__icontains=search)
|
.filter(title__icontains=search)
|
||||||
.distinct()
|
.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})
|
data.append({"type": "book", "item": item})
|
||||||
|
|
||||||
paginator = Paginator(data, get_items_per_page())
|
paginator = Paginator(data, get_items_per_page())
|
||||||
@@ -517,10 +527,26 @@ class Books(GetData):
|
|||||||
return Book.objects.get_published(request.user).all()
|
return Book.objects.get_published(request.user).all()
|
||||||
|
|
||||||
|
|
||||||
class GetBook(View):
|
class Catalogs(GetData):
|
||||||
def get(self, request, uuid):
|
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:
|
try:
|
||||||
book = Book.objects.get_published(request.user).get(uuid=uuid)
|
book = self.get_object(request, uuid, selector)
|
||||||
except ObjectDoesNotExist:
|
except ObjectDoesNotExist:
|
||||||
raise Http404
|
raise Http404
|
||||||
|
|
||||||
@@ -532,38 +558,11 @@ class GetBook(View):
|
|||||||
"title": book,
|
"title": book,
|
||||||
"book_properties": book_properties,
|
"book_properties": book_properties,
|
||||||
"book": book,
|
"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):
|
class GetFlatpage(View):
|
||||||
def get(self, request, flatpage):
|
def get(self, request, flatpage):
|
||||||
try:
|
try:
|
||||||
|
Reference in New Issue
Block a user