Merge branch 'master' into 'Javascript-continious-upload-translate'

# Conflicts:
#   photo21/settings.py
This commit is contained in:
loulous27 2025-11-23 15:31:56 +01:00
commit 7a0bf9485b
5 changed files with 77 additions and 13 deletions

View 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",)

View file

@ -37,6 +37,11 @@ ALLOWED_HOSTS = [
"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 = [
("admin", "photos-admin@lists.crans.org"),
@ -68,9 +73,12 @@ INSTALLED_APPS = [
"allauth_note_kfet",
"crispy_forms",
"photologue",
"photo21"
"photo21",
]
if DEBUG:
INSTALLED_APPS += ["debug_toolbar",] # For debug and optimisations
MIDDLEWARE = [
"django.middleware.security.SecurityMiddleware",
"django.contrib.sessions.middleware.SessionMiddleware",
@ -81,8 +89,10 @@ MIDDLEWARE = [
"django.middleware.clickjacking.XFrameOptionsMiddleware",
"django.middleware.locale.LocaleMiddleware",
"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"
@ -122,6 +132,13 @@ DATABASES = {
}
}
CACHES = {
"default": {
"BACKEND": "django.core.cache.backends.locmem.LocMemCache",
"LOCATION": "Master",
}
}
# Password validation
# https://docs.djangoproject.com/en/2.2/ref/settings/#auth-password-validators

View file

@ -14,6 +14,9 @@ from django.contrib import admin
from django.urls import include, path, re_path
from django.views.i18n import JavaScriptCatalog
if settings.DEBUG :
from debug_toolbar.toolbar import debug_toolbar_urls
from .views import IndexView, MediaAccess
urlpatterns = [
@ -29,6 +32,7 @@ urlpatterns = [
# In production media are served through NGINX with X-Accel-Redirect
if settings.DEBUG:
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
urlpatterns += debug_toolbar_urls()
else:
urlpatterns.append(
re_path("^media/(?P<path>.*)", MediaAccess.as_view(), name="media")

View file

@ -3,7 +3,6 @@
import logging
import os
import random
import unicodedata
from datetime import datetime
from functools import partial
@ -16,6 +15,7 @@ from django.conf import settings
from django.core.exceptions import ValidationError
from django.core.files.base import ContentFile
from django.core.validators import RegexValidator
from django.core.cache import caches
from django.db import models
from django.template.defaultfilters import slugify
from django.urls import reverse
@ -25,6 +25,8 @@ from django.utils.timezone import now
from django.utils.translation import gettext_lazy as _
from PIL import Image, ImageFile, ImageFilter
logger = logging.getLogger("photologue.models")
# Default limit for gallery.latest
@ -184,13 +186,15 @@ class Gallery(models.Model):
def sample(self, public=True):
"""Return a sample of photos, ordered at random."""
count = 1
if count > self.photo_count():
count = self.photo_count()
nb = self.photo_count(public) #Optimisation don't do twice the SQL requests
if nb < count:
count = nb
if public:
photo_set = self.photos.filter(is_public=True)
else:
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):
"""Return a count of all the photos in this gallery."""
@ -721,10 +725,16 @@ class PhotoSizeCache:
def __init__(self):
self.__dict__ = self.__state
if not len(self.sizes):
sizes = PhotoSize.objects.all()
for size in sizes:
self.sizes[size.name] = size
cached = caches.get("PhotoSizeCache",None)
if cached is None :
if not len(self.sizes):
sizes = PhotoSize.objects.all()
for size in sizes:
self.sizes[size.name] = size
caches.set("PhotoSizeCache",self)
else :
self = cached
def reset(self):
global size_method_map

View file

@ -20,10 +20,16 @@ from django.views.generic.dates import ArchiveIndexView, YearArchiveView
from django.views.generic.detail import DetailView
from django.views.generic.edit import DeleteView, FormView
from PIL import Image
from django.contrib.auth import get_user_model
from .forms import UploadForm
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):
model = Gallery
@ -135,11 +141,11 @@ class GalleryDetailView(LoginRequiredMixin, DetailView):
def get_context_data(self, **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:
context["photos"] = self.object.photos.all()
context["photos"] = self.object.photos.all().select_related('owner')
else:
context["photos"] = self.object.photos.filter(is_public=True)
context["photos"] = self.object.photos.filter(is_public=True).select_related('onwer')
# List owners
context["owners"] = []
@ -147,6 +153,8 @@ class GalleryDetailView(LoginRequiredMixin, DetailView):
if photo.owner not in context["owners"]:
context["owners"].append(photo.owner)
# Filter on owner
if "owner" in self.kwargs:
context["photos"] = context["photos"].filter(owner__id=self.kwargs["owner"])