optimize journal data models

This commit is contained in:
Your Name 2022-12-29 16:20:33 -05:00
parent 8aa6324334
commit f24df6c0fd
5 changed files with 114 additions and 67 deletions

View file

@ -10,10 +10,10 @@ def thumb(source, alias):
This filter modifies that from `easy_thumbnails` so that
it can neglect .svg file.
"""
if source.url.endswith(".svg"):
return source.url
else:
try:
try:
if source.url.endswith(".svg"):
return source.url
else:
return thumbnail_url(source, alias)
except Exception:
return ""
except Exception as e:
return ""

View file

@ -13,9 +13,11 @@ from django.utils.translation import gettext_lazy as _
from django.core.validators import RegexValidator
from functools import cached_property
from django.db.models import Count, Avg
from django.contrib.contenttypes.models import ContentType
import django.dispatch
import math
import uuid
import re
from catalog.common.utils import DEFAULT_ITEM_COVER, item_cover_path
from django.utils.baseconv import base62
from django.db.models import Q
@ -69,24 +71,6 @@ def query_item_category(item_category):
class Piece(PolymorphicModel, UserOwnedObjectMixin):
url_path = "piece" # subclass must specify this
uid = models.UUIDField(default=uuid.uuid4, editable=False, db_index=True)
owner = models.ForeignKey(User, on_delete=models.PROTECT)
visibility = models.PositiveSmallIntegerField(
default=0
) # 0: Public / 1: Follower only / 2: Self only
created_time = models.DateTimeField(
default=timezone.now
) # auto_now_add=True FIXME revert this after migration
edited_time = models.DateTimeField(
default=timezone.now
) # auto_now=True FIXME revert this after migration
metadata = models.JSONField(default=dict)
attached_to = models.ForeignKey(
User,
null=True,
default=None,
on_delete=models.SET_NULL,
related_name="attached_with",
)
@property
def uuid(self):
@ -102,10 +86,21 @@ class Piece(PolymorphicModel, UserOwnedObjectMixin):
@property
def api_url(self):
return ("/api/" + self.url) if self.url_path else None
return f"/api/{self.url}" if self.url_path else None
class Content(Piece):
owner = models.ForeignKey(User, on_delete=models.PROTECT)
visibility = models.PositiveSmallIntegerField(
default=0
) # 0: Public / 1: Follower only / 2: Self only
created_time = models.DateTimeField(
default=timezone.now
) # auto_now_add=True FIXME revert this after migration
edited_time = models.DateTimeField(
default=timezone.now
) # auto_now=True FIXME revert this after migration
metadata = models.JSONField(default=dict)
item = models.ForeignKey(Item, on_delete=models.PROTECT)
@cached_property
@ -122,8 +117,22 @@ class Content(Piece):
class Like(Piece):
owner = models.ForeignKey(User, on_delete=models.PROTECT)
visibility = models.PositiveSmallIntegerField(
default=0
) # 0: Public / 1: Follower only / 2: Self only
created_time = models.DateTimeField(
default=timezone.now
) # auto_now_add=True FIXME revert this after migration
edited_time = models.DateTimeField(
default=timezone.now
) # auto_now=True FIXME revert this after migration
target = models.ForeignKey(Piece, on_delete=models.CASCADE, related_name="likes")
@staticmethod
def user_liked_piece(user, piece):
return Like.objects.filter(owner=user, target=piece).first()
@staticmethod
def user_like_piece(user, piece):
if not piece or piece.__class__ not in [Collection]:
@ -139,6 +148,11 @@ class Like(Piece):
return
Like.objects.filter(owner=user, target=piece).delete()
@staticmethod
def user_likes_by_class(user, cls):
ctype_id = ContentType.objects.get_for_model(cls)
return Like.objects.filter(owner=user, target__polymorphic_ctype=ctype_id)
class Memo(Content):
pass
@ -272,17 +286,21 @@ list_remove = django.dispatch.Signal()
class List(Piece):
owner = models.ForeignKey(User, on_delete=models.PROTECT)
visibility = models.PositiveSmallIntegerField(
default=0
) # 0: Public / 1: Follower only / 2: Self only
created_time = models.DateTimeField(
default=timezone.now
) # auto_now_add=True FIXME revert this after migration
edited_time = models.DateTimeField(
default=timezone.now
) # auto_now=True FIXME revert this after migration
metadata = models.JSONField(default=dict)
class Meta:
abstract = True
_owner = models.ForeignKey(
User, on_delete=models.PROTECT
) # duplicated owner field to make unique key possible for subclasses
def save(self, *args, **kwargs):
self._owner = self.owner
super().save(*args, **kwargs)
# MEMBER_CLASS = None # subclass must override this
# subclass must add this:
# items = models.ManyToManyField(Item, through='ListMember')
@ -375,6 +393,17 @@ class ListMember(Piece):
parent = models.ForeignKey('List', related_name='members', on_delete=models.CASCADE)
"""
owner = models.ForeignKey(User, on_delete=models.PROTECT)
visibility = models.PositiveSmallIntegerField(
default=0
) # 0: Public / 1: Follower only / 2: Self only
created_time = models.DateTimeField(
default=timezone.now
) # auto_now_add=True FIXME revert this after migration
edited_time = models.DateTimeField(
default=timezone.now
) # auto_now=True FIXME revert this after migration
metadata = models.JSONField(default=dict)
item = models.ForeignKey(Item, on_delete=models.PROTECT)
position = models.PositiveIntegerField()
@ -430,7 +459,7 @@ class ShelfMember(ListMember):
class Shelf(List):
class Meta:
unique_together = [["_owner", "item_category", "shelf_type"]]
unique_together = [["owner", "item_category", "shelf_type"]]
MEMBER_CLASS = ShelfMember
items = models.ManyToManyField(Item, through="ShelfMember", related_name="+")
@ -508,7 +537,7 @@ class ShelfManager:
item=item, parent__in=self.owner.shelf_set.all()
).first()
def _shelf_for_item_and_type(item, shelf_type):
def _shelf_for_item_and_type(self, item, shelf_type):
if not item or not shelf_type:
return None
return self.owner.shelf_set.all().filter(
@ -604,6 +633,9 @@ class CollectionMember(ListMember):
note = jsondata.CharField(_("备注"), null=True, blank=True)
_RE_HTML_TAG = re.compile(r"<[^>]*>")
class Collection(List):
url_path = "collection"
MEMBER_CLASS = CollectionMember
@ -630,7 +662,7 @@ class Collection(List):
@property
def plain_description(self):
html = markdown(self.brief)
return RE_HTML_TAG.sub(" ", html)
return _RE_HTML_TAG.sub(" ", html)
def save(self, *args, **kwargs):
if getattr(self, "catalog_item", None) is None:
@ -668,7 +700,7 @@ class Tag(List):
# TODO check on save
class Meta:
unique_together = [["_owner", "title"]]
unique_together = [["owner", "title"]]
@staticmethod
def cleanup_title(title):

View file

@ -96,12 +96,12 @@
<div class="action-panel">
<div class="action-panel__button-group action-panel__button-group--center">
{% if following %}
<form action="{% url 'collection:unfollow' collection.id %}" method="post">
<form action="{% url 'journal:unlike' collection.uuid %}?back=1" method="post">
{% csrf_token %}
<button class="action-panel__button">{% trans '取消关注' %}</button>
</form>
{% else %}
<form action="{% url 'collection:follow' collection.id %}" method="post">
<form action="{% url 'journal:like' collection.uuid %}?back=1" method="post">
{% csrf_token %}
<button class="action-panel__button">{% trans '关注' %}</button>
</form>

View file

@ -18,6 +18,7 @@ def _get_all_shelf_types():
urlpatterns = [
path("wish/<str:item_uuid>", wish, name="wish"),
path("like/<str:piece_uuid>", like, name="like"),
path("unlike/<str:piece_uuid>", unlike, name="unlike"),
path("mark/<str:item_uuid>", mark, name="mark"),
path(
"add_to_collection/<str:item_uuid>", add_to_collection, name="add_to_collection"

View file

@ -33,42 +33,41 @@ _checkmark = "✔️".encode("utf-8")
@login_required
def wish(request, item_uuid):
if request.method == "POST":
item = get_object_or_404(Item, uid=base62.decode(item_uuid))
if not item:
return HttpResponseNotFound(b"item not found")
request.user.shelf_manager.move_item(item, ShelfType.WISHLIST)
if request.GET.get("back"):
return HttpResponseRedirect(request.META.get("HTTP_REFERER"))
return HttpResponse(_checkmark)
else:
if request.method != "POST":
return HttpResponseBadRequest(b"invalid request")
item = get_object_or_404(Item, uid=base62.decode(item_uuid))
if not item:
return HttpResponseNotFound(b"item not found")
request.user.shelf_manager.move_item(item, ShelfType.WISHLIST)
if request.GET.get("back"):
return HttpResponseRedirect(request.META.get("HTTP_REFERER"))
return HttpResponse(_checkmark)
@login_required
def like(request, piece_uuid):
if request.method == "POST":
piece = get_object_or_404(Collection, uid=base62.decode(piece_uuid))
if not piece:
return HttpResponseNotFound(b"piece not found")
Like.user_like_piece(request.user, piece)
return HttpResponse(_checkmark)
else:
if request.method != "POST":
return HttpResponseBadRequest(b"invalid request")
piece = get_object_or_404(Collection, uid=base62.decode(piece_uuid))
if not piece:
return HttpResponseNotFound(b"piece not found")
Like.user_like_piece(request.user, piece)
if request.GET.get("back"):
return HttpResponseRedirect(request.META.get("HTTP_REFERER"))
return HttpResponse(_checkmark)
@login_required
def unlike(request, piece_uuid):
if request.method == "POST":
piece = get_object_or_404(Collection, uid=base62.decode(piece_uuid))
if not piece:
return HttpResponseNotFound(b"piece not found")
Like.user_unlike_piece(request.user, piece)
if request.GET.get("back"):
return HttpResponseRedirect(request.META.get("HTTP_REFERER"))
return HttpResponse(_checkmark)
else:
if request.method != "POST":
return HttpResponseBadRequest(b"invalid request")
piece = get_object_or_404(Collection, uid=base62.decode(piece_uuid))
if not piece:
return HttpResponseNotFound(b"piece not found")
Like.user_unlike_piece(request.user, piece)
if request.GET.get("back"):
return HttpResponseRedirect(request.META.get("HTTP_REFERER"))
return HttpResponse(_checkmark)
@login_required
@ -163,7 +162,17 @@ def collection_retrieve(request, collection_uuid):
collection = get_object_or_404(Collection, uid=base62.decode(collection_uuid))
if not collection.is_visible_to(request.user):
raise PermissionDenied()
return render(request, "collection.html", {"collection": collection})
follower_count = collection.likes.all().count()
following = Like.user_liked_piece(request.user, collection) is not None
return render(
request,
"collection.html",
{
"collection": collection,
"follower_count": follower_count,
"following": following,
},
)
def collection_retrieve_items(request, collection_uuid, edit=False):
@ -563,7 +572,9 @@ def home(request, user_name):
Collection.objects.filter(owner=user).filter(qv).order_by("-edited_time")
)
liked_collections = (
Collection.objects.none().filter(likes__owner=user).order_by("-edited_time")
Like.user_likes_by_class(user, Collection)
.order_by("-edited_time")
.values_list("target_id", flat=True)
)
if user != request.user:
liked_collections = liked_collections.filter(query_visible(request.user))
@ -577,7 +588,10 @@ def home(request, user_name):
"shelf_list": shelf_list,
"collections": collections[:5],
"collections_count": collections.count(),
"liked_collections": liked_collections.order_by("-edited_time")[:5],
"liked_collections": [
Collection.objects.get(id=i)
for i in liked_collections.order_by("-edited_time")[:5]
],
"liked_collections_count": liked_collections.count(),
"layout": layout,
"reports": reports,