mirror of
https://github.com/daniviga/django-ram.git
synced 2026-02-04 10:00:40 +01:00
Improve performance oprimizing queries (#56)
* Extend test coverage * Implement query optimization * More aggressing code reuse * Add more indexes and optimize usage * Fix tests * Further optimizations, improve counting to rely on backend DB * chore: add Makefile for frontend asset minification - Add comprehensive Makefile with targets for JS and CSS minification - Implements instructions from ram/portal/static/js/src/README.md - Provides targets: install, minify, minify-js, minify-css, clean, watch - Fix main.min.js to only include theme_selector.js and tabs_selector.js - Remove validators.js from minified output per README instructions * Add a Makefile to compile JS and CSS * docs: add blank line whitespace rule to AGENTS.md Specify that blank lines must not contain any whitespace (spaces or tabs) to maintain code cleanliness and PEP 8 compliance * Update for 0.20 release with optimizations * Improve Makefile
This commit is contained in:
@@ -98,6 +98,11 @@ class BookAdmin(SortableAdminBase, admin.ModelAdmin):
|
||||
search_fields = ("title", "publisher__name", "authors__last_name")
|
||||
list_filter = ("publisher__name", "authors", "published")
|
||||
|
||||
def get_queryset(self, request):
|
||||
"""Optimize queryset with select_related and prefetch_related."""
|
||||
qs = super().get_queryset(request)
|
||||
return qs.with_related()
|
||||
|
||||
fieldsets = (
|
||||
(
|
||||
None,
|
||||
@@ -189,6 +194,12 @@ class BookAdmin(SortableAdminBase, admin.ModelAdmin):
|
||||
]
|
||||
|
||||
data = []
|
||||
|
||||
# Prefetch related data to avoid N+1 queries
|
||||
queryset = queryset.select_related(
|
||||
'publisher', 'shop'
|
||||
).prefetch_related('authors', 'tags', 'property__property')
|
||||
|
||||
for obj in queryset:
|
||||
properties = settings.CSV_SEPARATOR_ALT.join(
|
||||
"{}:{}".format(property.property.name, property.value)
|
||||
@@ -266,6 +277,11 @@ class CatalogAdmin(SortableAdminBase, admin.ModelAdmin):
|
||||
"scales__scale",
|
||||
)
|
||||
|
||||
def get_queryset(self, request):
|
||||
"""Optimize queryset with select_related and prefetch_related."""
|
||||
qs = super().get_queryset(request)
|
||||
return qs.with_related()
|
||||
|
||||
fieldsets = (
|
||||
(
|
||||
None,
|
||||
@@ -350,6 +366,12 @@ class CatalogAdmin(SortableAdminBase, admin.ModelAdmin):
|
||||
]
|
||||
|
||||
data = []
|
||||
|
||||
# Prefetch related data to avoid N+1 queries
|
||||
queryset = queryset.select_related(
|
||||
'manufacturer', 'shop'
|
||||
).prefetch_related('scales', 'tags', 'property__property')
|
||||
|
||||
for obj in queryset:
|
||||
properties = settings.CSV_SEPARATOR_ALT.join(
|
||||
"{}:{}".format(property.property.name, property.value)
|
||||
@@ -490,6 +512,11 @@ class MagazineAdmin(SortableAdminBase, admin.ModelAdmin):
|
||||
"publisher__name",
|
||||
)
|
||||
|
||||
def get_queryset(self, request):
|
||||
"""Optimize queryset with select_related and prefetch_related."""
|
||||
qs = super().get_queryset(request)
|
||||
return qs.select_related('publisher').prefetch_related('tags')
|
||||
|
||||
fieldsets = (
|
||||
(
|
||||
None,
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
# Generated by Django 6.0.1 on 2026-01-18 13:42
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("bookshelf", "0031_alter_tocentry_authors_alter_tocentry_subtitle_and_more"),
|
||||
(
|
||||
"metadata",
|
||||
"0027_company_company_slug_idx_company_company_country_idx_and_more",
|
||||
),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddIndex(
|
||||
model_name="book",
|
||||
index=models.Index(fields=["title"], name="book_title_idx"),
|
||||
),
|
||||
migrations.AddIndex(
|
||||
model_name="catalog",
|
||||
index=models.Index(fields=["manufacturer"], name="catalog_mfr_idx"),
|
||||
),
|
||||
migrations.AddIndex(
|
||||
model_name="magazine",
|
||||
index=models.Index(fields=["published"], name="magazine_published_idx"),
|
||||
),
|
||||
migrations.AddIndex(
|
||||
model_name="magazine",
|
||||
index=models.Index(fields=["name"], name="magazine_name_idx"),
|
||||
),
|
||||
migrations.AddIndex(
|
||||
model_name="magazineissue",
|
||||
index=models.Index(fields=["magazine"], name="mag_issue_mag_idx"),
|
||||
),
|
||||
migrations.AddIndex(
|
||||
model_name="magazineissue",
|
||||
index=models.Index(
|
||||
fields=["publication_month"], name="mag_issue_pub_month_idx"
|
||||
),
|
||||
),
|
||||
]
|
||||
@@ -11,6 +11,7 @@ from django_countries.fields import CountryField
|
||||
|
||||
from ram.utils import DeduplicatedStorage
|
||||
from ram.models import BaseModel, Image, PropertyInstance
|
||||
from ram.managers import BookManager, CatalogManager, MagazineIssueManager
|
||||
from metadata.models import Scale, Manufacturer, Shop, Tag
|
||||
|
||||
|
||||
@@ -105,8 +106,16 @@ class Book(BaseBook):
|
||||
authors = models.ManyToManyField(Author, blank=True)
|
||||
publisher = models.ForeignKey(Publisher, on_delete=models.CASCADE)
|
||||
|
||||
objects = BookManager()
|
||||
|
||||
class Meta:
|
||||
ordering = ["title"]
|
||||
indexes = [
|
||||
# Index for title searches (local field)
|
||||
models.Index(fields=["title"], name="book_title_idx"),
|
||||
# Note: published and publication_year are inherited from BaseBook/BaseModel
|
||||
# and cannot be indexed here due to multi-table inheritance
|
||||
]
|
||||
|
||||
def __str__(self):
|
||||
return self.title
|
||||
@@ -134,8 +143,18 @@ class Catalog(BaseBook):
|
||||
years = models.CharField(max_length=12)
|
||||
scales = models.ManyToManyField(Scale, related_name="catalogs")
|
||||
|
||||
objects = CatalogManager()
|
||||
|
||||
class Meta:
|
||||
ordering = ["manufacturer", "publication_year"]
|
||||
indexes = [
|
||||
# Index for manufacturer filtering (local field)
|
||||
models.Index(
|
||||
fields=["manufacturer"], name="catalog_mfr_idx"
|
||||
),
|
||||
# Note: published and publication_year are inherited from BaseBook/BaseModel
|
||||
# and cannot be indexed here due to multi-table inheritance
|
||||
]
|
||||
|
||||
def __str__(self):
|
||||
# if the object is new, return an empty string to avoid
|
||||
@@ -184,6 +203,12 @@ class Magazine(BaseModel):
|
||||
|
||||
class Meta:
|
||||
ordering = [Lower("name")]
|
||||
indexes = [
|
||||
# Index for published filtering
|
||||
models.Index(fields=["published"], name="magazine_published_idx"),
|
||||
# Index for name searches (case-insensitive via db_collation if needed)
|
||||
models.Index(fields=["name"], name="magazine_name_idx"),
|
||||
]
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
@@ -214,6 +239,8 @@ class MagazineIssue(BaseBook):
|
||||
null=True, blank=True, choices=MONTHS.items()
|
||||
)
|
||||
|
||||
objects = MagazineIssueManager()
|
||||
|
||||
class Meta:
|
||||
unique_together = ("magazine", "issue_number")
|
||||
ordering = [
|
||||
@@ -222,6 +249,17 @@ class MagazineIssue(BaseBook):
|
||||
"publication_month",
|
||||
"issue_number",
|
||||
]
|
||||
indexes = [
|
||||
# Index for magazine filtering (local field)
|
||||
models.Index(fields=["magazine"], name="mag_issue_mag_idx"),
|
||||
# Index for publication month (local field)
|
||||
models.Index(
|
||||
fields=["publication_month"],
|
||||
name="mag_issue_pub_month_idx",
|
||||
),
|
||||
# Note: published and publication_year are inherited from BaseBook/BaseModel
|
||||
# and cannot be indexed here due to multi-table inheritance
|
||||
]
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.magazine.name} - {self.issue_number}"
|
||||
|
||||
Reference in New Issue
Block a user