mirror of
https://github.com/Alexander-D-Karpov/akarpov
synced 2024-11-25 03:33:45 +03:00
created image gallery
This commit is contained in:
parent
716f798ce1
commit
0d45e5bac2
|
@ -1,6 +1,17 @@
|
|||
from django.contrib.auth.mixins import LoginRequiredMixin, UserPassesTestMixin
|
||||
from django.views.generic.detail import SingleObjectMixin
|
||||
|
||||
|
||||
class SuperUserRequiredMixin(LoginRequiredMixin, UserPassesTestMixin):
|
||||
def test_func(self):
|
||||
return self.request.user.is_superuser
|
||||
|
||||
|
||||
class HasPermissions(SingleObjectMixin):
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
has_perm = False
|
||||
if self.request.user.is_authentificated:
|
||||
has_perm = self.object.user == self.request.user
|
||||
context["has_permissions"] = has_perm
|
||||
return context
|
||||
|
|
0
akarpov/gallery/__init__.py
Normal file
0
akarpov/gallery/__init__.py
Normal file
6
akarpov/gallery/admin.py
Normal file
6
akarpov/gallery/admin.py
Normal file
|
@ -0,0 +1,6 @@
|
|||
from django.contrib import admin
|
||||
|
||||
from akarpov.gallery.models import Collection, Image
|
||||
|
||||
admin.site.register(Collection)
|
||||
admin.site.register(Image)
|
12
akarpov/gallery/apps.py
Normal file
12
akarpov/gallery/apps.py
Normal file
|
@ -0,0 +1,12 @@
|
|||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class GalleryConfig(AppConfig):
|
||||
name = "akarpov.gallery"
|
||||
verbose_name = "Gallery"
|
||||
|
||||
def ready(self):
|
||||
try:
|
||||
import akarpov.gallery.signals # noqa F401
|
||||
except ImportError:
|
||||
pass
|
134
akarpov/gallery/migrations/0001_initial.py
Normal file
134
akarpov/gallery/migrations/0001_initial.py
Normal file
|
@ -0,0 +1,134 @@
|
|||
# Generated by Django 4.2 on 2023-04-29 08:45
|
||||
|
||||
import akarpov.utils.files
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
import django_extensions.db.fields
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
("shortener", "0001_initial"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name="Collection",
|
||||
fields=[
|
||||
(
|
||||
"id",
|
||||
models.BigAutoField(
|
||||
auto_created=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
verbose_name="ID",
|
||||
),
|
||||
),
|
||||
("slug", models.SlugField(blank=True, max_length=20, unique=True)),
|
||||
(
|
||||
"created",
|
||||
django_extensions.db.fields.CreationDateTimeField(
|
||||
auto_now_add=True, verbose_name="created"
|
||||
),
|
||||
),
|
||||
(
|
||||
"modified",
|
||||
django_extensions.db.fields.ModificationDateTimeField(
|
||||
auto_now=True, verbose_name="modified"
|
||||
),
|
||||
),
|
||||
("name", models.CharField(blank=True, max_length=250)),
|
||||
("description", models.TextField()),
|
||||
("public", models.BooleanField(default=False)),
|
||||
(
|
||||
"short_link",
|
||||
models.ForeignKey(
|
||||
blank=True,
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.SET_NULL,
|
||||
to="shortener.link",
|
||||
),
|
||||
),
|
||||
(
|
||||
"user",
|
||||
models.ForeignKey(
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="collections",
|
||||
to=settings.AUTH_USER_MODEL,
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"get_latest_by": "modified",
|
||||
"abstract": False,
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="Image",
|
||||
fields=[
|
||||
(
|
||||
"id",
|
||||
models.BigAutoField(
|
||||
auto_created=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
verbose_name="ID",
|
||||
),
|
||||
),
|
||||
("image_cropped", models.ImageField(blank=True, upload_to="cropped/")),
|
||||
("slug", models.SlugField(blank=True, max_length=20, unique=True)),
|
||||
(
|
||||
"created",
|
||||
django_extensions.db.fields.CreationDateTimeField(
|
||||
auto_now_add=True, verbose_name="created"
|
||||
),
|
||||
),
|
||||
(
|
||||
"modified",
|
||||
django_extensions.db.fields.ModificationDateTimeField(
|
||||
auto_now=True, verbose_name="modified"
|
||||
),
|
||||
),
|
||||
(
|
||||
"image",
|
||||
models.ImageField(
|
||||
upload_to=akarpov.utils.files.user_file_upload_mixin
|
||||
),
|
||||
),
|
||||
(
|
||||
"collection",
|
||||
models.ForeignKey(
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="images",
|
||||
to="gallery.collection",
|
||||
),
|
||||
),
|
||||
(
|
||||
"short_link",
|
||||
models.ForeignKey(
|
||||
blank=True,
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.SET_NULL,
|
||||
to="shortener.link",
|
||||
),
|
||||
),
|
||||
(
|
||||
"user",
|
||||
models.ForeignKey(
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="images",
|
||||
to=settings.AUTH_USER_MODEL,
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"get_latest_by": "modified",
|
||||
"abstract": False,
|
||||
},
|
||||
),
|
||||
]
|
0
akarpov/gallery/migrations/__init__.py
Normal file
0
akarpov/gallery/migrations/__init__.py
Normal file
38
akarpov/gallery/models.py
Normal file
38
akarpov/gallery/models.py
Normal file
|
@ -0,0 +1,38 @@
|
|||
from django.db import models
|
||||
from django.urls import reverse
|
||||
from django_extensions.db.models import TimeStampedModel
|
||||
|
||||
from akarpov.common.models import BaseImageModel
|
||||
from akarpov.tools.shortener.models import ShortLink
|
||||
from akarpov.utils.files import user_file_upload_mixin
|
||||
|
||||
|
||||
class Collection(TimeStampedModel, ShortLink):
|
||||
name = models.CharField(max_length=250, blank=True)
|
||||
description = models.TextField()
|
||||
public = models.BooleanField(default=False)
|
||||
user = models.ForeignKey(
|
||||
"users.User", related_name="collections", on_delete=models.CASCADE
|
||||
)
|
||||
|
||||
def get_absolute_url(self):
|
||||
return reverse("gallery:collection", kwargs={"slug": self.slug})
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
|
||||
class Image(TimeStampedModel, ShortLink, BaseImageModel):
|
||||
collection = models.ForeignKey(
|
||||
"Collection", related_name="images", on_delete=models.CASCADE
|
||||
)
|
||||
user = models.ForeignKey(
|
||||
"users.User", related_name="images", on_delete=models.CASCADE
|
||||
)
|
||||
image = models.ImageField(upload_to=user_file_upload_mixin, blank=False, null=False)
|
||||
|
||||
def get_absolute_url(self):
|
||||
return reverse("gallery:view", kwargs={"slug": self.slug})
|
||||
|
||||
def __str__(self):
|
||||
return self.image.name
|
10
akarpov/gallery/urls.py
Normal file
10
akarpov/gallery/urls.py
Normal file
|
@ -0,0 +1,10 @@
|
|||
from django.urls import path
|
||||
|
||||
from akarpov.gallery.views import collection_view, image_view, list_collections_view
|
||||
|
||||
app_name = "gallery"
|
||||
urlpatterns = [
|
||||
path("", list_collections_view, name="list"),
|
||||
path("<str:slug>", collection_view, name="collection"),
|
||||
path("image/<str:slug>", image_view, name="view"),
|
||||
]
|
33
akarpov/gallery/views.py
Normal file
33
akarpov/gallery/views.py
Normal file
|
@ -0,0 +1,33 @@
|
|||
from django.views import generic
|
||||
|
||||
from akarpov.common.views import HasPermissions
|
||||
from akarpov.gallery.models import Collection
|
||||
|
||||
|
||||
class ListCollectionsView(generic.ListView):
|
||||
model = Collection
|
||||
template_name = "gallery/list.html"
|
||||
|
||||
def get_queryset(self):
|
||||
if self.request.user.is_authenticated:
|
||||
return self.request.user.collections.all()
|
||||
return Collection.objects.filter(public=True)
|
||||
|
||||
|
||||
list_collections_view = ListCollectionsView.as_view()
|
||||
|
||||
|
||||
class CollectionView(generic.DetailView, HasPermissions):
|
||||
model = Collection
|
||||
template_name = "gallery/collection.html"
|
||||
|
||||
|
||||
collection_view = CollectionView.as_view()
|
||||
|
||||
|
||||
class ImageView(generic.DetailView, HasPermissions):
|
||||
model = Collection
|
||||
template_name = "gallery/image.html"
|
||||
|
||||
|
||||
image_view = ImageView.as_view()
|
1
akarpov/templates/gallery/collection.html
Normal file
1
akarpov/templates/gallery/collection.html
Normal file
|
@ -0,0 +1 @@
|
|||
{% extends 'base.html' %}
|
1
akarpov/templates/gallery/image.html
Normal file
1
akarpov/templates/gallery/image.html
Normal file
|
@ -0,0 +1 @@
|
|||
{% extends 'base.html' %}
|
1
akarpov/templates/gallery/list.html
Normal file
1
akarpov/templates/gallery/list.html
Normal file
|
@ -0,0 +1 @@
|
|||
{% extends 'base.html' %}
|
|
@ -1,29 +0,0 @@
|
|||
{% load markdown_extras %}
|
||||
|
||||
{% block content %}
|
||||
<br>
|
||||
<a class="mx-5" style="text-decoration: none; color: black" href="{% url "about" %}#projects"><i class="bi-arrow-left"></i> back to all projects</a>
|
||||
<div class="row m-5 mb-5 g-1 row-cols-1 row-cols-md-2">
|
||||
<div class="col">
|
||||
<img class="img-fluid" src="{{ project.image.url }}" alt=""/>
|
||||
</div>
|
||||
<div class="col text-center d-flex row align-items-center">
|
||||
<div class="align-items-center m-3">
|
||||
<div class="align-self-center">
|
||||
<h1 class="fs-2">{{ project.name }}</h1>
|
||||
<p class="lead">{{ project.md | markdown | safe }}</p>
|
||||
<p>{{ project.description }}</p>
|
||||
<p>Created: {{ project.created|date:"d M Y" }}</p>
|
||||
<p>
|
||||
{% if project.source_link %}
|
||||
<a style="text-decoration: none; color: black" class="m-2" href="{{ project.source_link }}"><i class="bi bi-file-earmark-code"></i> Source code</a>
|
||||
{% endif %}
|
||||
{% if project.view_link %}
|
||||
<a style="text-decoration: none; color: black" class="m-2" href="{{ project.view_link }}"><i class="bi bi-box-arrow-up-right"></i> View project</a>
|
||||
{% endif %}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
|
@ -11,7 +11,7 @@ class ShortLinkCreateView(CreateView):
|
|||
model = Link
|
||||
form_class = LinkForm
|
||||
|
||||
template_name = "shortener/create.html"
|
||||
template_name = "tools/shortener/create.html"
|
||||
|
||||
def form_valid(self, form):
|
||||
if self.request.user.is_authenticated:
|
||||
|
@ -24,7 +24,7 @@ def form_valid(self, form):
|
|||
|
||||
class LinkDetailView(DetailView):
|
||||
|
||||
template_name = "shortener/view.html"
|
||||
template_name = "tools/shortener/view.html"
|
||||
|
||||
def get_object(self, *args, **kwargs):
|
||||
link = get_link_from_slug(self.kwargs["slug"])
|
||||
|
@ -39,7 +39,7 @@ def get_object(self, *args, **kwargs):
|
|||
|
||||
|
||||
class LinkRevokedView(TemplateView):
|
||||
template_name = "shortener/revoked.html"
|
||||
template_name = "tools/shortener/revoked.html"
|
||||
|
||||
|
||||
link_revoked_view = LinkRevokedView.as_view()
|
||||
|
|
|
@ -136,7 +136,7 @@
|
|||
"health_check.contrib.redis",
|
||||
]
|
||||
|
||||
ALL_AUTH_PROVIDERS = [
|
||||
ALLAUTH_PROVIDERS = [
|
||||
"allauth.socialaccount.providers.github",
|
||||
# "allauth.socialaccount.providers.google",
|
||||
# "allauth.socialaccount.providers.telegram",
|
||||
|
@ -149,6 +149,7 @@
|
|||
"akarpov.blog",
|
||||
"akarpov.files",
|
||||
"akarpov.music",
|
||||
"akarpov.gallery",
|
||||
"akarpov.pipeliner",
|
||||
"akarpov.test_platform",
|
||||
"akarpov.tools.shortener",
|
||||
|
@ -156,7 +157,7 @@
|
|||
]
|
||||
# https://docs.djangoproject.com/en/dev/ref/settings/#installed-apps
|
||||
INSTALLED_APPS = (
|
||||
DJANGO_APPS + LOCAL_APPS + THIRD_PARTY_APPS + HEALTH_CHECKS + ALL_AUTH_PROVIDERS
|
||||
DJANGO_APPS + LOCAL_APPS + THIRD_PARTY_APPS + HEALTH_CHECKS + ALLAUTH_PROVIDERS
|
||||
)
|
||||
|
||||
# MIGRATIONS
|
||||
|
|
|
@ -36,6 +36,7 @@
|
|||
path("music/", include("akarpov.music.urls", namespace="music")),
|
||||
path("forms/", include("akarpov.test_platform.urls", namespace="forms")),
|
||||
path("tools/", include("akarpov.tools.urls", namespace="tools")),
|
||||
path("gallery/", include("akarpov.gallery.urls", namespace="gallery")),
|
||||
path("ckeditor/", include("ckeditor_uploader.urls")),
|
||||
path("accounts/", include("allauth.urls")),
|
||||
path("", include("akarpov.blog.urls", namespace="blog")),
|
||||
|
|
Loading…
Reference in New Issue
Block a user