diff --git a/games/templates/view_purchase.html b/games/templates/view_purchase.html
new file mode 100644
index 0000000..aa3290f
--- /dev/null
+++ b/games/templates/view_purchase.html
@@ -0,0 +1,34 @@
+
+    
+    
+    
+    
+        {% if purchase.name %}{{ purchase.name }}{% else %}Unnamed purchase{% endif %} ({{ purchase.editions.count }} games)
+    
+    
+    
Price: {{ purchase.converted_price | floatformat }} {{ purchase.converted_currency }} ({{ purchase.price | floatformat }} {{ purchase.price_currency }})
+    
+        
Items:
+        
+        {% for edition in purchase.editions.all %}
+         
+        {% endfor %}
+        
+    
+    
+
 
+
+
diff --git a/games/urls.py b/games/urls.py
index 946b64d..ccb398f 100644
--- a/games/urls.py
+++ b/games/urls.py
@@ -54,6 +54,11 @@ urlpatterns = [
         purchase.delete_purchase,
         name="delete_purchase",
     ),
+    path(
+        "purchase/
/view",
+        purchase.view_purchase,
+        name="view_purchase",
+    ),
     path(
         "purchase//finish",
         purchase.finish_purchase,
diff --git a/games/views/game.py b/games/views/game.py
index d55fb14..0aac65c 100644
--- a/games/views/game.py
+++ b/games/views/game.py
@@ -13,6 +13,7 @@ from common.components import (
     Button,
     Div,
     Icon,
+    LinkedPurchase,
     NameWithPlatformIcon,
     Popover,
     PopoverTruncated,
@@ -162,7 +163,7 @@ def view_game(request: HttpRequest, game_id: int) -> HttpResponse:
         to_attr="nongame_related_purchases",
     )
     game_purchases_prefetch: Prefetch[Purchase] = Prefetch(
-        "purchase_set",
+        "purchases",
         queryset=Purchase.objects.filter(type=Purchase.GAME).prefetch_related(
             nongame_related_purchases_prefetch
         ),
@@ -174,14 +175,14 @@ def view_game(request: HttpRequest, game_id: int) -> HttpResponse:
         .order_by("year_released")
     )
 
-    purchases = Purchase.objects.filter(edition__game=game).order_by("date_purchased")
+    purchases = Purchase.objects.filter(editions__game=game).order_by("date_purchased")
 
     sessions = Session.objects.prefetch_related("device").filter(
-        purchase__edition__game=game
+        purchase__editions__game=game
     )
     session_count = sessions.count()
     session_count_without_manual = (
-        Session.objects.without_manual().filter(purchase__edition__game=game).count()
+        Session.objects.without_manual().filter(purchase__editions__game=game).count()
     )
 
     if sessions:
@@ -242,10 +243,7 @@ def view_game(request: HttpRequest, game_id: int) -> HttpResponse:
         "columns": ["Name", "Type", "Date", "Price", "Actions"],
         "rows": [
             [
-                NameWithPlatformIcon(
-                    name=purchase.name if purchase.name else purchase.edition.name,
-                    platform=purchase.platform,
-                ),
+                LinkedPurchase(purchase),
                 purchase.get_type_display(),
                 purchase.date_purchased.strftime(dateformat),
                 PurchasePrice(purchase),
@@ -271,7 +269,7 @@ def view_game(request: HttpRequest, game_id: int) -> HttpResponse:
         ],
     }
 
-    sessions_all = Session.objects.filter(purchase__edition__game=game).order_by(
+    sessions_all = Session.objects.filter(purchase__editions__game=game).order_by(
         "-timestamp_start"
     )
     last_session = None
@@ -300,7 +298,7 @@ def view_game(request: HttpRequest, game_id: int) -> HttpResponse:
                         args=[last_session.pk],
                     ),
                     children=Popover(
-                        popover_content=last_session.purchase.edition.name,
+                        popover_content=last_session.purchase.first_edition.name,
                         children=[
                             Button(
                                 icon=True,
@@ -308,7 +306,9 @@ def view_game(request: HttpRequest, game_id: int) -> HttpResponse:
                                 size="xs",
                                 children=[
                                     Icon("play"),
-                                    truncate(f"{last_session.purchase.edition.name}"),
+                                    truncate(
+                                        f"{last_session.purchase.first_edition.name}"
+                                    ),
                                 ],
                             )
                         ],
@@ -324,7 +324,7 @@ def view_game(request: HttpRequest, game_id: int) -> HttpResponse:
                 NameWithPlatformIcon(
                     name=session.purchase.name
                     if session.purchase.name
-                    else session.purchase.edition.name,
+                    else session.purchase.first_edition.name,
                     platform=session.purchase.platform,
                 ),
                 f"{local_strftime(session.timestamp_start)}{f" — {local_strftime(session.timestamp_end, timeformat)}" if session.timestamp_end else ""}",
@@ -375,7 +375,7 @@ def view_game(request: HttpRequest, game_id: int) -> HttpResponse:
         "editions": editions,
         "game": game,
         "playrange": playrange,
-        "purchase_count": Purchase.objects.filter(edition__game=game).count(),
+        "purchase_count": Purchase.objects.filter(editions__game=game).count(),
         "session_average_without_manual": round(
             safe_division(
                 total_hours_without_manual, int(session_count_without_manual)
diff --git a/games/views/general.py b/games/views/general.py
index 3ca554e..4834046 100644
--- a/games/views/general.py
+++ b/games/views/general.py
@@ -2,7 +2,7 @@ from datetime import datetime
 from typing import Any, Callable
 
 from django.contrib.auth.decorators import login_required
-from django.db.models import Avg, Count, ExpressionWrapper, F, Q, Sum, fields
+from django.db.models import Avg, Count, ExpressionWrapper, F, Prefetch, Q, Sum, fields
 from django.db.models.functions import TruncDate, TruncMonth
 from django.db.models.manager import BaseManager
 from django.http import HttpRequest, HttpResponse, HttpResponseRedirect
@@ -49,7 +49,9 @@ def use_custom_redirect(
 @login_required
 def stats_alltime(request: HttpRequest) -> HttpResponse:
     year = "Alltime"
-    this_year_sessions = Session.objects.all().select_related("purchase__edition")
+    this_year_sessions = Session.objects.all().prefetch_related(
+        Prefetch("purchase__editions")
+    )
     this_year_sessions_with_durations = this_year_sessions.annotate(
         duration=ExpressionWrapper(
             F("timestamp_end") - F("timestamp_start"),
@@ -58,10 +60,10 @@ def stats_alltime(request: HttpRequest) -> HttpResponse:
     )
     longest_session = this_year_sessions_with_durations.order_by("-duration").first()
     this_year_games = Game.objects.filter(
-        edition__purchase__session__in=this_year_sessions
+        editions__purchase__session__in=this_year_sessions
     ).distinct()
     this_year_games_with_session_counts = this_year_games.annotate(
-        session_count=Count("edition__purchase__session"),
+        session_count=Count("editions__purchase__session"),
     )
     game_highest_session_count = this_year_games_with_session_counts.order_by(
         "-session_count"
@@ -78,7 +80,7 @@ def stats_alltime(request: HttpRequest) -> HttpResponse:
     ).distinct()
 
     this_year_purchases = Purchase.objects.all()
-    this_year_purchases_with_currency = this_year_purchases.select_related("edition")
+    this_year_purchases_with_currency = this_year_purchases.select_related("editions")
     this_year_purchases_without_refunded = this_year_purchases_with_currency.filter(
         date_refunded=None
     )
@@ -127,11 +129,11 @@ def stats_alltime(request: HttpRequest) -> HttpResponse:
     total_spent = this_year_spendings["total_spent"] or 0
 
     games_with_playtime = (
-        Game.objects.filter(edition__purchase__session__in=this_year_sessions)
+        Game.objects.filter(editions__purchase__session__in=this_year_sessions)
         .annotate(
             total_playtime=Sum(
-                F("edition__purchase__session__duration_calculated")
-                + F("edition__purchase__session__duration_manual")
+                F("editions__purchase__session__duration_calculated")
+                + F("editions__purchase__session__duration_manual")
             )
         )
         .values("id", "name", "total_playtime")
@@ -146,9 +148,9 @@ def stats_alltime(request: HttpRequest) -> HttpResponse:
         month["playtime"] = format_duration(month["playtime"], "%2.0H")
 
     highest_session_average_game = (
-        Game.objects.filter(edition__purchase__session__in=this_year_sessions)
+        Game.objects.filter(editions__purchase__session__in=this_year_sessions)
         .annotate(
-            session_average=Avg("edition__purchase__session__duration_calculated")
+            session_average=Avg("editions__purchase__session__duration_calculated")
         )
         .order_by("-session_average")
         .first()
@@ -175,10 +177,10 @@ def stats_alltime(request: HttpRequest) -> HttpResponse:
     last_play_date = "N/A"
     if this_year_sessions:
         first_session = this_year_sessions.earliest()
-        first_play_game = first_session.purchase.edition.game
+        first_play_game = first_session.purchase.first_edition.game
         first_play_date = first_session.timestamp_start.strftime(dateformat)
         last_session = this_year_sessions.latest()
-        last_play_game = last_session.purchase.edition.game
+        last_play_game = last_session.purchase.first_edition.game
         last_play_date = last_session.timestamp_start.strftime(dateformat)
 
     all_purchased_this_year_count = this_year_purchases_with_currency.count()
@@ -227,7 +229,7 @@ def stats_alltime(request: HttpRequest) -> HttpResponse:
             else 0
         ),
         "longest_session_game": (
-            longest_session.purchase.edition.game if longest_session else None
+            longest_session.purchase.first_edition.game if longest_session else None
         ),
         "highest_session_count": (
             game_highest_session_count.session_count
@@ -266,7 +268,7 @@ def stats(request: HttpRequest, year: int = 0) -> HttpResponse:
         return HttpResponseRedirect(reverse("stats_alltime"))
     this_year_sessions = Session.objects.filter(
         timestamp_start__year=year
-    ).select_related("purchase__edition")
+    ).prefetch_related("purchase__editions")
     this_year_sessions_with_durations = this_year_sessions.annotate(
         duration=ExpressionWrapper(
             F("timestamp_end") - F("timestamp_start"),
@@ -275,12 +277,12 @@ def stats(request: HttpRequest, year: int = 0) -> HttpResponse:
     )
     longest_session = this_year_sessions_with_durations.order_by("-duration").first()
     this_year_games = Game.objects.filter(
-        edition__purchase__session__in=this_year_sessions
+        edition__purchases__session__in=this_year_sessions
     ).distinct()
     this_year_games_with_session_counts = this_year_games.annotate(
         session_count=Count(
-            "edition__purchase__session",
-            filter=Q(edition__purchase__session__timestamp_start__year=year),
+            "edition__purchases__session",
+            filter=Q(edition__purchases__session__timestamp_start__year=year),
         )
     )
     game_highest_session_count = this_year_games_with_session_counts.order_by(
@@ -298,7 +300,7 @@ def stats(request: HttpRequest, year: int = 0) -> HttpResponse:
     ).distinct()
 
     this_year_purchases = Purchase.objects.filter(date_purchased__year=year)
-    this_year_purchases_with_currency = this_year_purchases.select_related("edition")
+    this_year_purchases_with_currency = this_year_purchases.prefetch_related("editions")
     this_year_purchases_without_refunded = this_year_purchases_with_currency.filter(
         date_refunded=None
     ).exclude(ownership_type=Purchase.DEMO)
@@ -335,7 +337,7 @@ def stats(request: HttpRequest, year: int = 0) -> HttpResponse:
 
     purchases_finished_this_year = Purchase.objects.filter(date_finished__year=year)
     purchases_finished_this_year_released_this_year = (
-        purchases_finished_this_year.filter(edition__year_released=year).order_by(
+        purchases_finished_this_year.filter(editions__year_released=year).order_by(
             "date_finished"
         )
     )
@@ -349,11 +351,11 @@ def stats(request: HttpRequest, year: int = 0) -> HttpResponse:
     total_spent = this_year_spendings["total_spent"] or 0
 
     games_with_playtime = (
-        Game.objects.filter(edition__purchase__session__in=this_year_sessions)
+        Game.objects.filter(edition__purchases__session__in=this_year_sessions)
         .annotate(
             total_playtime=Sum(
-                F("edition__purchase__session__duration_calculated")
-                + F("edition__purchase__session__duration_manual")
+                F("edition__purchases__session__duration_calculated")
+                + F("edition__purchases__session__duration_manual")
             )
         )
         .values("id", "name", "total_playtime")
@@ -368,9 +370,9 @@ def stats(request: HttpRequest, year: int = 0) -> HttpResponse:
         month["playtime"] = format_duration(month["playtime"], "%2.0H")
 
     highest_session_average_game = (
-        Game.objects.filter(edition__purchase__session__in=this_year_sessions)
+        Game.objects.filter(edition__purchases__session__in=this_year_sessions)
         .annotate(
-            session_average=Avg("edition__purchase__session__duration_calculated")
+            session_average=Avg("edition__purchases__session__duration_calculated")
         )
         .order_by("-session_average")
         .first()
@@ -401,10 +403,10 @@ def stats(request: HttpRequest, year: int = 0) -> HttpResponse:
     last_play_game = None
     if this_year_sessions:
         first_session = this_year_sessions.earliest()
-        first_play_game = first_session.purchase.edition.game
+        first_play_game = first_session.purchase.first_edition.game
         first_play_date = first_session.timestamp_start.strftime(dateformat)
         last_session = this_year_sessions.latest()
-        last_play_game = last_session.purchase.edition.game
+        last_play_game = last_session.purchase.first_edition.game
         last_play_date = last_session.timestamp_start.strftime(dateformat)
 
     all_purchased_this_year_count = this_year_purchases_with_currency.count()
@@ -421,7 +423,7 @@ def stats(request: HttpRequest, year: int = 0) -> HttpResponse:
         ),
         "total_games": this_year_played_purchases.count(),
         "total_2023_games": this_year_played_purchases.filter(
-            edition__year_released=year
+            editions__year_released=year
         ).count(),
         "top_10_games_by_playtime": top_10_games_by_playtime,
         "year": year,
@@ -432,16 +434,16 @@ def stats(request: HttpRequest, year: int = 0) -> HttpResponse:
         "spent_per_game": int(
             safe_division(total_spent, this_year_purchases_without_refunded_count)
         ),
-        "all_finished_this_year": purchases_finished_this_year.select_related(
-            "edition"
+        "all_finished_this_year": purchases_finished_this_year.prefetch_related(
+            "editions"
         ).order_by("date_finished"),
         "all_finished_this_year_count": purchases_finished_this_year.count(),
-        "this_year_finished_this_year": purchases_finished_this_year_released_this_year.select_related(
-            "edition"
+        "this_year_finished_this_year": purchases_finished_this_year_released_this_year.prefetch_related(
+            "editions"
         ).order_by("date_finished"),
         "this_year_finished_this_year_count": purchases_finished_this_year_released_this_year.count(),
-        "purchased_this_year_finished_this_year": purchased_this_year_finished_this_year.select_related(
-            "edition"
+        "purchased_this_year_finished_this_year": purchased_this_year_finished_this_year.prefetch_related(
+            "editions"
         ).order_by("date_finished"),
         "total_sessions": this_year_sessions.count(),
         "unique_days": unique_days["dates"],
@@ -471,7 +473,7 @@ def stats(request: HttpRequest, year: int = 0) -> HttpResponse:
             else 0
         ),
         "longest_session_game": (
-            longest_session.purchase.edition.game if longest_session else None
+            longest_session.purchase.first_edition.game if longest_session else None
         ),
         "highest_session_count": (
             game_highest_session_count.session_count
diff --git a/games/views/purchase.py b/games/views/purchase.py
index 9191925..daa6424 100644
--- a/games/views/purchase.py
+++ b/games/views/purchase.py
@@ -13,7 +13,7 @@ from django.template.loader import render_to_string
 from django.urls import reverse
 from django.utils import timezone
 
-from common.components import A, Button, Icon, LinkedNameWithPlatformIcon, PurchasePrice
+from common.components import A, Button, Icon, LinkedPurchase, PurchasePrice
 from common.time import dateformat
 from games.forms import PurchaseForm
 from games.models import Edition, Purchase
@@ -58,11 +58,7 @@ def list_purchases(request: HttpRequest) -> HttpResponse:
             ],
             "rows": [
                 [
-                    LinkedNameWithPlatformIcon(
-                        name=purchase.edition.name,
-                        game_id=purchase.edition.game.pk,
-                        platform=purchase.platform,
-                    ),
+                    LinkedPurchase(purchase),
                     purchase.get_type_display(),
                     PurchasePrice(purchase),
                     purchase.infinite,
@@ -173,7 +169,7 @@ def add_purchase(request: HttpRequest, edition_id: int = 0) -> HttpResponse:
 
     context["form"] = form
     context["title"] = "Add New Purchase"
-    context["script_name"] = "add_purchase.js"
+    # context["script_name"] = "add_purchase.js"
     return render(request, "add_purchase.html", context)
 
 
@@ -189,7 +185,7 @@ def edit_purchase(request: HttpRequest, purchase_id: int) -> HttpResponse:
     context["title"] = "Edit Purchase"
     context["form"] = form
     context["purchase_id"] = str(purchase_id)
-    context["script_name"] = "add_purchase.js"
+    # context["script_name"] = "add_purchase.js"
     return render(request, "add_purchase.html", context)
 
 
@@ -200,6 +196,12 @@ def delete_purchase(request: HttpRequest, purchase_id: int) -> HttpResponse:
     return redirect("list_purchases")
 
 
+@login_required
+def view_purchase(request: HttpRequest, purchase_id: int) -> HttpResponse:
+    purchase = get_object_or_404(Purchase, id=purchase_id)
+    return render(request, "view_purchase.html", {"purchase": purchase})
+
+
 @login_required
 def drop_purchase(request: HttpRequest, purchase_id: int) -> HttpResponse:
     purchase = get_object_or_404(Purchase, id=purchase_id)
diff --git a/games/views/session.py b/games/views/session.py
index 0c38eb3..f886a9b 100644
--- a/games/views/session.py
+++ b/games/views/session.py
@@ -97,7 +97,7 @@ def list_sessions(request: HttpRequest, search_string: str = "") -> HttpResponse
                                     args=[last_session.pk],
                                 ),
                                 children=Popover(
-                                    popover_content=last_session.purchase.edition.name,
+                                    popover_content=last_session.purchase.first_edition.name,
                                     children=[
                                         Button(
                                             icon=True,
@@ -106,7 +106,7 @@ def list_sessions(request: HttpRequest, search_string: str = "") -> HttpResponse
                                             children=[
                                                 Icon("play"),
                                                 truncate(
-                                                    f"{last_session.purchase.edition.name}"
+                                                    f"{last_session.purchase.first_edition.name}"
                                                 ),
                                             ],
                                         )
@@ -131,8 +131,8 @@ def list_sessions(request: HttpRequest, search_string: str = "") -> HttpResponse
             "rows": [
                 [
                     LinkedNameWithPlatformIcon(
-                        name=session.purchase.edition.name,
-                        game_id=session.purchase.edition.game.pk,
+                        name=session.purchase.first_edition.name,
+                        game_id=session.purchase.first_edition.game.pk,
                         platform=session.purchase.platform,
                     ),
                     f"{local_strftime(session.timestamp_start)}{f" — {local_strftime(session.timestamp_end, timeformat)}" if session.timestamp_end else ""}",