Create and upload image of your dnd characters and search for spells and see spell details for each spell
I love dnd and this is going to be an on going project to develop a better dnd app for personal use
PolyWox's App of Arcane Arrangement
Trello Board
dnd5eapi
python
Django
CSS
DTL
AWS S3
- upload an image using amazon s3 buckets
- add class features
- update spell slots
- add more spell details
template:
{% extends 'base.html' %}
{% load static %}
{% block head %}
<link
rel="stylesheet"
type="text/css"
href="{% static 'css/character-detail.css' %}"
/>
<script defer src="{% static 'js/character-detail.js' %}"></script>
{% endblock %}
{% block content %}
<section class="character-container">
<div class="character-img">
{% if character.photo.url %}
<img src="{{character.photo.url}}" alt="A photo of {{character.name}}" class='usr-img'
>
{% else %}
<img
src="{% static 'images/character_placeholder.png' %}"
alt="Sillouette of a Character"
class='usr-img'
>
{% endif %}
</div>
<div class="character-details">
<h1>{{ character.name }}</h1>
<p>{{ character.char_class }}</p>
<p>{{ character.level }}</p>
<div class="character-actions">
<a href="{% url 'characters_update' character.id %}" class="btn warn">Edit</a>
<a href="{% url 'characters_delete' character.id %}" class="btn danger">Delete</a>
</div>
{% comment %} New markup below {% endcomment %}
<h3>Change {{ character.name }}'s photo</h3>
<p id="file-name"></p>
<form
action="{% url 'add_photo' character.id %}"
enctype="multipart/form-data"
method="POST"
>
{% csrf_token %}
<label class="btn secondary">
Choose photo
<input type="file" name="photo-file" id="file-input">
</label>
<button type="submit" class="btn submit">Upload Photo</button>
</form>
{% comment %} New markup above {% endcomment %}
</div>
</section>
<section class="spells">
<div class="subsection-title">
<h2>Spells</h2>
<img src="{% static 'images/'%}{{character.char_class}}.png" />
</div>
<h3>{{ character.name }}'s Learned Spells</h3>
<div class="subsection-content">
{% if character.spell_list.count %}
{% for spell in character.spell_list.all %}
<div class="spell-container">
<div
class="color-block"
></div>
<a href="{% url 'spells_detail' spell.id %}">
<p> {{ spell.name }}</p>
</a>
</div>
{% endfor %}
{% else %}
<p class="no-spells">{{character.name}} doesn't have any spells 😞</p>
{% endif %}
</div>
<h3>Available Spells</h3>
<div class="subsection-content">
{% comment %} We'll display learned_spells here {% endcomment %}
{% if spells.count %}
{% for spell in spells.all %}
<div class="spell-container">
<div
class="color-block"
></div>
<a href="{% url 'spells_detail' spell.id %}">
<p>{{ spell.name }}</p>
</a>
<form action="{% url 'assoc_spell' character.id spell.id %}" method="post">
{% csrf_token %}
<button type="submit" class="btn submit">Learn Spell</button>
</form>
</div>
{% endfor %}
{% else %}
<p class="all-spells">
{{character.name}} already has learned all the available spells 🥳
</p>
{% endif %}
<form action={% url 'spells_create' character.id %} method="GET">
<button type="submit" class="btn submit" >Search Spell</button>
</form>
</div>
</section>
</div>
</div>
{% endblock %}
view:
@login_required
def spell_details(request, spell_id):
spell = Spell.objects.get(id=spell_id)
response = requests.get(f"{API_BASE_URL}{spell.url}")
spelldata = response.json()
print(spelldata)
return render(request, 'main_app/spell_detail.html', {
"name": spelldata['name'], "level": spelldata['level'], 'desc': spelldata['desc'], 'range': spelldata['range'], 'duration': spelldata['duration'], 'casting_time': spelldata['casting_time'],
})
class Spell(models.Model):
name = models.CharField(max_length=250)
url = models.CharField(max_length=250)
def __str__(self):
return self.name
def get_absolute_url(self):
return reverse("spells_detail", kwargs={"spell_id": self.id})
class Character(models.Model):
player = models.ForeignKey(User, on_delete=models.CASCADE)
name = models.CharField(max_length=50)
char_class = models.CharField(max_length=9,
choices=CLASS_CHOICE,
default=CLASS_CHOICE[0][0]
)
level = models.IntegerField(
default=1,
validators=[MaxValueValidator(20), MinValueValidator(1)]
)
spell_list = models.ManyToManyField(Spell, blank=True)
def __str__(self):
return self.name
def get_absolute_url(self):
return reverse("characters_detail", kwargs={"character_id": self.id})
css inpired by David Stinson
Ben Manley
Aftin Combs for the icons
Blake Romano
David Nagarpowers
Chitra Son
Nicholas Rodriguez
Damien Rhodes