добавил настройки для единичного создания объекта тех поддержки
This commit is contained in:
parent
1cb37882bf
commit
17088d367d
|
|
@ -1,10 +1,11 @@
|
||||||
from .models import Team, SupportInfo
|
from .models import Team, SupportInfo
|
||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
|
from config_site.admin_configuration import SingletonModelAdmin
|
||||||
|
|
||||||
@admin.register(Team)
|
@admin.register(Team)
|
||||||
class TeamAdmin(admin.ModelAdmin):
|
class TeamAdmin(admin.ModelAdmin):
|
||||||
list_display = ('name', 'last_name', 'position', 'img_person')
|
list_display = ('name', 'last_name', 'position', 'img_person')
|
||||||
|
|
||||||
@admin.register(SupportInfo)
|
@admin.register(SupportInfo)
|
||||||
class SupportInfoAdmin(admin.ModelAdmin):
|
class SupportInfoAdmin(SingletonModelAdmin):
|
||||||
list_display = ('phone', 'city', 'street', 'house', 'email', 'vk_url', 'telegram_url')
|
list_display = ('phone', 'city', 'street', 'house', 'email', 'vk_url', 'telegram_url')
|
||||||
|
|
@ -0,0 +1,99 @@
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
|
from django.db.models import Model
|
||||||
|
from django.urls import URLPattern, re_path
|
||||||
|
from django.contrib import admin
|
||||||
|
from django.http import HttpRequest, HttpResponse, HttpResponseRedirect
|
||||||
|
from django.utils.encoding import force_str
|
||||||
|
from django.utils.translation import gettext as _
|
||||||
|
|
||||||
|
from config_site.single_configuration import DEFAULT_SINGLETON_INSTANCE_ID
|
||||||
|
from config_site import solo_settings
|
||||||
|
|
||||||
|
|
||||||
|
class SingletonModelAdmin(admin.ModelAdmin): # type: ignore[type-arg]
|
||||||
|
object_history_template = "admin/solo/object_history.html"
|
||||||
|
change_form_template = "admin/solo/change_form.html"
|
||||||
|
|
||||||
|
def has_add_permission(self, request: HttpRequest) -> bool:
|
||||||
|
return False
|
||||||
|
|
||||||
|
def has_delete_permission(self, request: HttpRequest, obj: Model | None = None) -> bool:
|
||||||
|
return False
|
||||||
|
|
||||||
|
def get_urls(self) -> list[URLPattern]:
|
||||||
|
urls = super().get_urls()
|
||||||
|
|
||||||
|
if not solo_settings.SOLO_ADMIN_SKIP_OBJECT_LIST_PAGE:
|
||||||
|
return urls
|
||||||
|
|
||||||
|
# _meta.model_name only exists on Django>=1.6 -
|
||||||
|
# on earlier versions, use module_name.lower()
|
||||||
|
try:
|
||||||
|
model_name = self.model._meta.model_name
|
||||||
|
except AttributeError:
|
||||||
|
model_name = self.model._meta.module_name.lower()
|
||||||
|
|
||||||
|
self.model._meta.verbose_name_plural = self.model._meta.verbose_name
|
||||||
|
url_name_prefix = '%(app_name)s_%(model_name)s' % {
|
||||||
|
'app_name': self.model._meta.app_label,
|
||||||
|
'model_name': model_name,
|
||||||
|
}
|
||||||
|
custom_urls = [
|
||||||
|
re_path(r'^history/$',
|
||||||
|
self.admin_site.admin_view(self.history_view),
|
||||||
|
{'object_id': str(self.singleton_instance_id)},
|
||||||
|
name='%s_history' % url_name_prefix),
|
||||||
|
re_path(r'^$',
|
||||||
|
self.admin_site.admin_view(self.change_view),
|
||||||
|
{'object_id': str(self.singleton_instance_id)},
|
||||||
|
name='%s_change' % url_name_prefix),
|
||||||
|
]
|
||||||
|
|
||||||
|
# By inserting the custom URLs first, we overwrite the standard URLs.
|
||||||
|
return custom_urls + urls
|
||||||
|
|
||||||
|
def response_change(self, request: HttpRequest, obj: Model) -> HttpResponseRedirect:
|
||||||
|
msg = _('%(obj)s was changed successfully.') % {
|
||||||
|
'obj': force_str(obj)}
|
||||||
|
if '_continue' in request.POST:
|
||||||
|
self.message_user(request, msg + ' ' +
|
||||||
|
_('You may edit it again below.'))
|
||||||
|
return HttpResponseRedirect(request.path)
|
||||||
|
else:
|
||||||
|
self.message_user(request, msg)
|
||||||
|
return HttpResponseRedirect("../../")
|
||||||
|
|
||||||
|
def change_view(self, request: HttpRequest, object_id: str, form_url: str = '', extra_context: dict[str, Any] | None = None) -> HttpResponse:
|
||||||
|
if object_id == str(self.singleton_instance_id):
|
||||||
|
self.model.objects.get_or_create(pk=self.singleton_instance_id)
|
||||||
|
|
||||||
|
if not extra_context:
|
||||||
|
extra_context = dict()
|
||||||
|
extra_context['skip_object_list_page'] = solo_settings.SOLO_ADMIN_SKIP_OBJECT_LIST_PAGE
|
||||||
|
|
||||||
|
return super().change_view(
|
||||||
|
request,
|
||||||
|
object_id,
|
||||||
|
form_url=form_url,
|
||||||
|
extra_context=extra_context,
|
||||||
|
)
|
||||||
|
|
||||||
|
def history_view(self, request: HttpRequest, object_id: str, extra_context: dict[str, Any] | None = None) -> HttpResponse:
|
||||||
|
if not extra_context:
|
||||||
|
extra_context = dict()
|
||||||
|
extra_context['skip_object_list_page'] = solo_settings.SOLO_ADMIN_SKIP_OBJECT_LIST_PAGE
|
||||||
|
|
||||||
|
return super().history_view(
|
||||||
|
request,
|
||||||
|
object_id,
|
||||||
|
extra_context=extra_context,
|
||||||
|
)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def singleton_instance_id(self) -> int:
|
||||||
|
return getattr(self.model, 'singleton_instance_id', DEFAULT_SINGLETON_INSTANCE_ID)
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
from django.db import models
|
from django.db import models
|
||||||
|
from config_site.single_configuration import SingletonModel
|
||||||
|
|
||||||
class Page(models.Model):
|
class Page(models.Model):
|
||||||
name = models.CharField('Название страницы', max_length=50)
|
name = models.CharField('Название страницы', max_length=50)
|
||||||
|
|
@ -25,7 +26,7 @@ class Team(models.Model):
|
||||||
verbose_name = 'Команда'
|
verbose_name = 'Команда'
|
||||||
verbose_name_plural = 'Команда'
|
verbose_name_plural = 'Команда'
|
||||||
|
|
||||||
class SupportInfo(models.Model):
|
class SupportInfo(SingletonModel):
|
||||||
phone = models.CharField('Номер телефона', max_length=50, null=True, blank=True)
|
phone = models.CharField('Номер телефона', max_length=50, null=True, blank=True)
|
||||||
city = models.CharField('Город', max_length=50, null=True, blank=True)
|
city = models.CharField('Город', max_length=50, null=True, blank=True)
|
||||||
street = models.CharField('Улица', max_length=50, null=True, blank=True)
|
street = models.CharField('Улица', max_length=50, null=True, blank=True)
|
||||||
|
|
@ -34,6 +35,9 @@ class SupportInfo(models.Model):
|
||||||
vk_url = models.URLField('Ссылка на группу Вк', max_length=50, null=True, blank=True)
|
vk_url = models.URLField('Ссылка на группу Вк', max_length=50, null=True, blank=True)
|
||||||
telegram_url = models.URLField('Ссылка на канал в Телегерамме', max_length=50, null=True, blank=True)
|
telegram_url = models.URLField('Ссылка на канал в Телегерамме', max_length=50, null=True, blank=True)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return "Информация о тех поддержке"
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
verbose_name = 'Тех поддержка'
|
verbose_name = 'Тех поддержка'
|
||||||
verbose_name_plural = 'Тех поддержка'
|
verbose_name_plural = 'Тех поддержка'
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,77 @@
|
||||||
|
from __future__ import annotations
|
||||||
|
import sys
|
||||||
|
import warnings
|
||||||
|
from typing import Any
|
||||||
|
from django.conf import settings
|
||||||
|
from django.core.cache import BaseCache, caches
|
||||||
|
from django.db import models
|
||||||
|
from config_site import solo_settings
|
||||||
|
from typing_extensions import Self
|
||||||
|
if sys.version_info >= (3, 11):
|
||||||
|
from typing import Self
|
||||||
|
else:
|
||||||
|
from typing_extensions import Self
|
||||||
|
|
||||||
|
DEFAULT_SINGLETON_INSTANCE_ID = 1
|
||||||
|
|
||||||
|
|
||||||
|
def get_cache(cache_name: str) -> BaseCache:
|
||||||
|
warnings.warn(
|
||||||
|
"'get_cache' is deprecated and will be removed in django-solo 2.4.0. "
|
||||||
|
"Instead, use 'caches' from 'django.core.cache'.",
|
||||||
|
DeprecationWarning,
|
||||||
|
stacklevel=2,
|
||||||
|
)
|
||||||
|
return caches[cache_name] # type: ignore[no-any-return] # mypy bug, unable to get a MRE
|
||||||
|
|
||||||
|
|
||||||
|
class SingletonModel(models.Model):
|
||||||
|
singleton_instance_id = DEFAULT_SINGLETON_INSTANCE_ID
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
abstract = True
|
||||||
|
|
||||||
|
def save(self, *args: Any, **kwargs: Any) -> None:
|
||||||
|
self.pk = self.singleton_instance_id
|
||||||
|
super().save(*args, **kwargs)
|
||||||
|
self.set_to_cache()
|
||||||
|
|
||||||
|
def delete(self, *args: Any, **kwargs: Any) -> tuple[int, dict[str, int]]:
|
||||||
|
self.clear_cache()
|
||||||
|
return super().delete(*args, **kwargs)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def clear_cache(cls) -> None:
|
||||||
|
cache_name = getattr(settings, 'SOLO_CACHE', solo_settings.SOLO_CACHE)
|
||||||
|
if cache_name:
|
||||||
|
cache = caches[cache_name]
|
||||||
|
cache_key = cls.get_cache_key()
|
||||||
|
cache.delete(cache_key)
|
||||||
|
|
||||||
|
def set_to_cache(self) -> None:
|
||||||
|
cache_name = getattr(settings, 'SOLO_CACHE', solo_settings.SOLO_CACHE)
|
||||||
|
if not cache_name:
|
||||||
|
return None
|
||||||
|
cache = caches[cache_name]
|
||||||
|
cache_key = self.get_cache_key()
|
||||||
|
timeout = getattr(settings, 'SOLO_CACHE_TIMEOUT', solo_settings.SOLO_CACHE_TIMEOUT)
|
||||||
|
cache.set(cache_key, self, timeout)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_cache_key(cls) -> str:
|
||||||
|
prefix = getattr(settings, 'SOLO_CACHE_PREFIX', solo_settings.SOLO_CACHE_PREFIX)
|
||||||
|
return '%s:%s' % (prefix, cls.__name__.lower())
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_solo(cls) -> Self:
|
||||||
|
cache_name = getattr(settings, 'SOLO_CACHE', solo_settings.SOLO_CACHE)
|
||||||
|
if not cache_name:
|
||||||
|
obj, _ = cls.objects.get_or_create(pk=cls.singleton_instance_id)
|
||||||
|
return obj # type: ignore[return-value]
|
||||||
|
cache = caches[cache_name]
|
||||||
|
cache_key = cls.get_cache_key()
|
||||||
|
obj = cache.get(cache_key)
|
||||||
|
if not obj:
|
||||||
|
obj, _ = cls.objects.get_or_create(pk=cls.singleton_instance_id)
|
||||||
|
obj.set_to_cache()
|
||||||
|
return obj # type: ignore[return-value]
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from django.conf import settings
|
||||||
|
|
||||||
|
# template parameters
|
||||||
|
GET_SOLO_TEMPLATE_TAG_NAME: str = getattr(
|
||||||
|
settings, 'GET_SOLO_TEMPLATE_TAG_NAME', 'get_solo'
|
||||||
|
)
|
||||||
|
|
||||||
|
SOLO_ADMIN_SKIP_OBJECT_LIST_PAGE: bool = getattr(
|
||||||
|
settings, 'SOLO_ADMIN_SKIP_OBJECT_LIST_PAGE', True
|
||||||
|
)
|
||||||
|
|
||||||
|
# The cache that should be used, e.g. 'default'. Refers to Django CACHES setting.
|
||||||
|
# Set to None to disable caching.
|
||||||
|
SOLO_CACHE: str | None = None
|
||||||
|
|
||||||
|
SOLO_CACHE_TIMEOUT = 60 * 5
|
||||||
|
|
||||||
|
SOLO_CACHE_PREFIX = 'solo'
|
||||||
|
DEFAULT_AUTO_FIELD = 'django.db.models.AutoField'
|
||||||
|
|
@ -0,0 +1,22 @@
|
||||||
|
{% extends "admin/change_form.html" %}
|
||||||
|
{% load i18n %}
|
||||||
|
{% load admin_urls %}
|
||||||
|
|
||||||
|
{% block breadcrumbs %}
|
||||||
|
{% if skip_object_list_page %}
|
||||||
|
<div class="breadcrumbs">
|
||||||
|
<a href="{% url 'admin:index' %}">{% trans 'Home' %}</a> ›
|
||||||
|
<a href="../">{{ opts.app_config.verbose_name }}</a> ›
|
||||||
|
{{ opts.verbose_name|capfirst }}
|
||||||
|
</div>
|
||||||
|
{% else %}
|
||||||
|
{{ block.super }}
|
||||||
|
{% endif %}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block object-tools-items %}
|
||||||
|
<li><a href="{% url opts|admin_urlname:'history' original.pk %}" class="historylink">{% trans "History" %}</a></li>
|
||||||
|
{% if has_absolute_url %}
|
||||||
|
<li><a href="{% url 'admin:view_on_site' content_type_id original.pk %}" class="viewsitelink">{% trans "View on site" %}</a></li>
|
||||||
|
{% endif %}
|
||||||
|
{% endblock %}
|
||||||
|
|
@ -0,0 +1,15 @@
|
||||||
|
{% extends "admin/object_history.html" %}
|
||||||
|
{% load i18n %}
|
||||||
|
|
||||||
|
{% block breadcrumbs %}
|
||||||
|
{% if skip_object_list_page %}
|
||||||
|
<div class="breadcrumbs">
|
||||||
|
<a href="{% url 'admin:index' %}">{% trans 'Home' %}</a> ›
|
||||||
|
<a href="../../">{{ opts.app_config.verbose_name }}</a> ›
|
||||||
|
<a href="../">{{ object|truncatewords:"18" }}</a> ›
|
||||||
|
{% trans 'History' %}
|
||||||
|
</div>
|
||||||
|
{% else %}
|
||||||
|
{{ block.super }}
|
||||||
|
{% endif %}
|
||||||
|
{% endblock %}
|
||||||
|
|
@ -1,8 +1,6 @@
|
||||||
from rest_framework.viewsets import GenericViewSet
|
from rest_framework.viewsets import GenericViewSet
|
||||||
from rest_framework.response import Response
|
from rest_framework.response import Response
|
||||||
from rest_framework import status
|
from rest_framework import status
|
||||||
|
|
||||||
|
|
||||||
from .models import Team, SupportInfo
|
from .models import Team, SupportInfo
|
||||||
from .serializers import TeamSerializer, SupportInfoSerializer
|
from .serializers import TeamSerializer, SupportInfoSerializer
|
||||||
|
|
||||||
|
|
@ -17,11 +15,11 @@ class TeamViewSet(GenericViewSet):
|
||||||
return Response(serializer.data, status=status.HTTP_200_OK)
|
return Response(serializer.data, status=status.HTTP_200_OK)
|
||||||
|
|
||||||
class SupportInfoViewSet(GenericViewSet):
|
class SupportInfoViewSet(GenericViewSet):
|
||||||
queryset = SupportInfo
|
queryset = SupportInfo.objects.all()
|
||||||
serializer_class = SupportInfoSerializer
|
serializer_class = SupportInfoSerializer
|
||||||
|
|
||||||
def list(self, request):
|
def list(self, request):
|
||||||
queryset = self.get_queryset().objects.all()
|
queryset = self.get_queryset().first()
|
||||||
serializer = self.get_serializer(queryset, many=True)
|
serializer = self.get_serializer(queryset)
|
||||||
return Response(serializer.data, status=status.HTTP_200_OK)
|
return Response(serializer.data, status=status.HTTP_200_OK)
|
||||||
|
|
||||||
Loading…
Reference in New Issue