Caches é SQL optimisations
This commit is contained in:
parent
213644d0af
commit
f1673da45f
5 changed files with 69 additions and 14 deletions
25
Scripts/small_pictures_gen.py
Normal file
25
Scripts/small_pictures_gen.py
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
"""A generator of small picture to test very larges galeries"""
|
||||||
|
|
||||||
|
from PIL import Image
|
||||||
|
from PIL import ImageDraw
|
||||||
|
import argparse
|
||||||
|
|
||||||
|
|
||||||
|
parser = argparse.ArgumentParser(
|
||||||
|
description="A generator of small picture to test very larges galeries"
|
||||||
|
)
|
||||||
|
|
||||||
|
parser.add_argument("count", help="Numbers of photo to generate", type=int)
|
||||||
|
parser.add_argument(
|
||||||
|
"-outputfolder", help="The outputfolders by default : ./photos/", default="photos/"
|
||||||
|
)
|
||||||
|
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
for i in range(args.count):
|
||||||
|
if (100//5 * (i + 1)) % args.count == 0: # affichage tout les 5%
|
||||||
|
print(f"Image {i+1} : {(i+1)/args.count:.0%}")
|
||||||
|
|
||||||
|
img = Image.new(mode="RGB",size=(100,100),color=(0,0,0))
|
||||||
|
ImageDraw.Draw(img).text((0,0),str(i+1),(255,255,255))
|
||||||
|
img.save(args.outputfolder+f"img_{i+1}.jpg",)
|
||||||
|
|
@ -28,7 +28,7 @@ BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||||
SECRET_KEY = "CHANGE ME"
|
SECRET_KEY = "CHANGE ME"
|
||||||
|
|
||||||
# SECURITY WARNING: don't run with debug turned on in production!
|
# SECURITY WARNING: don't run with debug turned on in production!
|
||||||
DEBUG = False
|
DEBUG = True
|
||||||
|
|
||||||
ALLOWED_HOSTS = [
|
ALLOWED_HOSTS = [
|
||||||
"127.0.0.1",
|
"127.0.0.1",
|
||||||
|
|
@ -37,6 +37,11 @@ ALLOWED_HOSTS = [
|
||||||
"photos-dev.crans.org",
|
"photos-dev.crans.org",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
INTERNAL_IPS = [
|
||||||
|
"127.0.0.1",
|
||||||
|
"localhost",
|
||||||
|
]
|
||||||
|
|
||||||
# Admins receive server errors, this is useful to be notified of potential bugs
|
# Admins receive server errors, this is useful to be notified of potential bugs
|
||||||
ADMINS = [
|
ADMINS = [
|
||||||
("admin", "photos-admin@lists.crans.org"),
|
("admin", "photos-admin@lists.crans.org"),
|
||||||
|
|
@ -68,9 +73,12 @@ INSTALLED_APPS = [
|
||||||
"allauth_note_kfet",
|
"allauth_note_kfet",
|
||||||
"crispy_forms",
|
"crispy_forms",
|
||||||
"photologue",
|
"photologue",
|
||||||
"photo21"
|
"photo21",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
if DEBUG:
|
||||||
|
INSTALLED_APPS += ["debug_toolbar",] # For debug and optimisations
|
||||||
|
|
||||||
MIDDLEWARE = [
|
MIDDLEWARE = [
|
||||||
"django.middleware.security.SecurityMiddleware",
|
"django.middleware.security.SecurityMiddleware",
|
||||||
"django.contrib.sessions.middleware.SessionMiddleware",
|
"django.contrib.sessions.middleware.SessionMiddleware",
|
||||||
|
|
@ -81,8 +89,10 @@ MIDDLEWARE = [
|
||||||
"django.middleware.clickjacking.XFrameOptionsMiddleware",
|
"django.middleware.clickjacking.XFrameOptionsMiddleware",
|
||||||
"django.middleware.locale.LocaleMiddleware",
|
"django.middleware.locale.LocaleMiddleware",
|
||||||
"django.contrib.sites.middleware.CurrentSiteMiddleware",
|
"django.contrib.sites.middleware.CurrentSiteMiddleware",
|
||||||
"allauth.account.middleware.AccountMiddleware",
|
"allauth.account.middleware.AccountMiddleware", # For the django =< 5.0
|
||||||
]
|
]
|
||||||
|
if DEBUG :
|
||||||
|
MIDDLEWARE += ["debug_toolbar.middleware.DebugToolbarMiddleware",]
|
||||||
|
|
||||||
ROOT_URLCONF = "photo21.urls"
|
ROOT_URLCONF = "photo21.urls"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@ from django.conf import settings
|
||||||
from django.conf.urls.static import static
|
from django.conf.urls.static import static
|
||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
from django.urls import include, path, re_path
|
from django.urls import include, path, re_path
|
||||||
|
from debug_toolbar.toolbar import debug_toolbar_urls
|
||||||
|
|
||||||
from .views import IndexView, MediaAccess
|
from .views import IndexView, MediaAccess
|
||||||
|
|
||||||
|
|
@ -27,6 +28,7 @@ urlpatterns = [
|
||||||
# In production media are served through NGINX with X-Accel-Redirect
|
# In production media are served through NGINX with X-Accel-Redirect
|
||||||
if settings.DEBUG:
|
if settings.DEBUG:
|
||||||
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
|
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
|
||||||
|
urlpatterns += debug_toolbar_urls()
|
||||||
else:
|
else:
|
||||||
urlpatterns.append(
|
urlpatterns.append(
|
||||||
re_path("^media/(?P<path>.*)", MediaAccess.as_view(), name="media")
|
re_path("^media/(?P<path>.*)", MediaAccess.as_view(), name="media")
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,6 @@
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
import random
|
|
||||||
import unicodedata
|
import unicodedata
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from functools import partial
|
from functools import partial
|
||||||
|
|
@ -16,6 +15,7 @@ from django.conf import settings
|
||||||
from django.core.exceptions import ValidationError
|
from django.core.exceptions import ValidationError
|
||||||
from django.core.files.base import ContentFile
|
from django.core.files.base import ContentFile
|
||||||
from django.core.validators import RegexValidator
|
from django.core.validators import RegexValidator
|
||||||
|
from django.core.cache import caches
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.template.defaultfilters import slugify
|
from django.template.defaultfilters import slugify
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
|
|
@ -25,6 +25,8 @@ from django.utils.timezone import now
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
from PIL import Image, ImageFile, ImageFilter
|
from PIL import Image, ImageFile, ImageFilter
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
logger = logging.getLogger("photologue.models")
|
logger = logging.getLogger("photologue.models")
|
||||||
|
|
||||||
# Default limit for gallery.latest
|
# Default limit for gallery.latest
|
||||||
|
|
@ -184,13 +186,15 @@ class Gallery(models.Model):
|
||||||
def sample(self, public=True):
|
def sample(self, public=True):
|
||||||
"""Return a sample of photos, ordered at random."""
|
"""Return a sample of photos, ordered at random."""
|
||||||
count = 1
|
count = 1
|
||||||
if count > self.photo_count():
|
nb = self.photo_count(public) #Optimisation don't do twice the SQL requests
|
||||||
count = self.photo_count()
|
if nb < count:
|
||||||
|
count = nb
|
||||||
|
|
||||||
if public:
|
if public:
|
||||||
photo_set = self.photos.filter(is_public=True)
|
photo_set = self.photos.filter(is_public=True)
|
||||||
else:
|
else:
|
||||||
photo_set = self.photos
|
photo_set = self.photos
|
||||||
return random.sample(list(photo_set), count)
|
return photo_set.order_by("?")[:count] # Use native SQL random
|
||||||
|
|
||||||
def photo_count(self, public=True):
|
def photo_count(self, public=True):
|
||||||
"""Return a count of all the photos in this gallery."""
|
"""Return a count of all the photos in this gallery."""
|
||||||
|
|
@ -721,10 +725,16 @@ class PhotoSizeCache:
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.__dict__ = self.__state
|
self.__dict__ = self.__state
|
||||||
|
|
||||||
|
cached = caches.get("PhotoSizeCache",None)
|
||||||
|
if cached is None :
|
||||||
if not len(self.sizes):
|
if not len(self.sizes):
|
||||||
sizes = PhotoSize.objects.all()
|
sizes = PhotoSize.objects.all()
|
||||||
for size in sizes:
|
for size in sizes:
|
||||||
self.sizes[size.name] = size
|
self.sizes[size.name] = size
|
||||||
|
caches.set("PhotoSizeCache",self)
|
||||||
|
else :
|
||||||
|
self = cached
|
||||||
|
|
||||||
def reset(self):
|
def reset(self):
|
||||||
global size_method_map
|
global size_method_map
|
||||||
|
|
|
||||||
|
|
@ -20,10 +20,16 @@ from django.views.generic.dates import ArchiveIndexView, YearArchiveView
|
||||||
from django.views.generic.detail import DetailView
|
from django.views.generic.detail import DetailView
|
||||||
from django.views.generic.edit import DeleteView, FormView
|
from django.views.generic.edit import DeleteView, FormView
|
||||||
from PIL import Image
|
from PIL import Image
|
||||||
|
from django.contrib.auth import get_user_model
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
from .forms import UploadForm
|
from .forms import UploadForm
|
||||||
from .models import Gallery, Photo, Tag
|
from .models import Gallery, Photo, Tag
|
||||||
|
|
||||||
|
# Cette ligne renvoie le modèle d'utilisateur actif (le natif ou le vôtre)
|
||||||
|
User = get_user_model()
|
||||||
|
|
||||||
|
|
||||||
class GalleryDateView(LoginRequiredMixin):
|
class GalleryDateView(LoginRequiredMixin):
|
||||||
model = Gallery
|
model = Gallery
|
||||||
|
|
@ -135,11 +141,11 @@ class GalleryDetailView(LoginRequiredMixin, DetailView):
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
context = super().get_context_data(**kwargs)
|
context = super().get_context_data(**kwargs)
|
||||||
|
|
||||||
# Non-staff members only see public photos
|
# Non-staff members only see public photos + prefetch all owners informations (Optimisation)
|
||||||
if self.request.user.is_staff:
|
if self.request.user.is_staff:
|
||||||
context["photos"] = self.object.photos.all()
|
context["photos"] = self.object.photos.all().select_related('owner')
|
||||||
else:
|
else:
|
||||||
context["photos"] = self.object.photos.filter(is_public=True)
|
context["photos"] = self.object.photos.filter(is_public=True).select_related('onwer')
|
||||||
|
|
||||||
# List owners
|
# List owners
|
||||||
context["owners"] = []
|
context["owners"] = []
|
||||||
|
|
@ -147,6 +153,8 @@ class GalleryDetailView(LoginRequiredMixin, DetailView):
|
||||||
if photo.owner not in context["owners"]:
|
if photo.owner not in context["owners"]:
|
||||||
context["owners"].append(photo.owner)
|
context["owners"].append(photo.owner)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Filter on owner
|
# Filter on owner
|
||||||
if "owner" in self.kwargs:
|
if "owner" in self.kwargs:
|
||||||
context["photos"] = context["photos"].filter(owner__id=self.kwargs["owner"])
|
context["photos"] = context["photos"].filter(owner__id=self.kwargs["owner"])
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue