Refactor card badge and multiselect template tags to properly implement and/or improve caching and context handling
- Updated `card_badge` and `card_multiselect` template tags to utilize `reverse_lazy` for URL resolution. - Enhanced caching mechanisms in `card_badge.html` and `card_multiselect.html` to improve performance. - Introduced a new template `_card_multiselect_options.html` for rendering multiselect options. - Improved context management in `card_multiselect` to handle selected cards and dynamic placeholders. - Added error handling for query hashing in `card_multiselect` to ensure robustness. - Updated `trade_offer_tags` to optimize database queries using `select_related` for related objects.
This commit is contained in:
parent
7d94dc001f
commit
4e50e1545c
10 changed files with 234 additions and 163 deletions
|
|
@ -1,41 +1,46 @@
|
|||
from django import template
|
||||
from django.conf import settings
|
||||
from django.template.loader import render_to_string
|
||||
from django.utils.safestring import mark_safe
|
||||
from django.urls import reverse
|
||||
from django.urls import reverse_lazy
|
||||
|
||||
register = template.Library()
|
||||
|
||||
@register.inclusion_tag("templatetags/card_badge.html")
|
||||
def card_badge(card, quantity=None, expanded=False):
|
||||
url = reverse('cards:card_detail', args=[card.pk])
|
||||
return {
|
||||
@register.inclusion_tag("templatetags/card_badge.html", takes_context=True)
|
||||
def card_badge(context, card, quantity=None, expanded=False):
|
||||
"""
|
||||
Renders a card badge.
|
||||
"""
|
||||
url = reverse_lazy('cards:card_detail', args=[card.pk])
|
||||
tag_context = {
|
||||
'quantity': quantity,
|
||||
'style': card.style,
|
||||
'name': card.name,
|
||||
'rarity': card.rarity_icon,
|
||||
'cardset': card.cardset,
|
||||
'expanded': expanded,
|
||||
'cache_key': f'card_badge_{card.pk}_{quantity}_{expanded}',
|
||||
'url': url,
|
||||
}
|
||||
context.update(tag_context)
|
||||
return context
|
||||
|
||||
@register.filter
|
||||
def card_badge_inline(card, quantity=None):
|
||||
"""
|
||||
Renders an inline card badge.
|
||||
Renders an inline card badge by directly rendering the template.
|
||||
"""
|
||||
url = reverse('cards:card_detail', args=[card.pk])
|
||||
html = render_to_string("templatetags/card_badge.html", {
|
||||
url = reverse_lazy('cards:card_detail', args=[card.pk])
|
||||
tag_context = {
|
||||
'quantity': quantity,
|
||||
'style': card.style,
|
||||
'name': card.name,
|
||||
'rarity': card.rarity_icon,
|
||||
'cardset': card.cardset,
|
||||
'expanded': True,
|
||||
'cache_key': f'card_badge_{card.pk}_{quantity}_{True}',
|
||||
'CACHE_TIMEOUT': settings.CACHE_TIMEOUT,
|
||||
'url': url,
|
||||
})
|
||||
return mark_safe(html)
|
||||
|
||||
@register.filter
|
||||
def addstr(arg1, arg2):
|
||||
"""concatenate arg1 & arg2"""
|
||||
return str(arg1) + str(arg2)
|
||||
}
|
||||
html = render_to_string("templatetags/card_badge.html", tag_context)
|
||||
return mark_safe(html)
|
||||
|
|
@ -1,54 +1,72 @@
|
|||
import uuid
|
||||
from django import template
|
||||
from cards.models import Card
|
||||
|
||||
from django.db.models.query import QuerySet
|
||||
import json
|
||||
import hashlib
|
||||
import logging
|
||||
register = template.Library()
|
||||
|
||||
@register.inclusion_tag('templatetags/card_multiselect.html')
|
||||
def card_multiselect(field_name, label, placeholder, cards=None, selected_values=None, cache_timeout=86400):
|
||||
@register.filter
|
||||
def get_item(dictionary, key):
|
||||
"""Allows accessing dictionary items using a variable key in templates."""
|
||||
return dictionary.get(key)
|
||||
|
||||
@register.simple_tag
|
||||
def fetch_all_cards():
|
||||
"""Simple tag to fetch all Card objects."""
|
||||
return Card.objects.order_by('pk').all()
|
||||
|
||||
@register.inclusion_tag('templatetags/card_multiselect.html', takes_context=True)
|
||||
def card_multiselect(context, field_name, label, placeholder, cards=None, selected_values=None):
|
||||
"""
|
||||
Renders a multiselect field for choosing cards while supporting quantity data.
|
||||
|
||||
Updated to allow `card_filter` to be either a dictionary (of lookup parameters) or a QuerySet.
|
||||
This is useful when you want to limit available cards based on your new trades models (e.g. showing only
|
||||
cards that appear in active trade offers).
|
||||
|
||||
Parameters:
|
||||
- field_name: The name attribute for the select tag.
|
||||
- label: Label text to show above the selector.
|
||||
- placeholder: Placeholder text to show in the select.
|
||||
- selected_values: (Optional) A list of selected values; if a value includes a quantity it should be in the format "card_id:quantity".
|
||||
- cache_timeout: (Optional) Cache timeout (in seconds) for the options block.
|
||||
- cache_key: (Optional) Cache key.
|
||||
Prepares context for rendering a card multiselect input.
|
||||
Database querying and rendering are handled within the template's cache block.
|
||||
"""
|
||||
if selected_values is None:
|
||||
selected_values = []
|
||||
# Create a mapping {card_id: quantity}
|
||||
|
||||
selected_cards = {}
|
||||
for val in selected_values:
|
||||
parts = str(val).split(':')
|
||||
card_id = parts[0]
|
||||
quantity = parts[1] if len(parts) > 1 else 1
|
||||
selected_cards[card_id] = quantity
|
||||
if len(parts) >= 1 and parts[0]:
|
||||
card_id = parts[0]
|
||||
quantity = parts[1] if len(parts) > 1 else 1
|
||||
selected_cards[str(card_id)] = quantity
|
||||
|
||||
if cards is None:
|
||||
cards = Card.objects.all()
|
||||
effective_field_name = field_name if field_name is not None else 'card_multiselect'
|
||||
effective_label = label if label is not None else 'Card'
|
||||
effective_placeholder = placeholder if placeholder is not None else 'Select Cards'
|
||||
|
||||
# Loop through available cards and attach pre‑selected quantity
|
||||
for card in cards:
|
||||
pk_str = str(card.pk)
|
||||
if pk_str in selected_cards:
|
||||
card.selected_quantity = selected_cards[pk_str]
|
||||
card.selected = True
|
||||
else:
|
||||
card.selected_quantity = 1
|
||||
card.selected = False
|
||||
selected_cards_key_part = json.dumps(selected_cards, sort_keys=True)
|
||||
|
||||
return {
|
||||
'field_name': field_name,
|
||||
'field_id': field_name, # using the name as id for simplicity
|
||||
'label': label,
|
||||
'cards': cards,
|
||||
'placeholder': placeholder,
|
||||
'selected_values': list(selected_cards.keys()),
|
||||
'cache_timeout': cache_timeout
|
||||
}
|
||||
has_passed_cards = isinstance(cards, QuerySet)
|
||||
|
||||
if has_passed_cards:
|
||||
try:
|
||||
query_string = str(cards.query)
|
||||
passed_cards_identifier = hashlib.sha256(query_string.encode('utf-8')).hexdigest()
|
||||
except Exception as e:
|
||||
logging.warning(f"Could not generate query hash for card_multiselect. Error: {e}")
|
||||
passed_cards_identifier = 'specific_qs_fallback_' + str(uuid.uuid4())
|
||||
else:
|
||||
passed_cards_identifier = 'all_cards'
|
||||
|
||||
# Define the variables specific to this tag
|
||||
tag_specific_context = {
|
||||
'field_name': effective_field_name,
|
||||
'field_id': effective_field_name,
|
||||
'label': effective_label,
|
||||
'placeholder': effective_placeholder,
|
||||
'passed_cards': cards if has_passed_cards else None,
|
||||
'has_passed_cards': has_passed_cards,
|
||||
'selected_cards': selected_cards,
|
||||
'selected_cards_key_part': selected_cards_key_part,
|
||||
'passed_cards_identifier': passed_cards_identifier,
|
||||
}
|
||||
|
||||
# Update the original context with the tag-specific variables
|
||||
# This preserves CACHE_TIMEOUT and other parent context variables
|
||||
context.update(tag_specific_context)
|
||||
|
||||
return context # Return the MODIFIED original context
|
||||
Loading…
Add table
Add a link
Reference in a new issue