Refactor database models to majorly increase queries needed and decrease load times of home from 30 secs to 5 sec (we will be caching the rest to decrease even further via background tasks)
This commit is contained in:
parent
f7a9b2f823
commit
86c7eba10a
25 changed files with 1941 additions and 1560 deletions
|
|
@ -1,4 +1,4 @@
|
|||
# Generated by Django 5.1.2 on 2025-03-16 18:18
|
||||
# Generated by Django 5.1.2 on 2025-03-17 20:39
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations, models
|
||||
|
|
@ -20,10 +20,11 @@ class Migration(migrations.Migration):
|
|||
('id', models.AutoField(primary_key=True, serialize=False)),
|
||||
('is_closed', models.BooleanField(db_index=True, default=False)),
|
||||
('hash', models.CharField(editable=False, max_length=9)),
|
||||
('rarity_icon', models.CharField(max_length=8, null=True)),
|
||||
('rarity_level', models.IntegerField(null=True)),
|
||||
('created_at', models.DateTimeField(auto_now_add=True)),
|
||||
('updated_at', models.DateTimeField(auto_now=True)),
|
||||
('initiated_by', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='initiated_trade_offers', to='accounts.friendcode')),
|
||||
('rarity', models.ForeignKey(blank=True, editable=False, null=True, on_delete=django.db.models.deletion.PROTECT, to='cards.rarity')),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
|
|
|
|||
|
|
@ -7,30 +7,18 @@ from accounts.models import FriendCode
|
|||
class TradeOfferManager(models.Manager):
|
||||
|
||||
def get_queryset(self):
|
||||
queryset = super().get_queryset().select_related("initiated_by", "initiated_by__user", "rarity")
|
||||
queryset = queryset.prefetch_related(
|
||||
Prefetch(
|
||||
"trade_offer_want_cards",
|
||||
queryset=TradeOfferWantCard.objects.select_related("card").prefetch_related('card__decks').annotate(
|
||||
total_quantity=Sum("quantity"),
|
||||
total_accepted=Sum("qty_accepted")
|
||||
).order_by("total_quantity", "id")
|
||||
),
|
||||
Prefetch(
|
||||
"trade_offer_have_cards",
|
||||
queryset=TradeOfferHaveCard.objects.select_related("card").prefetch_related('card__decks').annotate(
|
||||
total_quantity=Sum("quantity"),
|
||||
total_accepted=Sum("qty_accepted")
|
||||
).order_by("total_quantity", "id")
|
||||
),
|
||||
Prefetch(
|
||||
"acceptances",
|
||||
queryset=TradeAcceptance.objects.select_related("accepted_by", "accepted_by__user", "requested_card", "offered_card")
|
||||
),
|
||||
queryset = super().get_queryset().select_related(
|
||||
"initiated_by__user",
|
||||
).prefetch_related(
|
||||
"trade_offer_have_cards__card",
|
||||
"trade_offer_want_cards__card",
|
||||
"acceptances",
|
||||
"acceptances__requested_card",
|
||||
"acceptances__offered_card",
|
||||
"acceptances__accepted_by__user",
|
||||
).order_by("-updated_at")
|
||||
return queryset
|
||||
|
||||
|
||||
class TradeOffer(models.Model):
|
||||
objects = TradeOfferManager()
|
||||
|
||||
|
|
@ -42,14 +30,8 @@ class TradeOffer(models.Model):
|
|||
on_delete=models.PROTECT,
|
||||
related_name='initiated_trade_offers'
|
||||
)
|
||||
rarity = models.ForeignKey(
|
||||
"cards.Rarity",
|
||||
on_delete=models.PROTECT,
|
||||
null=True,
|
||||
blank=True,
|
||||
editable=False,
|
||||
db_index=True
|
||||
)
|
||||
rarity_icon = models.CharField(max_length=8, null=True)
|
||||
rarity_level = models.IntegerField(null=True)
|
||||
want_cards = models.ManyToManyField(
|
||||
"cards.Card",
|
||||
related_name='trade_offers_want',
|
||||
|
|
|
|||
|
|
@ -5,36 +5,40 @@ from .models import TradeOffer
|
|||
from cards.models import Card
|
||||
from django.db.models import F
|
||||
from trades.models import TradeOfferHaveCard, TradeOfferWantCard, TradeAcceptance
|
||||
from django.db import transaction
|
||||
|
||||
def validate_and_set_trade_offer_rarity(instance):
|
||||
"""
|
||||
Ensures all cards on both sides share the same rarity and sets the TradeOffer.rarity
|
||||
if it hasn't been set already.
|
||||
Ensures all cards on both sides share the same rarity and sets the TradeOffer's
|
||||
rarity_level and rarity_icon if they haven't been set already.
|
||||
"""
|
||||
# Combine cards from both sides.
|
||||
combined_cards = list(instance.have_cards.all()) + list(instance.want_cards.all())
|
||||
if not combined_cards:
|
||||
return
|
||||
|
||||
# Gather the Rarity instances from the cards.
|
||||
rarities = {card.normalized_rarity for card in combined_cards}
|
||||
rarities = {card.rarity_level for card in combined_cards}
|
||||
if len(rarities) > 1:
|
||||
raise ValidationError("All cards in a trade offer must have the same rarity.")
|
||||
|
||||
# If trade offer's rarity isn't set yet, update it.
|
||||
if instance.rarity is None:
|
||||
instance.rarity = combined_cards[0].normalized_rarity
|
||||
instance.save(update_fields=["rarity"])
|
||||
updated_fields = []
|
||||
if instance.rarity_level is None:
|
||||
instance.rarity_level = combined_cards[0].rarity_level
|
||||
updated_fields.append("rarity_level")
|
||||
if instance.rarity_icon is None:
|
||||
instance.rarity_icon = combined_cards[0].rarity_icon
|
||||
updated_fields.append("rarity_icon")
|
||||
if updated_fields:
|
||||
instance.save(update_fields=updated_fields)
|
||||
|
||||
@receiver(m2m_changed, sender=TradeOffer.have_cards.through)
|
||||
def validate_have_cards_rarity(sender, instance, action, **kwargs):
|
||||
if action == "post_add":
|
||||
validate_and_set_trade_offer_rarity(instance)
|
||||
transaction.on_commit(lambda: validate_and_set_trade_offer_rarity(instance))
|
||||
|
||||
@receiver(m2m_changed, sender=TradeOffer.want_cards.through)
|
||||
def validate_want_cards_rarity(sender, instance, action, **kwargs):
|
||||
if action == "post_add":
|
||||
validate_and_set_trade_offer_rarity(instance)
|
||||
transaction.on_commit(lambda: validate_and_set_trade_offer_rarity(instance))
|
||||
|
||||
ACTIVE_STATES = [
|
||||
TradeAcceptance.AcceptanceState.ACCEPTED,
|
||||
|
|
|
|||
|
|
@ -20,8 +20,17 @@ def render_trade_offer(context, offer):
|
|||
if card.quantity > card.qty_accepted
|
||||
]
|
||||
|
||||
acceptances = [acceptance for acceptance in list(offer.acceptances.all())
|
||||
if acceptance.is_active
|
||||
]
|
||||
|
||||
return {
|
||||
'offer': offer,
|
||||
'offer_pk': offer.pk,
|
||||
'offer_hash': offer.hash,
|
||||
'rarity_icon': offer.rarity_icon,
|
||||
'initiated_by_email': offer.initiated_by.user.email,
|
||||
'initiated_by_username': offer.initiated_by.user.username,
|
||||
'acceptances': acceptances,
|
||||
'have_cards_available': have_cards_available,
|
||||
'want_cards_available': want_cards_available,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ from .models import TradeOffer, TradeAcceptance
|
|||
from .forms import (TradeOfferAcceptForm,
|
||||
TradeAcceptanceCreateForm, TradeOfferCreateForm, TradeAcceptanceTransitionForm)
|
||||
from cards.models import Card
|
||||
from silk.profiling.profiler import silk_profile
|
||||
#from silk.profiling.profiler import silk_profile
|
||||
|
||||
class TradeOfferCreateView(LoginRequiredMixin, CreateView):
|
||||
model = TradeOffer
|
||||
|
|
@ -42,7 +42,7 @@ class TradeOfferCreateView(LoginRequiredMixin, CreateView):
|
|||
context = super().get_context_data(**kwargs)
|
||||
from cards.models import Card
|
||||
# Ensure available_cards is a proper QuerySet
|
||||
context["cards"] = Card.objects.all().order_by("name", "rarity__pk") \
|
||||
context["cards"] = Card.objects.all().order_by("name", "rarity_level") \
|
||||
.select_related("rarity", "cardset") \
|
||||
.prefetch_related("decks")
|
||||
friend_codes = self.request.user.friend_codes.all()
|
||||
|
|
@ -68,7 +68,7 @@ class TradeOfferAllListView(ListView):
|
|||
model = TradeOffer
|
||||
template_name = "trades/trade_offer_all_list.html"
|
||||
|
||||
@silk_profile(name="Trade Offer All List- Get Context Data")
|
||||
#@silk_profile(name="Trade Offer All List- Get Context Data")
|
||||
def get_context_data(self, *, object_list=None, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
request = self.request
|
||||
|
|
@ -88,14 +88,14 @@ class TradeOfferAllListView(ListView):
|
|||
context["all_trade_offers_paginated"] = offers_paginator.get_page(offers_page)
|
||||
return context
|
||||
|
||||
@silk_profile(name="Trade Offer All List- Render to Response")
|
||||
#@silk_profile(name="Trade Offer All List- Render to Response")
|
||||
def render_to_response(self, context, **response_kwargs):
|
||||
# For AJAX requests, return only the paginated fragment.
|
||||
if self.request.headers.get("X-Requested-With") == "XMLHttpRequest":
|
||||
page = self.request.GET.get("page")
|
||||
show_closed = self.request.GET.get("show_closed", "false").lower() == "true"
|
||||
|
||||
queryset = TradeOffer.objects.all()
|
||||
queryset = TradeOffer.objects
|
||||
if show_closed:
|
||||
queryset = queryset.filter(is_closed=True)
|
||||
else:
|
||||
|
|
@ -185,7 +185,7 @@ class TradeOfferMyListView(LoginRequiredMixin, ListView):
|
|||
other_acceptances = involved_acceptances.exclude(pk__in=waiting_acceptances.values("pk"))
|
||||
return Paginator(other_acceptances, 10).get_page(page_param)
|
||||
|
||||
@silk_profile(name="Trade Offer My List- Get Context Data")
|
||||
#@silk_profile(name="Trade Offer My List- Get Context Data")
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
request = self.request
|
||||
|
|
@ -206,7 +206,7 @@ class TradeOfferMyListView(LoginRequiredMixin, ListView):
|
|||
|
||||
return context
|
||||
|
||||
@silk_profile(name="Trade Offer My List- Render to Response")
|
||||
#@silk_profile(name="Trade Offer My List- Render to Response")
|
||||
def render_to_response(self, context, **response_kwargs):
|
||||
# For AJAX requests, return only the paginated fragment.
|
||||
if self.request.headers.get("X-Requested-With") == "XMLHttpRequest":
|
||||
|
|
@ -318,7 +318,7 @@ class TradeOfferSearchView(ListView):
|
|||
results.append((card_id, qty))
|
||||
return results
|
||||
|
||||
@silk_profile(name="Trade Offer Search- Get Queryset")
|
||||
#@silk_profile(name="Trade Offer Search- Get Queryset")
|
||||
def get_queryset(self):
|
||||
from django.db.models import F
|
||||
# For a GET request (initial load), return an empty queryset.
|
||||
|
|
@ -355,18 +355,17 @@ class TradeOfferSearchView(ListView):
|
|||
|
||||
return qs.distinct()
|
||||
|
||||
@silk_profile(name="Trade Offer Search- Post")
|
||||
#@silk_profile(name="Trade Offer Search- Post")
|
||||
def post(self, request, *args, **kwargs):
|
||||
# For POST, simply process the search through get().
|
||||
return self.get(request, *args, **kwargs)
|
||||
|
||||
@silk_profile(name="Trade Offer Search- Get Context Data")
|
||||
#@silk_profile(name="Trade Offer Search- Get Context Data")
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
from cards.models import Card
|
||||
# Populate available_cards to re-populate the multiselects.
|
||||
context["cards"] = Card.objects.all().order_by("name", "rarity__pk") \
|
||||
.select_related("rarity", "cardset")
|
||||
context["cards"] = Card.objects.all().order_by("name")
|
||||
if self.request.method == "POST":
|
||||
context["offered_cards"] = self.request.POST.getlist("offered_cards")
|
||||
context["wanted_cards"] = self.request.POST.getlist("wanted_cards")
|
||||
|
|
@ -375,7 +374,7 @@ class TradeOfferSearchView(ListView):
|
|||
context["wanted_cards"] = []
|
||||
return context
|
||||
|
||||
@silk_profile(name="Trade Offer Search- Render to Response")
|
||||
#@silk_profile(name="Trade Offer Search- Render to Response")
|
||||
def render_to_response(self, context, **response_kwargs):
|
||||
"""
|
||||
Render the AJAX fragment if the request is AJAX; otherwise, render the complete page.
|
||||
|
|
@ -395,7 +394,7 @@ class TradeOfferDetailView(LoginRequiredMixin, DetailView):
|
|||
model = TradeOffer
|
||||
template_name = "trades/trade_offer_detail.html"
|
||||
|
||||
@silk_profile(name="Trade Offer Detail- Get Context Data")
|
||||
#@silk_profile(name="Trade Offer Detail- Get Context Data")
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
trade_offer = self.get_object()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue