This commit is contained in:
Niko Abeler 2023-08-25 21:42:46 +02:00
parent 11292774f2
commit a9648c12b8
13 changed files with 273 additions and 8 deletions

View File

@ -1,5 +1,6 @@
from typing import Any
from django import forms
from guild.models import PlaySession, Character, Reward
from guild.models import NPC, PlaySession, Character, Reward
from django.utils.translation import gettext as _
@ -11,14 +12,22 @@ class PlaySessionCharacterForm(forms.ModelMultipleChoiceField):
return character.name
class PlaySessionNPCForm(forms.ModelMultipleChoiceField):
def label_from_instance(self, npc):
return npc.name
class PlaySessionForm(forms.ModelForm):
characters = PlaySessionCharacterForm(
queryset=Character.objects.all(), widget=forms.CheckboxSelectMultiple
)
npcs = PlaySessionNPCForm(
queryset=NPC.objects.all(), widget=forms.CheckboxSelectMultiple, required=False
)
class Meta:
model = PlaySession
fields = ["date", "characters", "summary"]
fields = ["date", "characters", "summary", "npcs"]
# set date wideget to type="date"
widgets = {
"date": forms.DateInput(attrs={"type": "date"}),

View File

@ -0,0 +1,54 @@
# Generated by Django 4.2.1 on 2023-08-25 18:41
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("guild", "0012_alter_character_options_alter_character_picture"),
]
operations = [
migrations.CreateModel(
name="NPC",
fields=[
(
"id",
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("name", models.CharField(max_length=255)),
("description", models.TextField()),
(
"picture",
models.ImageField(
blank=True,
null=True,
upload_to="uploads/",
verbose_name="NPC Picture",
),
),
(
"created_at",
models.DateTimeField(auto_now_add=True, verbose_name="created at"),
),
(
"updated_at",
models.DateTimeField(auto_now=True, verbose_name="updated at"),
),
],
options={
"verbose_name": "npc",
"verbose_name_plural": "npcs",
},
),
migrations.AddField(
model_name="playsession",
name="npcs",
field=models.ManyToManyField(to="guild.npc", verbose_name="npcs"),
),
]

View File

@ -0,0 +1,19 @@
# Generated by Django 4.2.1 on 2023-08-25 18:52
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("guild", "0013_npc_playsession_npcs"),
]
operations = [
migrations.AlterField(
model_name="playsession",
name="npcs",
field=models.ManyToManyField(
blank=True, to="guild.npc", verbose_name="npcs"
),
),
]

View File

@ -116,6 +116,7 @@ class PlaySession(models.Model):
"Adventure", verbose_name=_("adventure"), on_delete=models.CASCADE
)
characters = models.ManyToManyField("Character", verbose_name=_("characters"))
npcs = models.ManyToManyField("NPC", verbose_name=_("npcs"), blank=True)
summary = models.TextField()
@ -199,3 +200,25 @@ class Reward(models.Model):
def get_absolute_url(self):
return reverse("guild:reward_detail", kwargs={"pk": self.pk})
class NPC(models.Model):
name = models.CharField(max_length=255)
description = models.TextField()
picture = models.ImageField(
_("NPC Picture"), null=True, blank=True, upload_to="uploads/"
)
created_at = models.DateTimeField(_("created at"), auto_now_add=True)
updated_at = models.DateTimeField(_("updated at"), auto_now=True)
class Meta:
verbose_name = _("npc")
verbose_name_plural = _("npcs")
def __str__(self):
return self.name
def get_absolute_url(self):
return reverse("guild:npc_detail", kwargs={"pk": self.pk})

View File

@ -8,11 +8,13 @@
<div class="column column-75">
<hrgroup>
<h1>Adventure: {{ adventure.name }}</h1>
<h4>Mastered by:
<a href="{% url 'guild:player_detail' adventure.master.id %}">
{{ adventure.master }}
</a>
</h4>
{% if adventure.master %}
<h4>Mastered by:
<a href="{% url 'guild:player_detail' adventure.master.id %}">
{{ adventure.master }}
</a>
</h4>
{% endif %}
</hrgroup>
</div>
<div class="column">

View File

@ -55,6 +55,25 @@
{% endfor %}
</ul>
<div class="row">
<div class="column column-75">
<h2>NPCs</h2>
</div>
<div class="column column-25">
<a class="button button-outline" href="{% url 'guild:create_npc' %}">Create New NPC</a>
</div>
</div>
<ul>
{% for npc in npcs %}
<li>
<a href="{% url 'guild:npc_detail' npc.id %}">
{{ npc.name }}
</a>
</li>
{% endfor %}
</ul>
<div class="row">
<div class="column column-75">
<h2>Players</h2>

View File

@ -0,0 +1,14 @@
{% extends 'base.html' %}
{% block content %}
<h1>Session Delete</h1>
<p>Are you sure you want to delete <strong>{{ character.name}}</strong>?</p>
<form action="" method="post">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Delete Character">
</form>
{% endblock content %}

View File

@ -0,0 +1,52 @@
{% extends 'base.html' %}
{% load guild_extras %}
{% block content %}
<div class="row">
<div class="column column-75">
<hrgroup>
<h1>NPCs: {{ npc.name }}</h1>
<h4>
{{ npc.get_status_display }}
</h4>
</hrgroup>
</div>
<div class="column">
<a class="button button-outline" href="{% url 'guild:npc_update' npc.id %}">Edit</a>
</div>
<div class="column">
<a class="button button-clear" href="{% url 'guild:npc_delete' npc.id %}">Delete</a>
</div>
</div>
<div class="row">
</div>
{% if npc.picture %}
<a href="{{npc.picture.url}}" style="float:left;margin-right:10px;margin-bottom:10px;">
<img src="{{npc.picture.url}}" width="300"/>
</a>
{% endif %}
<p>{{npc.description|md|safe}}</p>
<div class="column">
</div>
<br>
<h2>Session History</h2>
{% if not npc.playsession_set.count %}
<p>No appearance yet.</p>
{% else %}
<ul>
{% for session in npc.playsession_set.all %}
<li>
<a href="{% url 'guild:adventure_detail' session.adventure.id %}">
{{session.date}} - {{ session.adventure.name }}
</a></li>
{% endfor %}
</ul>
{% endif %}
{% endblock content %}

View File

@ -0,0 +1,13 @@
{% extends 'base.html' %}
{% block content %}
<form action="" method="post" enctype="multipart/form-data" >
{% csrf_token %}
{{ form.as_p }}
{% if object %}
<input type="submit" value="Update NPC">
{% else %}
<input type="submit" value="Create NPC">
{% endif %}
</form>
{% endblock content %}

View File

@ -74,4 +74,14 @@
<p>{{playsession.summary|md|safe}}</p>
<h3>NPC Appearances</h3>
<ul>
{% for npc in playsession.npcs.all %}
<li><a href="{% url 'guild:npc_detail' npc.id %}">{{ npc.name }}</a></li>
{% endfor %}
</ul>
{% endblock content %}

View File

@ -2,6 +2,7 @@ from django.urls import path
import guild.views as views
import guild.views.player as player_views
import guild.views.character as character_views
import guild.views.npc as npc_views
import guild.views.adventure as adventure_views
import guild.views.playsession as playsession_views
import guild.views.settings as settings_views
@ -137,4 +138,24 @@ urlpatterns = [
resource_views.ResourceUpdateView.as_view(),
name="resource_update",
),
path(
"npcs/create/",
npc_views.CreateNPCView.as_view(),
name="create_npc",
),
path(
"npcs/<int:pk>/",
npc_views.NPCDetailView.as_view(),
name="npc_detail",
),
path(
"npcs/<int:pk>/update/",
npc_views.NPCUpdateView.as_view(),
name="npc_update",
),
path(
"npcs/<int:pk>/delete/",
npc_views.NPCDeleteView.as_view(),
name="npc_delete",
),
]

View File

@ -5,7 +5,7 @@ from django.views.generic.edit import CreateView
from django.contrib.auth.mixins import LoginRequiredMixin
from django.contrib.auth.models import User
from django.contrib.auth.forms import UserCreationForm
from guild.models import Adventure, Character, Player, Reward
from guild.models import NPC, Adventure, Character, Player, Reward
# Create your views here.
@ -23,6 +23,7 @@ class HomeView(LoginRequiredMixin, TemplateView):
context["adventures"] = advs
context["players"] = Player.objects.all()
context["characters"] = Character.objects.all()
context["npcs"] = NPC.objects.all()
context["rewards"] = Reward.objects.filter(character=None).order_by(
"-playsession__date"

28
guild/views/npc.py Normal file
View File

@ -0,0 +1,28 @@
from django.views.generic import TemplateView, ListView, DetailView
from django.views.generic.edit import CreateView, UpdateView, DeleteView
from django.contrib.auth.mixins import LoginRequiredMixin
from guild.models import NPC
class NPCListView(LoginRequiredMixin, ListView):
model = NPC
context_object_name = "NPCs"
class CreateNPCView(LoginRequiredMixin, CreateView):
model = NPC
fields = ["name", "picture", "description"]
class NPCDetailView(LoginRequiredMixin, DetailView):
model = NPC
class NPCUpdateView(LoginRequiredMixin, UpdateView):
model = NPC
fields = ["name", "picture", "description"]
class NPCDeleteView(LoginRequiredMixin, DeleteView):
model = NPC
success_url = "/"