Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Get Saves working #285

Merged
merged 2 commits into from
Dec 29, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
169 changes: 118 additions & 51 deletions cmp/forms.py
Original file line number Diff line number Diff line change
@@ -19,22 +19,37 @@
from django.forms import inlineformset_factory

from crispy_forms.helper import FormHelper
from crispy_forms.layout import Layout, Field, Div, HTML
from crispy_forms.bootstrap import Accordion, AccordionGroup
from crispy_forms.layout import Layout, Field
from crispy_forms.bootstrap import Accordion, AccordionGroup, TabHolder, Tab

# First define the formset form
class SoldierImprisonmentForm(forms.ModelForm):
class Meta:
model = SoldierImprisonment
fields = ['pow_camp', 'pow_number', 'date_from', 'date_to', 'notes']
widgets = {
'date_from': forms.DateInput(
attrs={
'type': 'date',
'class': 'form-control'
}
),
'date_to': forms.DateInput(
attrs={
'type': 'date',
'class': 'form-control'
}
)
}

# First, create a helper class for the formset
class SoldierImprisonmentFormSetHelper(FormHelper):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.form_tag = False

# Check if there's any data in the formset
# Default to collapsed
has_data = False
if hasattr(self, 'formset'):
has_data = any(not form.empty_permitted or form.initial for form in self.formset)

# Set title based on whether there's data
title = 'Prisoner of War Details' if has_data else 'Prisoner of War Details (None Recorded)'
title = 'Prisoner of War Details (None Recorded)'

self.layout = Layout(
Accordion(
@@ -45,24 +60,37 @@ def __init__(self, *args, **kwargs):
'date_from',
'date_to',
'notes',
active=has_data, # Only active if there's data
css_class='bg-light'
active=has_data, # Collapsed by default
css_class='bg-info bg-opacity-25 border rounded p-3'
),
css_id="imprisonment-details-accordion"
)
)

# Then create the formset with the helper
def update_title(self):
"""Update the title based on formset data"""
if hasattr(self, 'formset') and self.formset.initial_forms:
has_data = any(form.initial for form in self.formset.initial_forms)
title = 'Prisoner of War Details' if has_data else 'Prisoner of War Details (None Recorded)'
self.layout[0][0].name = title
self.layout[0][0].active = has_data

# Create the formset
SoldierImprisonmentInlineFormSet = inlineformset_factory(
Soldier,
SoldierImprisonment,
fields=['pow_camp', 'pow_number', 'date_from', 'date_to', 'notes'],
form=SoldierImprisonmentForm,
extra=1,
can_delete=True
)

# Add the helper to the formset
SoldierImprisonmentInlineFormSet.helper = SoldierImprisonmentFormSetHelper()
class SoldierImprisonmentFormSetWithHelper(SoldierImprisonmentInlineFormSet):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.helper = SoldierImprisonmentFormSetHelper()
self.helper.formset = self
self.helper.update_title()


class CustomUserCreationForm(UserCreationForm):
@@ -217,40 +245,31 @@ class editSoldierDeathForm(forms.ModelForm):
class Meta:
model = SoldierDeath
fields = ['date', 'company', 'cemetery', 'cwgc_id', 'image']
widgets = {
'date': forms.DateInput(
attrs={
'type': 'date',
'class': 'form-control'
}
)
}
labels = {
'image': 'Grave Photograph' # Updated label
}

def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.helper = FormHelper()

# Determine header class and active state based on whether form has data
header_class = 'bg-light' if self.instance and self.instance.pk else 'bg-light-blue'
is_active = bool(self.instance and self.instance.pk)

# Set title based on whether there's data
title = 'Death Details' if self.instance and self.instance.pk else 'Death Details (None Recorded)'

self.helper.layout = Layout(
Accordion(
AccordionGroup(
title,
'date',
'company',
'cemetery',
'cwgc_id',
'image',
active=is_active,
button_class=header_class
),
css_id="death-details-accordion"
)
)
self.helper = SoldierDeathFormHelper()
self.helper.form = self
self.helper.update_title()


class editSoldierForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.helper = FormHelper()
self.helper.label_class = 'form-label'
self.fields['provost_officer'].disabled = True

# Determine header class and active state based on whether form has data
header_class = 'bg-light' if self.instance and self.instance.pk else 'bg-light-blue'
@@ -342,6 +361,7 @@ class SoldierForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.helper = FormHelper()


# Determine header class and active state based on whether form has data
header_class = 'bg-light' if self.instance and self.instance.pk else 'bg-light-blue'
@@ -352,7 +372,7 @@ def __init__(self, *args, **kwargs):
Field('initials'),
Field('army_number'),
Field('rank'),
Field('provost_officer'),
#Field('provost_officer'),
Field('notes'),
Accordion(
AccordionGroup(
@@ -375,18 +395,27 @@ class Meta:
fields = ['surname', 'initials', 'army_number', 'rank', 'provost_officer', 'notes']


class SoldierDecorationForm(forms.ModelForm):
class Meta:
model = SoldierDecoration
fields = ['decoration', 'gazette_issue', 'gazette_page', 'gazette_date', 'theatre', 'country', 'citation', 'notes']
widgets = {
'gazette_date': forms.DateInput(
attrs={
'type': 'date',
'class': 'form-control'
}
)
}

class SoldierDecorationFormSetHelper(FormHelper):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.form_tag = False

# Check if there's any data in the formset
# Default to collapsed
has_data = False
if hasattr(self, 'formset'):
has_data = any(not form.empty_permitted or form.initial for form in self.formset)

# Set title based on whether there's data
title = 'Decoration Details' if has_data else 'Decoration Details (None Recorded)'
title = 'Decoration Details (None Recorded)'

self.layout = Layout(
Accordion(
@@ -400,23 +429,61 @@ def __init__(self, *args, **kwargs):
'country',
'citation',
'notes',
active=has_data, # Only active if there's data
css_class='bg-light'
active=has_data,
css_class='bg-info bg-opacity-25 border rounded p-3'
),
css_id="decoration-details-accordion"
)
)

# Create the formset with the helper
def update_title(self):
if hasattr(self, 'formset') and self.formset.initial_forms:
has_data = any(form.initial for form in self.formset.initial_forms)
title = 'Decoration Details' if has_data else 'Decoration Details (None Recorded)'
self.layout[0][0].name = title
self.layout[0][0].active = has_data

# Create the formset
SoldierDecorationInlineFormSet = inlineformset_factory(
Soldier,
SoldierDecoration,
fields=['decoration', 'gazette_issue', 'gazette_page', 'gazette_date', 'theatre', 'country', 'citation', 'notes'],
form=SoldierDecorationForm,
extra=1,
can_delete=True
)

# Add the helper to the formset
SoldierDecorationInlineFormSet.helper = SoldierDecorationFormSetHelper()

class SoldierDeathFormHelper(FormHelper):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.form_tag = False

# Default to collapsed
has_data = False
title = 'Death Details (None Recorded)'

self.layout = Layout(
Accordion(
AccordionGroup(
title,
'date',
'company',
'cemetery',
'cwgc_id',
'image',
active=has_data, # Collapsed by default
css_class='bg-info bg-opacity-25 border rounded p-3'
),
css_id="death-details-accordion"
)
)

def update_title(self):
"""Update the title based on form data"""
if hasattr(self, 'form') and self.form.initial:
has_data = any(self.form.initial.values())
title = 'Death Details' if has_data else 'Death Details (None Recorded)'
self.layout[0][0].name = title
self.layout[0][0].active = has_data


2 changes: 1 addition & 1 deletion cmp/urls.py
Original file line number Diff line number Diff line change
@@ -88,7 +88,7 @@
# Soldier management
path("mgmt/soldiers/search/", views.search_soldiers, name='search-soldiers'),
path("mgmt/soldiers/edit/<int:id>/", views.edit_soldier, name='edit-soldier'),
path("mgmt/soldiers/edit/", views.edit_soldier, name='edit-soldier'),
path("mgmt/soldiers/edit/", views.edit_soldier, name='create-soldier'),
path("mgmt/soldiers/delete/<int:id>/", views.delete_soldier, name='delete-soldier'),
path("mgmt/soldiers/<int:id>/", views.detail_soldiers, name='soldier-detail'),

104 changes: 87 additions & 17 deletions cmp/views.py
Original file line number Diff line number Diff line change
@@ -38,9 +38,14 @@

from .models import SoldierImprisonment

from .forms import editSoldierForm, editSoldierDeathForm, SoldierImprisonmentInlineFormSet
from .forms import (
editSoldierForm, editSoldierDeathForm,
SoldierImprisonmentFormSetWithHelper,
SoldierDecorationInlineFormSet,
)
from .forms import SoldierDecorationInlineFormSet
from .forms import ProvostOfficerForm, ProvostAppointmentForm
from .forms import SoldierImprisonmentFormSetHelper, SoldierDecorationFormSetHelper



@@ -441,28 +446,93 @@ def soldier_detail(request, soldier_id):
return render(request, 'cmp/soldier.html', {'soldier': soldier})


def edit_soldier(request, id):
soldier = get_object_or_404(Soldier, pk=id)
def edit_soldier(request, id=None):
print("\n=== Starting View ===")
print(f"Method: {request.method}")
print(f"ID: {id}")

if id:
soldier = get_object_or_404(Soldier, pk=id)
print(f"Editing existing soldier: {soldier}")
else:
soldier = None
print("Creating new soldier")

if request.method == 'POST':
form = editSoldierForm(request.POST, instance=soldier)
death_form = editSoldierDeathForm(request.POST, request.FILES, instance=getattr(soldier, 'soldierdeath', None))
imprisonment_formset = SoldierImprisonmentInlineFormSet(request.POST, instance=soldier, prefix='imprisonment')
decoration_formset = SoldierDecorationInlineFormSet(request.POST, instance=soldier, prefix='decoration')
print("\n=== Processing POST ===")
print(f"POST data: {request.POST}")
print(f"FILES data: {request.FILES}")

if form.is_valid() and death_form.is_valid() and imprisonment_formset.is_valid() and decoration_formset.is_valid():
form.save()
if death_form.has_changed():
death_form.save()
imprisonment_formset.save()
decoration_formset.save()
messages.success(request, f'Soldier "{soldier.surname}, {soldier.initials}" successfully updated!')
return redirect('search-soldiers')
try:
form = editSoldierForm(request.POST, instance=soldier)
death_form = editSoldierDeathForm(request.POST, request.FILES, instance=getattr(soldier, 'soldierdeath', None))
imprisonment_formset = SoldierImprisonmentFormSetWithHelper(request.POST, instance=soldier, prefix='imprisonment')
decoration_formset = SoldierDecorationInlineFormSet(request.POST, instance=soldier, prefix='decoration')

print("=== Form Validation ===")
print(f"Main form bound: {form.is_bound}")
print(f"Death form bound: {death_form.is_bound}")
print(f"Imprisonment formset bound: {imprisonment_formset.is_bound}")
print(f"Decoration formset bound: {decoration_formset.is_bound}")

form_valid = form.is_valid()
death_form_valid = death_form.is_valid()
imprisonment_formset_valid = imprisonment_formset.is_valid()
decoration_formset_valid = decoration_formset.is_valid()

print(f"Main form valid: {form_valid}")
print(f"Death form valid: {death_form_valid}")
print(f"Imprisonment formset valid: {imprisonment_formset_valid}")
print(f"Decoration formset valid: {decoration_formset_valid}")

if all([form_valid, death_form_valid, imprisonment_formset_valid, decoration_formset_valid]):
print("=== Saving Forms ===")
soldier = form.save()
print(f"Main form saved: {soldier}")

if death_form.has_changed():
print("Death form has changes:", death_form.changed_data)
death_instance = death_form.save(commit=False)
death_instance.soldier = soldier
death_instance.save()
print("Death form saved")

# Check if any form in the formset has changes
if any(form.has_changed() for form in imprisonment_formset):
print("Imprisonment formset has changes")
imprisonment_formset.instance = soldier
imprisonment_formset.save()
print("Imprisonment formset saved")

if any(form.has_changed() for form in decoration_formset):
print("Decoration formset has changes")
decoration_formset.instance = soldier
decoration_formset.save()
print("Decoration formset saved")

messages.success(request, f'Soldier "{soldier.surname}, {soldier.initials}" successfully {"updated" if id else "created"}!')
return redirect('search-soldiers')
else:
if not form_valid:
print(f"Main form errors: {form.errors}")
if not death_form_valid:
print(f"Death form errors: {death_form.errors}")
if not imprisonment_formset_valid:
print(f"Imprisonment formset errors: {imprisonment_formset.errors}")
if not decoration_formset_valid:
print(f"Decoration formset errors: {decoration_formset.errors}")
messages.error(request, 'Please correct the errors below.')
except Exception as e:
print(f"Exception occurred: {str(e)}")
messages.error(request, f'Error: {str(e)}')
else:
form = editSoldierForm(instance=soldier)
death_form = editSoldierDeathForm(instance=getattr(soldier, 'soldierdeath', None))
imprisonment_formset = SoldierImprisonmentInlineFormSet(instance=soldier, prefix='imprisonment')
imprisonment_formset = SoldierImprisonmentFormSetWithHelper(instance=soldier, prefix='imprisonment')
imprisonment_formset.helper = SoldierImprisonmentFormSetHelper()
decoration_formset = SoldierDecorationInlineFormSet(instance=soldier, prefix='decoration')

decoration_formset.helper = SoldierDecorationFormSetHelper()

return render(request, 'cmp/edit-soldiers.html', {
'form': form,
'death_form': death_form,
36 changes: 19 additions & 17 deletions templates/cmp/edit-companies.html
Original file line number Diff line number Diff line change
@@ -1,20 +1,22 @@
{% extends "base.html" %}
{% load static crispy_forms_tags %}
{% block title %}Companies Form{% endblock %}
{% block content %}

<div class="center-content">
<h3>Edit Companies</h3>
{% load static %}
{% load crispy_forms_tags %}

<div>
<form method="POST">
{% csrf_token %}
{{ form.management_form }}
{{ form.errors }}
{{form | crispy}}
<button type="submit" class="btn btn-primary">Save</button>
</form>
</div>
{% block title %}{% if company %}Edit{% else %}Add{% endif %} Company{% endblock %}

{% endblock %}
</div>
{% block content %}
<div class="center-content">
<h3>{% if company %}Edit{% else %}Add{% endif %} Company</h3>
<form method="post">
{% csrf_token %}
{{ form|crispy }}
<button type="submit" class="glossy-button add-button">SAVE</button>
{% if company %}
<button type="button" class="glossy-button delete-button"
onclick="if(confirm('Are you sure you want to delete this company?')) {
window.location.href='{% url 'delete-company' company.id %}';
}">DELETE</button>
{% endif %}
</form>
</div>
{% endblock %}
19 changes: 14 additions & 5 deletions templates/cmp/edit-soldiers.html
Original file line number Diff line number Diff line change
@@ -4,20 +4,29 @@

{% block content %}
<div class="container mt-4">
{% if messages %}
<div class="messages">
{% for message in messages %}
<div class="alert alert-{{ message.tags }}">
{{ message }}
</div>
{% endfor %}
</div>
{% endif %}

<h2>{% if soldier %}Edit{% else %}Add{% endif %} Soldier</h2>

<form method="post" enctype="multipart/form-data">
<form method="post" action="" enctype="multipart/form-data">
{% csrf_token %}
{{ form|crispy }}

{{ decoration_formset.management_form }}
{% crispy decoration_formset decoration_formset.helper %}

{% crispy death_form %}
{% crispy death_form death_form.helper %}

{{ imprisonment_formset.management_form }}
{% crispy imprisonment_formset imprisonment_formset.helper %}

{{ decoration_formset.management_form }}
{% crispy decoration_formset decoration_formset.helper %}

<div class="mt-3">
<button type="submit" class="btn btn-primary">Save</button>
4 changes: 2 additions & 2 deletions templates/cmp/search-soldiers.html
Original file line number Diff line number Diff line change
@@ -15,7 +15,7 @@
<h3>Search/Edit/Add/Delete Soldiers</h3>

<div class="center-content">
<button class="glossy-button add-button" onclick="location.href='{% url 'edit-soldier' %}'" type="button">Add New Soldier</button>
<a href="{% url 'create-soldier' %}" class="glossy-button add-button">Add New Soldier</a>
</div>

<div name="search-input" class="search-input">
@@ -41,7 +41,7 @@ <h3>Search/Edit/Add/Delete Soldiers</h3>

{% for soldier in page_obj %}
<tr>
<td><button class="glossy-button edit-button" onclick="location.href='{% url 'edit-soldier' soldier.id %}'" type="button">EDIT</button></td>
<td><button class="glossy-button edit-button" onclick="location.href='{% url 'edit-soldier' id=soldier.id %}'" type="button">EDIT</button></td>
<td><span class="soldier-info">{{ soldier.surname }}</span></td>
<td><span class="soldier-info">{{ soldier.initials }}</span></td>
<td><span class="soldier-info">{{ soldier.army_number }}</span></td>