Add likes, update templates

This commit is contained in:
Nyymix 2025-01-15 20:31:41 +02:00
parent 89134993ad
commit f3a94857d0
8 changed files with 109 additions and 16 deletions

View file

@ -1,4 +1,5 @@
from django.contrib import admin from django.contrib import admin
from django.utils.html import format_html
from imagekit import ImageSpec from imagekit import ImageSpec
from imagekit.admin import AdminThumbnail from imagekit.admin import AdminThumbnail
from imagekit.cachefiles import ImageCacheFile from imagekit.cachefiles import ImageCacheFile
@ -36,16 +37,34 @@ class LocationAdmin(admin.ModelAdmin):
class AlbumAdmin(admin.ModelAdmin): class AlbumAdmin(admin.ModelAdmin):
prepopulated_fields = {'slug': ('name',)} prepopulated_fields = {'slug': ('name',)}
list_display = ('__str__', 'location', 'album_date', 'is_public', ) list_display = ('__str__', 'location', 'album_date', 'is_public', 'thumbnail', )
search_fields = ('name',) search_fields = ('name',)
ordering = ('name',) ordering = ('name',)
list_per_page = 30 list_per_page = 30
list_editable = ('is_public', 'location') list_editable = ('is_public', 'location')
def formfield_for_foreignkey(self, db_field, request, **kwargs):
if db_field.name == "cover":
if hasattr(request, 'resolver_match') and request.resolver_match.kwargs.get('object_id'):
album_id = request.resolver_match.kwargs['object_id']
kwargs["queryset"] = Photo.objects.filter(album_id=album_id)
return super().formfield_for_foreignkey(db_field, request, **kwargs)
def thumbnail(self, obj):
if obj.cover and obj.cover.photo:
return format_html(
'<img src="{}" style="width: 50px; height: 50px; object-fit: cover;"/>',
obj.cover.photo.url,
)
return "-"
thumbnail.short_description = "Thumbnail"
class PhotoAdmin(admin.ModelAdmin): class PhotoAdmin(admin.ModelAdmin):
list_display = ('slug', 'album', 'admin_thumbnail',) list_display = ('slug', 'album', 'admin_thumbnail',)
list_display_links = ('slug',) list_display_links = ('slug',)
search_fields = ('slug',)
readonly_fields = ['slug', 'taken_at', 'height', 'width', 'exif', ] readonly_fields = ['slug', 'taken_at', 'height', 'width', 'exif', ]
admin_thumbnail = AdminThumbnail(image_field=cached_admin_thumb) admin_thumbnail = AdminThumbnail(image_field=cached_admin_thumb)

View file

@ -1,4 +1,4 @@
# Generated by Django 5.1.4 on 2025-01-13 20:45 # Generated by Django 5.1.4 on 2025-01-15 18:22
import datetime import datetime
import django.db.models.deletion import django.db.models.deletion
@ -43,7 +43,6 @@ class Migration(migrations.Migration):
('name', models.CharField(max_length=150, unique=True, verbose_name='Album')), ('name', models.CharField(max_length=150, unique=True, verbose_name='Album')),
('slug', models.SlugField(max_length=150, unique=True, verbose_name='Slug')), ('slug', models.SlugField(max_length=150, unique=True, verbose_name='Slug')),
('album_date', models.DateField(default=datetime.datetime.now, verbose_name='Album Date')), ('album_date', models.DateField(default=datetime.datetime.now, verbose_name='Album Date')),
('cover', models.ImageField(blank=True, null=True, upload_to='covers/', verbose_name='Album Cover')),
('is_public', models.BooleanField(default=False, verbose_name='Published')), ('is_public', models.BooleanField(default=False, verbose_name='Published')),
('location', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='albums', to='gallery.location', verbose_name='Location')), ('location', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='albums', to='gallery.location', verbose_name='Location')),
], ],
@ -67,4 +66,9 @@ class Migration(migrations.Migration):
('album', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='photos', to='gallery.album', verbose_name='Album')), ('album', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='photos', to='gallery.album', verbose_name='Album')),
], ],
), ),
migrations.AddField(
model_name='album',
name='cover',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='cover_to', to='gallery.photo', verbose_name='Album cover'),
),
] ]

View file

@ -1,23 +1,35 @@
from datetime import datetime from datetime import datetime
from django.db import models from django.db import models
from django.templatetags.static import static
from django.urls import reverse from django.urls import reverse
from django.utils.text import slugify from django.utils.text import slugify
from gallery.models.location import Location from gallery.models.location import Location
#from gallery.models.photo import Photo
class Album(models.Model): class Album(models.Model):
name = models.CharField(max_length=150, unique=True, verbose_name="Album") name = models.CharField(max_length=150, unique=True, verbose_name="Album")
slug = models.SlugField(max_length=150, unique=True, verbose_name="Slug") slug = models.SlugField(max_length=150, unique=True, verbose_name="Slug")
location = models.ForeignKey(Location, blank=True, null=True, on_delete=models.SET_NULL, related_name='albums', verbose_name="Location") location = models.ForeignKey(Location, blank=True, null=True, on_delete=models.SET_NULL, related_name='albums', verbose_name="Location")
album_date = models.DateField(default=datetime.now, verbose_name="Album Date") album_date = models.DateField(default=datetime.now, verbose_name="Album Date")
cover = models.ImageField(upload_to="covers/", blank=True, null=True, verbose_name="Album Cover") cover = models.ForeignKey("Photo", blank=True, null=True, on_delete=models.SET_NULL, related_name='cover_to', verbose_name="Album cover")
is_public = models.BooleanField(default=False, verbose_name="Published") is_public = models.BooleanField(default=False, verbose_name="Published")
@property @property
def photos_in_album(self): def photos_in_album(self):
return self.photos.count() return self.photos.count()
@property
def cover_url(self):
if self.cover:
return self.cover.photo.url
random_cover = self.photos.order_by('-width').first()
if random_cover:
return random_cover.photo.url
return static('img/placeholder.png')
def save(self, *args, **kwargs): def save(self, *args, **kwargs):
if not self.slug: if not self.slug:

View file

@ -43,6 +43,13 @@ class Photo(models.Model):
self.views += 1 self.views += 1
self.save() self.save()
def get_next(self):
return self.__class__.objects.filter(taken_at__gt=self.taken_at, album=self.album.id).order_by('taken_at').first()
def get_prev(self):
return self.__class__.objects.filter(taken_at__lt=self.taken_at, album=self.album.id).order_by('-taken_at').first()
def save(self, *args, **kwargs): def save(self, *args, **kwargs):
self.exif_data = Exif(self.photo.path) self.exif_data = Exif(self.photo.path)
datetime_taken = getattr(self.exif_data, 'datetimeoriginal', datetime.now)() datetime_taken = getattr(self.exif_data, 'datetimeoriginal', datetime.now)()

View file

@ -1,4 +1,5 @@
{% extends "base.html" %} {% extends "base.html" %}
{% load static %}
<!-- Title --> <!-- Title -->
{% block title %} Gallery : Albums {% endblock %} {% block title %} Gallery : Albums {% endblock %}
@ -18,7 +19,7 @@
<div class="uk-card uk-card-default"> <div class="uk-card uk-card-default">
<div class="uk-card-media-top"> <div class="uk-card-media-top">
<a href="{{ album.get_absolute_url }}"> <a href="{{ album.get_absolute_url }}">
<img src="{{ album.cover.url }}" width="1800" height="1200" alt=""> <img src="{{ album.cover_url }}" width="1800" height="1200" alt="">
</a> </a>
</div> </div>
<div class="uk-overlay uk-overlay-primary uk-position-bottom uk-padding-small"> <div class="uk-overlay uk-overlay-primary uk-position-bottom uk-padding-small">

View file

@ -14,8 +14,37 @@
<!-- Content --> <!-- Content -->
{% block content %} {% block content %}
<h1>{{ photo.slug }}</h1> <div uk-grid>
<p> Views: {{ photo.views }}</p> <div class="uk-width-1-1 uk-width-3-4@m">
<img src="{{ photo.photo.url }}" alt="{{ photo.slug }}" class="height='100%'" /> <div uk-lightbox >
<a href="{{ photo.photo.url }}" data-alt="{{ photo.slug }}">
<img src="{{ photo.photo.url }}" alt="{{ photo.slug }}" class="height='100%'" />
</a>
</div>
</div>
<div class="uk-margin-top uk-width-1-4@m uk-visible@m">
{% if prev %}
<a href="{% url 'gallery:photo_url' photo.album.slug prev.slug %}" uk-slidenav-previous>&laquo; Prev</a>
{% endif %}
{% if next %}
<a href="{% url 'gallery:photo_url' photo.album.slug next.slug %}" uk-slidenav-next>Next &raquo;</a>
{% endif %}
<p> Views: {{ photo.views }}</p>
<p> Likes: {{ photo.likes }}</p>
<p> Taken: {{ photo.taken_at }} </p>
<p> Favorite: {{ photo.favorite }}</p>
<a href="{{ photo.photo.url }}">Download {{ photo.width }}x{{ photo.height }}</a>
<form action="{% url 'gallery:photo_url' photo.album.slug photo.slug %}" method="POST" class="uk-form">
{% csrf_token %}
<button type="submit" name="like" value="true" class="uk-button uk-button-primary">
<span uk-icon="icon: heart"></span> Like
</button>
</form>
</div>
</div>
{% endblock %} {% endblock %}

View file

@ -46,18 +46,39 @@ class PhotosList(ListView):
paginate_by = 30 paginate_by = 30
ordering = ['-taken_at'] ordering = ['-taken_at']
class PhotoDetail(DetailView): class PhotoDetail(DetailView):
model = Photo model = Photo
slug_url_kwarg = 'photo_slug' slug_url_kwarg = 'photo_slug'
template_name = 'gallery/photo_detail.html' template_name = 'gallery/photo_detail.html'
def get_object(self, queryset=None): def get_object(self, queryset=None):
photo = get_object_or_404(Photo, slug=self.kwargs.get(self.slug_url_kwarg)) album_slug = self.kwargs.get('album_slug')
photo_slug = self.kwargs.get('photo_slug')
photo_key = f'photo_{photo.slug}' photo = get_object_or_404(Photo, slug=photo_slug, album__slug=album_slug)
if photo_key not in self.request.session:
photo.add_view() if photo.slug not in self.request.session:
self.request.session[photo_key] = 0 photo.add_view()
self.request.session[photo.slug] = 0
return photo return photo
def get_context_data(self, *args, **kwargs):
context = super().get_context_data(*args, **kwargs)
context["next"] = self.object.get_next()
context["prev"] = self.object.get_prev()
return context
def post(self, request, *args, **kwargs):
photo = self.get_object()
if request.POST.get("like") == "true":
if self.request.session.get(photo.slug) == 0:
photo.add_like()
self.request.session[photo.slug] = 1
if request.user.is_authenticated:
photo.is_favorite = True
photo.save()
return redirect('gallery:photo_url', album_slug=self.kwargs['album_slug'], photo_slug=self.kwargs['photo_slug'])

BIN
static/img/placeholder.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6 KiB