mirror of
https://github.com/Alexander-D-Karpov/akarpov
synced 2024-11-22 07:26:33 +03:00
minor blog updates and fixes, added better cache
This commit is contained in:
parent
13638466a2
commit
f0dd4e2b27
18
akarpov/blog/migrations/0008_tag_seo_tags.py
Normal file
18
akarpov/blog/migrations/0008_tag_seo_tags.py
Normal file
|
@ -0,0 +1,18 @@
|
|||
# Generated by Django 4.2.3 on 2023-08-03 12:10
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("blog", "0007_alter_comment_options_alter_commentrating_options_and_more"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name="tag",
|
||||
name="seo_tags",
|
||||
field=models.TextField(blank=True, null=True),
|
||||
),
|
||||
]
|
|
@ -10,6 +10,7 @@
|
|||
from akarpov.tools.shortener.models import ShortLinkModel
|
||||
from akarpov.users.models import User
|
||||
from akarpov.users.services.history import UserHistoryModel
|
||||
from akarpov.utils.cache import cache_model_property
|
||||
from akarpov.utils.string import cleanhtml
|
||||
|
||||
|
||||
|
@ -41,7 +42,6 @@ def get_comments(self):
|
|||
return self.comments.all()
|
||||
|
||||
def h_tags(self):
|
||||
# TODO: add caching here
|
||||
tags = (
|
||||
Tag.objects.filter(posts__id=self.id)
|
||||
.annotate(num_posts=Count("posts"))
|
||||
|
@ -49,18 +49,20 @@ def h_tags(self):
|
|||
)
|
||||
return tags
|
||||
|
||||
def h_tag(self):
|
||||
def _h_tag(self):
|
||||
return self.h_tags().first()
|
||||
|
||||
def h_tag(self):
|
||||
return cache_model_property(self, "_h_tag")
|
||||
|
||||
@property
|
||||
def text(self):
|
||||
# TODO: add caching here
|
||||
return cleanhtml(self.body)
|
||||
|
||||
@property
|
||||
@extend_schema_field(serializers.CharField)
|
||||
def summary(self):
|
||||
body = self.text
|
||||
body = cache_model_property(self, "text")
|
||||
return body[:100] + "..." if len(body) > 100 else ""
|
||||
|
||||
def get_absolute_url(self):
|
||||
|
@ -77,6 +79,7 @@ class SlugMeta:
|
|||
class Tag(UserHistoryModel):
|
||||
name = models.CharField(max_length=20, unique=True)
|
||||
color = ColorField(blank=True, default="#FF0000")
|
||||
seo_tags = models.TextField(blank=True, null=True)
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
from django.db.models.signals import pre_delete, pre_save
|
||||
from django.dispatch import receiver
|
||||
|
||||
from akarpov.blog.models import PostRating, Tag
|
||||
from akarpov.blog.models import Post, PostRating, Tag
|
||||
from akarpov.utils.cache import clear_model_cache
|
||||
from akarpov.utils.generators import generate_hex_color
|
||||
|
||||
|
||||
|
@ -38,6 +39,16 @@ def post_rating(sender, instance: PostRating, **kwargs):
|
|||
post.save()
|
||||
|
||||
|
||||
@receiver(pre_save, sender=Post)
|
||||
def post_update(sender, instance: Post, **kwargs):
|
||||
if instance.id:
|
||||
if "update_fields" in kwargs:
|
||||
for field in kwargs["update_fields"]:
|
||||
clear_model_cache(instance, field)
|
||||
else:
|
||||
clear_model_cache(instance)
|
||||
|
||||
|
||||
@receiver(pre_delete, sender=PostRating)
|
||||
def post_rating_delete(sender, instance: PostRating, **kwargs):
|
||||
post = instance.post
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
from django.core.exceptions import PermissionDenied, ValidationError
|
||||
from django.http import HttpResponseRedirect
|
||||
from django.shortcuts import get_object_or_404
|
||||
from django.urls import reverse
|
||||
from django.views.decorators.csrf import csrf_exempt
|
||||
from django.views.generic import CreateView, DetailView, ListView, UpdateView
|
||||
|
||||
|
@ -19,17 +20,19 @@ class PostDetailView(DetailView):
|
|||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
|
||||
# that's kind of trash code, but CBS forced me to do so
|
||||
post = self.get_object()
|
||||
post.post_views += 1
|
||||
post.save(update_fields=["post_views"])
|
||||
|
||||
if self.request.user.is_authenticated:
|
||||
context["rating_bar"] = get_rating_bar(self.request.user, post)
|
||||
context["rating_bar"] = get_rating_bar(self.request.user, kwargs["object"])
|
||||
else:
|
||||
context["rating_bar"] = None
|
||||
return context
|
||||
|
||||
def get(self, request, *args, **kwargs):
|
||||
self.object = self.get_object()
|
||||
self.object.post_views += 1
|
||||
self.object.save(update_fields=["post_views"])
|
||||
context = self.get_context_data(object=self.object)
|
||||
return self.render_to_response(context)
|
||||
|
||||
|
||||
post_detail_view = PostDetailView.as_view()
|
||||
|
||||
|
@ -127,7 +130,7 @@ def rate_post_up(request, slug):
|
|||
post_r.save()
|
||||
else:
|
||||
PostRating.objects.create(user=request.user, post=post, vote_up=True)
|
||||
return HttpResponseRedirect(f"/{slug}" + "#rating")
|
||||
return HttpResponseRedirect(reverse("blog:post", kwargs={"slug": slug}) + "#rating")
|
||||
|
||||
|
||||
@csrf_exempt
|
||||
|
@ -147,7 +150,7 @@ def rate_post_down(request, slug):
|
|||
post_r.save()
|
||||
else:
|
||||
PostRating.objects.create(user=request.user, post=post, vote_up=False)
|
||||
return HttpResponseRedirect(f"/{slug}" + "#rating")
|
||||
return HttpResponseRedirect(reverse("blog:post", kwargs={"slug": slug}) + "#rating")
|
||||
|
||||
|
||||
def comment(request, slug):
|
||||
|
@ -160,4 +163,6 @@ def comment(request, slug):
|
|||
post=post, author=request.user, body=request.POST["body"]
|
||||
)
|
||||
|
||||
return HttpResponseRedirect(f"/{slug}" + "#comments")
|
||||
return HttpResponseRedirect(
|
||||
reverse("blog:post", kwargs={"slug": slug}) + "#comments"
|
||||
)
|
||||
|
|
|
@ -107,6 +107,7 @@
|
|||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
{# TODO: add SEO tags here #}
|
||||
|
||||
<script>
|
||||
function addComment(){
|
||||
|
|
39
akarpov/utils/cache.py
Normal file
39
akarpov/utils/cache.py
Normal file
|
@ -0,0 +1,39 @@
|
|||
from django.db.models import Model
|
||||
|
||||
stack = {}
|
||||
|
||||
|
||||
def cache_model_property(model: Model, name: str):
|
||||
# function to store non-hashable value for model instances
|
||||
# TODO: add TTL here and update with celery
|
||||
|
||||
app_name = model._meta.app_label + model._meta.model_name
|
||||
if app_name not in stack:
|
||||
stack[app_name] = {}
|
||||
|
||||
if model.pk not in stack[app_name]:
|
||||
stack[app_name][model.pk] = {}
|
||||
|
||||
if name not in stack[app_name][model.pk]:
|
||||
val = getattr(model, name)
|
||||
if callable(val):
|
||||
val = val()
|
||||
stack[app_name][model.pk][name] = val
|
||||
return val
|
||||
return stack[app_name][model.pk][name]
|
||||
|
||||
|
||||
def clear_model_cache(model: Model, name=None):
|
||||
app_name = model._meta.app_label + model._meta.model_name
|
||||
if app_name not in stack:
|
||||
return
|
||||
|
||||
if model.pk not in stack[app_name]:
|
||||
return
|
||||
|
||||
if name:
|
||||
if name in stack[app_name][model.pk]:
|
||||
del stack[app_name][model.pk][name]
|
||||
else:
|
||||
del stack[app_name][model.pk]
|
||||
return
|
Loading…
Reference in New Issue
Block a user