Skip to content

Games ~ BoardGameGeek (BGG) API Demo Page

Owen Fahey edited this page Nov 27, 2023 · 4 revisions

The code in this wiki page has been integrated in the codebase. Some issues link to this page and BGG autofilling is still being developed so we will keep it around for a bit longer.

Related:

  1. Issue here
  2. Wiki page with BGG API documentation here

This code implements two BGG API calls:

  1. Gets all games that match an exact query
  2. Gets game details for those games.

This is code to designed integrated into the Create Game Page in the future. We decided to put it here in order to avoid dangling branches.

src/chigame/games/forms.py

from django import forms

class BGGSearchForm(forms.Form):
    bgg_search_term = forms.CharField(label='Search BoardGameGeek', max_length=100)

src/chigame/games/views.py:

from .forms import BGGSearchForm
from django.shortcuts import render
from django.views.generic import ListView
import requests
import xml.etree.ElementTree as ET
BGG_BASE_URL = "https://www.boardgamegeek.com/xmlapi2/"

# Takes a string and displays information about Board Games with title that exactly match the string via the Board Game Geek API.
# Renders a page where the specific game can be selected and its details viewed.
# This view is for demonstration purposes. Eventualy, it will be incorporated into the create game view.
def bgg_search_view(request):
    games_list = []
    form = BGGSearchForm()

    if request.method == 'POST':
        form = BGGSearchForm(request.POST)
        if form.is_valid():
            search_term = form.cleaned_data['bgg_search_term']
            url = f"{BGG_BASE_URL}search?type=boardgame&query={search_term}&exact=1"
            response = requests.get(url)
            root = ET.fromstring(response.text)

            for game in root.findall(".//item"):
                game_id = game.get("id")
                details_url = f"{BGG_BASE_URL}thing?id={game_id}&stats=1"
                details_response = requests.get(details_url)
                details_root = ET.fromstring(details_response.text)

                game_data = {
                    "id": game_id,
                    "name": details_root.find(".//name").get("value"),
                    "image": details_root.find(".//image").text,
                    "description": details_root.find(".//description").text,
                    "yearpublished": details_root.find(".//yearpublished").get("value"),
                    "boardgamepublishers": [publisher.get("value") for publisher in details_root.findall(".//link[@type='boardgamepublisher']")],
                    "minplaytime": details_root.find(".//minplaytime").get("value"),
                    "maxplaytime": details_root.find(".//maxplaytime").get("value"),
                }

                games_list.append(game_data)

    return render(request, 'games/search_results.html', {'form': form, 'games_list': games_list})

src/templates/games/search_results.html

{% extends "base.html" %}

{% block title %}
BGG API CALL Demo
{% endblock title %}

{% block css %}
{{ block.super }} <!-- This will inherit the styles from the base.html -->
<style>
    body {
        font-family: Arial, sans-serif;
        margin: 20px;
    }

    form {
        margin-bottom: 20px;
    }

    img {
        max-width: 100px;
        margin: 10px 0;
    }

    .game-item {
        border: 1px solid #e1e1e1;
        padding: 15px;
        margin: 10px 0;
        border-radius: 5px;
        display: flex;
        align-items: center;
    }

    .game-image {
        max-width: 200px;
        margin-right: 20px;
        border-radius: 10px;
        box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
    }

    .game-details {
        flex-grow: 1;
    }

    .game-description {
        text-align: justify;
        margin-top: 10px;
    }
</style>
{% endblock %}

{% block content %}

<form method="post">
    {% csrf_token %}
    {{ form.as_p }}
    <button type="submit">Search on BoardGameGeek</button>
</form>

{% if games_list %}
<h2>Matching Games:</h2>
{% for game in games_list %}
<div class="game-item">
    <img class="game-image" src="{{ game.image }}" alt="{{ game.name }}">
    <div class="game-details">
        <h3>{{ game.name }} (ID: {{ game.id }})</h3>
        <p class="game-description">{{ game.description|escape|safe|linebreaks }}</p>
        <p><strong>Year Published:</strong> {{ game.yearpublished }}</p>
        <p>
        <strong>Publishers:</strong>
        {% for publisher in game.boardgamepublishers %}
            {{ publisher }}{% if not forloop.last %}, {% endif %}
        {% endfor %}
        </p>
        <p><strong>Minimum Playtime:</strong> {{ game.minplaytime }} minutes</p>
        <p><strong>Maximum Playtime:</strong> {{ game.maxplaytime }} minutes</p>
    </div>
</div>
{% endfor %}
{% endif %}

{% endblock content %}
Clone this wiki locally