mirror of
https://github.com/Crocmagnon/charasheet.git
synced 2024-11-26 08:28:04 +01:00
Add parties
This commit is contained in:
parent
a8f7d04bdf
commit
596dd59780
12 changed files with 242 additions and 29 deletions
|
@ -105,6 +105,11 @@ class CharacterAdminForm(ModelForm):
|
|||
].queryset = models.RacialCapability.objects.select_related("race")
|
||||
|
||||
|
||||
class PartyInline(admin.TabularInline):
|
||||
model = models.Character.parties.through
|
||||
extra = 0
|
||||
|
||||
|
||||
@admin.register(models.Character)
|
||||
class CharacterAdmin(admin.ModelAdmin):
|
||||
list_display = ["name", "player", "race", "profile", "level"]
|
||||
|
@ -185,6 +190,7 @@ class CharacterAdmin(admin.ModelAdmin):
|
|||
"weapons",
|
||||
"states",
|
||||
]
|
||||
inlines = [PartyInline]
|
||||
|
||||
form = CharacterAdminForm
|
||||
|
||||
|
@ -204,3 +210,9 @@ class WeaponAdmin(admin.ModelAdmin):
|
|||
class HarmfulStateAdmin(admin.ModelAdmin):
|
||||
list_display = ["name", "description"]
|
||||
search_fields = ["name"]
|
||||
|
||||
|
||||
@admin.register(models.Party)
|
||||
class PartyAdmin(admin.ModelAdmin):
|
||||
list_display = ["name", "game_master"]
|
||||
search_fields = ["name"]
|
||||
|
|
68
src/character/migrations/0033_party.py
Normal file
68
src/character/migrations/0033_party.py
Normal file
|
@ -0,0 +1,68 @@
|
|||
# Generated by Django 4.1.2 on 2022-11-02 22:07
|
||||
|
||||
import django.db.models.deletion
|
||||
import django_extensions.db.fields
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
("character", "0032_weapon_url"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name="Party",
|
||||
fields=[
|
||||
(
|
||||
"id",
|
||||
models.BigAutoField(
|
||||
auto_created=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
verbose_name="ID",
|
||||
),
|
||||
),
|
||||
(
|
||||
"name",
|
||||
models.CharField(max_length=100, unique=True, verbose_name="nom"),
|
||||
),
|
||||
(
|
||||
"created",
|
||||
django_extensions.db.fields.CreationDateTimeField(
|
||||
auto_now_add=True, verbose_name="created"
|
||||
),
|
||||
),
|
||||
(
|
||||
"modified",
|
||||
django_extensions.db.fields.ModificationDateTimeField(
|
||||
auto_now=True, verbose_name="modified"
|
||||
),
|
||||
),
|
||||
(
|
||||
"characters",
|
||||
models.ManyToManyField(
|
||||
blank=True,
|
||||
related_name="parties",
|
||||
to="character.character",
|
||||
verbose_name="personnages",
|
||||
),
|
||||
),
|
||||
(
|
||||
"game_master",
|
||||
models.ForeignKey(
|
||||
on_delete=django.db.models.deletion.PROTECT,
|
||||
related_name="parties",
|
||||
to=settings.AUTH_USER_MODEL,
|
||||
verbose_name="meneur de jeu",
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"abstract": False,
|
||||
},
|
||||
),
|
||||
]
|
17
src/character/migrations/0034_alter_party_options.py
Normal file
17
src/character/migrations/0034_alter_party_options.py
Normal file
|
@ -0,0 +1,17 @@
|
|||
# Generated by Django 4.1.2 on 2022-11-02 22:07
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("character", "0033_party"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterModelOptions(
|
||||
name="party",
|
||||
options={"ordering": ["name"]},
|
||||
),
|
||||
]
|
|
@ -0,0 +1,83 @@
|
|||
# Generated by Django 4.1.2 on 2022-11-02 22:10
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("character", "0034_alter_party_options"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterModelOptions(
|
||||
name="capability",
|
||||
options={
|
||||
"get_latest_by": "modified",
|
||||
"verbose_name": "Capacité",
|
||||
"verbose_name_plural": "Capacités",
|
||||
},
|
||||
),
|
||||
migrations.AlterModelOptions(
|
||||
name="harmfulstate",
|
||||
options={
|
||||
"get_latest_by": "modified",
|
||||
"ordering": ["name"],
|
||||
"verbose_name": "État préjudiciable",
|
||||
"verbose_name_plural": "États préjudiciables",
|
||||
},
|
||||
),
|
||||
migrations.AlterModelOptions(
|
||||
name="party",
|
||||
options={
|
||||
"get_latest_by": "modified",
|
||||
"ordering": ["name"],
|
||||
"verbose_name": "Groupe",
|
||||
"verbose_name_plural": "Groupes",
|
||||
},
|
||||
),
|
||||
migrations.AlterModelOptions(
|
||||
name="path",
|
||||
options={
|
||||
"get_latest_by": "modified",
|
||||
"ordering": ["name"],
|
||||
"verbose_name": "Voie",
|
||||
"verbose_name_plural": "Voies",
|
||||
},
|
||||
),
|
||||
migrations.AlterModelOptions(
|
||||
name="profile",
|
||||
options={
|
||||
"get_latest_by": "modified",
|
||||
"ordering": ["name"],
|
||||
"verbose_name": "Profil",
|
||||
"verbose_name_plural": "Profils",
|
||||
},
|
||||
),
|
||||
migrations.AlterModelOptions(
|
||||
name="race",
|
||||
options={
|
||||
"get_latest_by": "modified",
|
||||
"ordering": ["name"],
|
||||
"verbose_name": "Race",
|
||||
"verbose_name_plural": "Races",
|
||||
},
|
||||
),
|
||||
migrations.AlterModelOptions(
|
||||
name="racialcapability",
|
||||
options={
|
||||
"get_latest_by": "modified",
|
||||
"verbose_name": "Capacité raciale",
|
||||
"verbose_name_plural": "Capacités raciales",
|
||||
},
|
||||
),
|
||||
migrations.AlterModelOptions(
|
||||
name="weapon",
|
||||
options={
|
||||
"get_latest_by": "modified",
|
||||
"ordering": ["name"],
|
||||
"verbose_name": "Arme",
|
||||
"verbose_name_plural": "Armes",
|
||||
},
|
||||
),
|
||||
]
|
|
@ -1 +1 @@
|
|||
0032_weapon_url
|
||||
0035_alter_capability_options_alter_harmfulstate_options_and_more
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
from .capabilities import Capability, Path, RacialCapability
|
||||
from .character import Character, HarmfulState, Profile, Race
|
||||
from .equipment import Weapon
|
||||
from .party import Party
|
||||
|
||||
__all__ = [
|
||||
"Capability",
|
||||
|
@ -11,4 +12,5 @@ __all__ = [
|
|||
"Profile",
|
||||
"Race",
|
||||
"Weapon",
|
||||
"Party",
|
||||
]
|
||||
|
|
|
@ -36,7 +36,7 @@ class Path(DocumentedModel, UniquelyNamedModel, TimeStampedModel, models.Model):
|
|||
)
|
||||
notes = models.TextField(blank=True, verbose_name="notes")
|
||||
|
||||
class Meta:
|
||||
class Meta(UniquelyNamedModel.Meta, TimeStampedModel.Meta):
|
||||
verbose_name = "Voie"
|
||||
verbose_name_plural = "Voies"
|
||||
|
||||
|
@ -105,7 +105,7 @@ class Capability(DocumentedModel, TimeStampedModel, models.Model):
|
|||
|
||||
objects = CapabilityManager()
|
||||
|
||||
class Meta:
|
||||
class Meta(TimeStampedModel.Meta):
|
||||
constraints = [models.UniqueConstraint("path", "rank", name="unique_path_rank")]
|
||||
verbose_name = "Capacité"
|
||||
verbose_name_plural = "Capacités"
|
||||
|
@ -134,7 +134,7 @@ class RacialCapability(DocumentedModel, TimeStampedModel, models.Model):
|
|||
|
||||
objects = RacialCapabilityManager()
|
||||
|
||||
class Meta:
|
||||
class Meta(TimeStampedModel.Meta):
|
||||
verbose_name = "Capacité raciale"
|
||||
verbose_name_plural = "Capacités raciales"
|
||||
constraints = [models.UniqueConstraint("name", "race", name="unique_name_race")]
|
||||
|
|
|
@ -39,13 +39,13 @@ class Profile(DocumentedModel, UniquelyNamedModel, TimeStampedModel, models.Mode
|
|||
)
|
||||
notes = models.TextField(blank=True, verbose_name="notes")
|
||||
|
||||
class Meta:
|
||||
class Meta(UniquelyNamedModel.Meta, TimeStampedModel.Meta):
|
||||
verbose_name = "Profil"
|
||||
verbose_name_plural = "Profils"
|
||||
|
||||
|
||||
class Race(DocumentedModel, UniquelyNamedModel, TimeStampedModel, models.Model):
|
||||
class Meta:
|
||||
class Meta(UniquelyNamedModel.Meta, TimeStampedModel.Meta):
|
||||
verbose_name = "Race"
|
||||
verbose_name_plural = "Races"
|
||||
|
||||
|
@ -54,10 +54,9 @@ class HarmfulState(DocumentedModel, UniquelyNamedModel, TimeStampedModel, models
|
|||
description = models.TextField()
|
||||
icon_url = models.URLField()
|
||||
|
||||
class Meta:
|
||||
class Meta(UniquelyNamedModel.Meta, TimeStampedModel.Meta):
|
||||
verbose_name = "État préjudiciable"
|
||||
verbose_name_plural = "États préjudiciables"
|
||||
ordering = ["name"]
|
||||
|
||||
|
||||
def modifier(value: int) -> int:
|
||||
|
@ -74,6 +73,14 @@ class CharacterManager(models.Manager):
|
|||
return self.get(name=name, player_id=player_id)
|
||||
|
||||
|
||||
class CharacterQuerySet(models.QuerySet):
|
||||
def managed_by(self, user):
|
||||
return self.filter(player=user)
|
||||
|
||||
def owned_by(self, user):
|
||||
return self.filter(player=user)
|
||||
|
||||
|
||||
DEFAULT_NOTES = """
|
||||
#### Traits personnalisés
|
||||
|
||||
|
@ -190,7 +197,7 @@ class Character(models.Model):
|
|||
|
||||
states = models.ManyToManyField(HarmfulState, blank=True, related_name="characters")
|
||||
|
||||
objects = CharacterManager()
|
||||
objects = CharacterManager.from_queryset(CharacterQuerySet)()
|
||||
|
||||
class Meta:
|
||||
verbose_name = "Personnage"
|
||||
|
|
|
@ -16,6 +16,6 @@ class Weapon(UniquelyNamedModel, DocumentedModel, TimeStampedModel, models.Model
|
|||
max_length=3, choices=Category.choices, default=Category.NONE
|
||||
)
|
||||
|
||||
class Meta:
|
||||
class Meta(UniquelyNamedModel.Meta, TimeStampedModel.Meta):
|
||||
verbose_name = "Arme"
|
||||
verbose_name_plural = "Armes"
|
||||
|
|
23
src/character/models/party.py
Normal file
23
src/character/models/party.py
Normal file
|
@ -0,0 +1,23 @@
|
|||
from django.db import models
|
||||
from django_extensions.db.models import TimeStampedModel
|
||||
|
||||
from common.models import UniquelyNamedModel
|
||||
|
||||
|
||||
class Party(UniquelyNamedModel, TimeStampedModel, models.Model):
|
||||
game_master = models.ForeignKey(
|
||||
"common.User",
|
||||
on_delete=models.PROTECT,
|
||||
related_name="parties",
|
||||
verbose_name="meneur de jeu",
|
||||
)
|
||||
characters = models.ManyToManyField(
|
||||
"character.Character",
|
||||
blank=True,
|
||||
related_name="parties",
|
||||
verbose_name="personnages",
|
||||
)
|
||||
|
||||
class Meta(UniquelyNamedModel.Meta, TimeStampedModel.Meta):
|
||||
verbose_name = "Groupe"
|
||||
verbose_name_plural = "Groupes"
|
|
@ -11,7 +11,7 @@ from character.templatetags.character_extras import modifier
|
|||
@login_required
|
||||
def characters_list(request):
|
||||
context = {
|
||||
"characters": Character.objects.filter(player=request.user).select_related(
|
||||
"characters": Character.objects.owned_by(request.user).select_related(
|
||||
"race", "profile"
|
||||
)
|
||||
}
|
||||
|
@ -26,7 +26,7 @@ def character_create(request):
|
|||
@login_required
|
||||
def character_view(request, pk: int):
|
||||
character = get_object_or_404(
|
||||
Character.objects.filter(player=request.user)
|
||||
Character.objects.managed_by(request.user)
|
||||
.select_related("player", "racial_capability", "profile", "race")
|
||||
.prefetch_related("capabilities__path", "weapons"),
|
||||
pk=pk,
|
||||
|
@ -42,7 +42,7 @@ def character_view(request, pk: int):
|
|||
|
||||
@login_required
|
||||
def add_path(request, pk: int):
|
||||
character = get_object_or_404(Character.objects.filter(player=request.user), pk=pk)
|
||||
character = get_object_or_404(Character.objects.managed_by(request.user), pk=pk)
|
||||
form = AddPathForm(character, request.POST)
|
||||
context = {"character": character}
|
||||
if form.is_valid():
|
||||
|
@ -64,7 +64,7 @@ def add_path(request, pk: int):
|
|||
@login_required
|
||||
def character_health_change(request, pk: int):
|
||||
character = get_object_or_404(
|
||||
Character.objects.filter(player=request.user).only(
|
||||
Character.objects.managed_by(request.user).only(
|
||||
"health_max", "health_remaining"
|
||||
),
|
||||
pk=pk,
|
||||
|
@ -78,7 +78,7 @@ def character_health_change(request, pk: int):
|
|||
@login_required
|
||||
def character_mana_change(request, pk: int):
|
||||
character = get_object_or_404(
|
||||
Character.objects.filter(player=request.user)
|
||||
Character.objects.managed_by(request.user)
|
||||
.only("mana_remaining", "level", "value_intelligence", "profile")
|
||||
.select_related("profile"),
|
||||
pk=pk,
|
||||
|
@ -92,7 +92,7 @@ def character_mana_change(request, pk: int):
|
|||
@login_required
|
||||
def character_recovery_points_change(request, pk: int):
|
||||
character = get_object_or_404(
|
||||
Character.objects.filter(player=request.user).only("recovery_points_remaining"),
|
||||
Character.objects.managed_by(request.user).only("recovery_points_remaining"),
|
||||
pk=pk,
|
||||
)
|
||||
value = get_updated_value(
|
||||
|
@ -106,7 +106,7 @@ def character_recovery_points_change(request, pk: int):
|
|||
@login_required
|
||||
def character_defense_misc_change(request, pk: int):
|
||||
character = get_object_or_404(
|
||||
Character.objects.filter(player=request.user).only("defense_misc"), pk=pk
|
||||
Character.objects.managed_by(request.user).only("defense_misc"), pk=pk
|
||||
)
|
||||
value = get_updated_value(request, character.defense_misc, float("inf"))
|
||||
character.defense_misc = value
|
||||
|
@ -118,7 +118,7 @@ def character_defense_misc_change(request, pk: int):
|
|||
@login_required
|
||||
def character_shield_change(request, pk: int):
|
||||
character = get_object_or_404(
|
||||
Character.objects.filter(player=request.user).only("shield"), pk=pk
|
||||
Character.objects.managed_by(request.user).only("shield"), pk=pk
|
||||
)
|
||||
value = get_updated_value(request, character.shield, float("inf"))
|
||||
character.shield = value
|
||||
|
@ -130,7 +130,7 @@ def character_shield_change(request, pk: int):
|
|||
@login_required
|
||||
def character_armor_change(request, pk: int):
|
||||
character = get_object_or_404(
|
||||
Character.objects.filter(player=request.user).only("armor"), pk=pk
|
||||
Character.objects.managed_by(request.user).only("armor"), pk=pk
|
||||
)
|
||||
value = get_updated_value(request, character.armor, float("inf"))
|
||||
character.armor = value
|
||||
|
@ -142,7 +142,7 @@ def character_armor_change(request, pk: int):
|
|||
@login_required
|
||||
def character_initiative_misc_change(request, pk: int):
|
||||
character = get_object_or_404(
|
||||
Character.objects.filter(player=request.user).only("initiative_misc"), pk=pk
|
||||
Character.objects.managed_by(request.user).only("initiative_misc"), pk=pk
|
||||
)
|
||||
value = get_updated_value(request, character.initiative_misc, float("inf"))
|
||||
character.initiative_misc = value
|
||||
|
@ -154,7 +154,7 @@ def character_initiative_misc_change(request, pk: int):
|
|||
@login_required
|
||||
def character_luck_points_change(request, pk: int):
|
||||
character = get_object_or_404(
|
||||
Character.objects.filter(player=request.user).only(
|
||||
Character.objects.managed_by(request.user).only(
|
||||
"luck_points_remaining", "value_charisma"
|
||||
),
|
||||
pk=pk,
|
||||
|
@ -184,7 +184,7 @@ def get_updated_value(request, remaining_value: int, max_value: int | float) ->
|
|||
@login_required
|
||||
def character_get_defense(request, pk: int):
|
||||
character = get_object_or_404(
|
||||
Character.objects.filter(player=request.user).only(
|
||||
Character.objects.managed_by(request.user).only(
|
||||
"defense_misc", "armor", "shield", "value_dexterity"
|
||||
),
|
||||
pk=pk,
|
||||
|
@ -195,7 +195,7 @@ def character_get_defense(request, pk: int):
|
|||
@login_required
|
||||
def character_get_initiative(request, pk: int):
|
||||
character = get_object_or_404(
|
||||
Character.objects.filter(player=request.user).only(
|
||||
Character.objects.managed_by(request.user).only(
|
||||
"initiative_misc", "value_dexterity"
|
||||
),
|
||||
pk=pk,
|
||||
|
@ -212,7 +212,7 @@ def character_notes_change(request, pk: int):
|
|||
def character_equipment_change(request, pk: int):
|
||||
field = "equipment"
|
||||
character = get_object_or_404(
|
||||
Character.objects.filter(player=request.user).only(field), pk=pk
|
||||
Character.objects.managed_by(request.user).only(field), pk=pk
|
||||
)
|
||||
context = {"character": character}
|
||||
if request.method == "GET":
|
||||
|
@ -245,7 +245,7 @@ def character_damage_reduction_change(request, pk: int):
|
|||
|
||||
def update_text_field(request, pk, field):
|
||||
character = get_object_or_404(
|
||||
Character.objects.filter(player=request.user).only(field), pk=pk
|
||||
Character.objects.managed_by(request.user).only(field), pk=pk
|
||||
)
|
||||
context = {"character": character}
|
||||
if request.method == "GET":
|
||||
|
@ -264,7 +264,7 @@ def update_text_field(request, pk, field):
|
|||
@login_required
|
||||
def add_next_in_path(request, character_pk: int, path_pk: int):
|
||||
character = get_object_or_404(
|
||||
Character.objects.filter(player=request.user), pk=character_pk
|
||||
Character.objects.managed_by(request.user), pk=character_pk
|
||||
)
|
||||
path = get_object_or_404(Path, pk=path_pk)
|
||||
capability = path.get_next_capability(character)
|
||||
|
@ -283,7 +283,7 @@ def add_next_in_path(request, character_pk: int, path_pk: int):
|
|||
@login_required
|
||||
def remove_last_in_path(request, character_pk: int, path_pk: int):
|
||||
character = get_object_or_404(
|
||||
Character.objects.filter(player=request.user), pk=character_pk
|
||||
Character.objects.managed_by(request.user), pk=character_pk
|
||||
)
|
||||
last_rank = max(
|
||||
character.capabilities.filter(path_id=path_pk).values_list("rank", flat=True)
|
||||
|
@ -304,7 +304,7 @@ def remove_last_in_path(request, character_pk: int, path_pk: int):
|
|||
@login_required
|
||||
def remove_state(request, pk: int, state_pk: int):
|
||||
character: Character = get_object_or_404(
|
||||
Character.objects.filter(player=request.user), pk=pk
|
||||
Character.objects.managed_by(request.user), pk=pk
|
||||
)
|
||||
state = get_object_or_404(HarmfulState, pk=state_pk)
|
||||
character.states.remove(state)
|
||||
|
@ -318,7 +318,7 @@ def remove_state(request, pk: int, state_pk: int):
|
|||
@login_required
|
||||
def add_state(request, pk: int, state_pk: int):
|
||||
character: Character = get_object_or_404(
|
||||
Character.objects.filter(player=request.user), pk=pk
|
||||
Character.objects.managed_by(request.user), pk=pk
|
||||
)
|
||||
state = get_object_or_404(HarmfulState, pk=state_pk)
|
||||
character.states.add(state)
|
||||
|
|
|
@ -19,6 +19,7 @@ class UniquelyNamedModel(models.Model):
|
|||
|
||||
class Meta:
|
||||
abstract = True
|
||||
ordering = ["name"]
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
|
Loading…
Reference in a new issue