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

Tp2000 1387 - Python 3.12 Reattempt at async bulk edit - DNM #1279

Draft
wants to merge 16 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
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
69 changes: 69 additions & 0 deletions common/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -892,3 +892,72 @@ def deserialize_init_kwargs(cls, form_kwargs: Dict) -> Dict:
representation.
"""
return {}

def get_data_form_list(self) -> dict:
"""
Returns a form list based on form_list, conditionally including only
those items as per condition_list and also appearing in data_form_list.

The list is generated dynamically because conditions in condition_list
may be dynamic.

Essentially, version of `WizardView.get_form_list()` filtering in only
those list items appearing in `data_form_list`.
"""
data_form_keys = [key for key, form in self.data_form_list]
return {
form_key: form_class
for form_key, form_class in self.get_form_list().items()
if form_key in data_form_keys
}

def all_serializable_form_data(self) -> Dict:
"""
Returns serializable data for all wizard steps.

This is a re-implementation of
MeasureCreateWizard.get_all_cleaned_data(), but using self.data after
is_valid() has been successfully run.
"""

all_data = {}

for form_key in self.get_data_form_list().keys():
all_data[form_key] = self.serializable_form_data_for_step(form_key)

return all_data

def serializable_form_data_for_step(self, step) -> Dict:
"""
Returns serializable data for a wizard step.

This is a re-implementation of WizardView.get_cleaned_data_for_step(),
returning the serializable version of data in place of the form's
regular cleaned_data.
"""

form_obj = self.get_form(
step=step,
data=self.storage.get_step_data(step),
files=self.storage.get_step_files(step),
)

return form_obj.serializable_data(remove_key_prefix=step)

def all_serializable_form_kwargs(self) -> Dict:
"""Returns serializable kwargs for all wizard steps."""

all_kwargs = {}

for form_key in self.get_data_form_list().keys():
all_kwargs[form_key] = self.serializable_form_kwargs_for_step(form_key)

return all_kwargs

def serializable_form_kwargs_for_step(self, step) -> Dict:
"""Returns serializable kwargs for a wizard step."""

form_kwargs = self.get_form_kwargs(step)
form_class = self.form_list[step]

return form_class.serializable_init_kwargs(form_kwargs)
109 changes: 103 additions & 6 deletions measures/forms/wizard.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,9 @@
from . import MeasureFootnotesForm
from . import MeasureGeoAreaInitialDataMixin

import logging
logger = logging.getLogger(__name__)


class MeasureConditionsWizardStepForm(MeasureConditionsFormMixin):
# override methods that use form kwargs
Expand Down Expand Up @@ -781,7 +784,7 @@ def __init__(self, *args, **kwargs):
)


class MeasureStartDateForm(forms.Form):
class MeasureStartDateForm(forms.Form, SerializableFormMixin):
start_date = DateInputFieldFixed(
label="Start date",
help_text="For example, 27 3 2008",
Expand All @@ -806,7 +809,6 @@ def __init__(self, *args, **kwargs):

def clean(self):
cleaned_data = super().clean()

if "start_date" in cleaned_data:
start_date = cleaned_data["start_date"]
for measure in self.selected_measures:
Expand All @@ -818,9 +820,33 @@ def clean(self):
)

return cleaned_data

@classmethod
def serializable_init_kwargs(cls, kwargs: Dict) -> Dict:
selected_measures = kwargs.get("selected_measures")
selected_measures_pks = []
for measure in selected_measures:
selected_measures_pks.append(measure.id)

serializable_kwargs = {
"selected_measures": selected_measures_pks,
}

return serializable_kwargs

@classmethod
def deserialize_init_kwargs(cls, form_kwargs: Dict) -> Dict:
serialized_selected_measures_pks = form_kwargs.get("selected_measures")
deserialized_selected_measures = models.Measure.objects.filter(pk__in=serialized_selected_measures_pks)

kwargs = {
"selected_measures": deserialized_selected_measures,
}

return kwargs

class MeasureEndDateForm(forms.Form):

class MeasureEndDateForm(forms.Form, SerializableFormMixin):
end_date = DateInputFieldFixed(
label="End date",
help_text="For example, 27 3 2008",
Expand Down Expand Up @@ -860,9 +886,33 @@ def clean(self):
cleaned_data["end_date"] = None

return cleaned_data

@classmethod
def serializable_init_kwargs(cls, kwargs: Dict) -> Dict:
selected_measures = kwargs.get("selected_measures")
selected_measures_pks = []
for measure in selected_measures:
selected_measures_pks.append(measure.id)

serializable_kwargs = {
"selected_measures": selected_measures_pks,
}

return serializable_kwargs

@classmethod
def deserialize_init_kwargs(cls, form_kwargs: Dict) -> Dict:
serialized_selected_measures_pks = form_kwargs.get("selected_measures")
deserialized_selected_measures = models.Measure.objects.filter(pk__in=serialized_selected_measures_pks)

kwargs = {
"selected_measures": deserialized_selected_measures,
}

return kwargs


class MeasureRegulationForm(forms.Form):
class MeasureRegulationForm(forms.Form, SerializableFormMixin):
generating_regulation = AutoCompleteField(
label="Regulation ID",
help_text="Select the regulation which provides the legal basis for the measures.",
Expand All @@ -887,9 +937,32 @@ def __init__(self, *args, **kwargs):
data_prevent_double_click="true",
),
)
@classmethod
def serializable_init_kwargs(cls, kwargs: Dict) -> Dict:
selected_measures = kwargs.get("selected_measures")
selected_measures_pks = []
for measure in selected_measures:
selected_measures_pks.append(measure.id)

serializable_kwargs = {
"selected_measures": selected_measures_pks,
}

return serializable_kwargs

@classmethod
def deserialize_init_kwargs(cls, form_kwargs: Dict) -> Dict:
serialized_selected_measures_pks = form_kwargs.get("selected_measures")
deserialized_selected_measures = models.Measure.objects.filter(pk__in=serialized_selected_measures_pks)

kwargs = {
"selected_measures": deserialized_selected_measures,
}

return kwargs


class MeasureDutiesForm(forms.Form):
class MeasureDutiesForm(forms.Form, SerializableFormMixin):
duties = forms.CharField(
label="Duties",
help_text="Enter the duty that applies to the measures.",
Expand Down Expand Up @@ -920,6 +993,30 @@ def __init__(self, *args, **kwargs):
data_prevent_double_click="true",
),
)

@classmethod
def serializable_init_kwargs(cls, kwargs: Dict) -> Dict:
selected_measures = kwargs.get("selected_measures")
selected_measures_pks = []
for measure in selected_measures:
selected_measures_pks.append(measure.id)

serializable_kwargs = {
"selected_measures": selected_measures_pks,
}

return serializable_kwargs

@classmethod
def deserialize_init_kwargs(cls, form_kwargs: Dict) -> Dict:
serialized_selected_measures_pks = form_kwargs.get("selected_measures")
deserialized_selected_measures = models.Measure.objects.filter(pk__in=serialized_selected_measures_pks)

kwargs = {
"selected_measures": deserialized_selected_measures,
}

return kwargs

def clean(self):
cleaned_data = super().clean()
Expand Down Expand Up @@ -965,7 +1062,7 @@ def __init__(self, *args, **kwargs):
)


class MeasureGeographicalAreaExclusionsFormSet(FormSet):
class MeasureGeographicalAreaExclusionsFormSet(FormSet, SerializableFormMixin):
"""Allows editing the geographical area exclusions of multiple measures in
`MeasureEditWizard`."""

Expand Down
84 changes: 84 additions & 0 deletions measures/migrations/0017_measuresbulkeditor.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
# Generated by Django 4.2.14 on 2024-07-29 14:39

from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
import django_fsm
import measures.models.bulk_processing


class Migration(migrations.Migration):

dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
("workbaskets", "0008_datarow_dataupload"),
("measures", "0016_measuresbulkcreator"),
]

operations = [
migrations.CreateModel(
name="MeasuresBulkEditor",
fields=[
(
"id",
models.AutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("created_at", models.DateTimeField(auto_now_add=True)),
("updated_at", models.DateTimeField(auto_now=True)),
(
"task_id",
models.CharField(blank=True, max_length=50, null=True, unique=True),
),
(
"processing_state",
django_fsm.FSMField(
choices=[
("AWAITING_PROCESSING", "Awaiting processing"),
("CURRENTLY_PROCESSING", "Currently processing"),
("SUCCESSFULLY_PROCESSED", "Successfully processed"),
("FAILED_PROCESSING", "Failed processing"),
("CANCELLED", "Cancelled"),
],
db_index=True,
default="AWAITING_PROCESSING",
editable=False,
max_length=50,
protected=True,
),
),
(
"successfully_processed_count",
models.PositiveIntegerField(default=0),
),
("form_data", models.JSONField()),
("form_kwargs", models.JSONField()),
("selected_measures", models.JSONField()),
(
"user",
models.ForeignKey(
editable=False,
null=True,
on_delete=django.db.models.deletion.SET_NULL,
to=settings.AUTH_USER_MODEL,
),
),
(
"workbasket",
models.ForeignKey(
editable=False,
null=True,
on_delete=measures.models.bulk_processing.REVOKE_TASKS_AND_SET_NULL,
to="workbaskets.workbasket",
),
),
],
options={
"abstract": False,
},
),
]
2 changes: 2 additions & 0 deletions measures/models/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from measures.models.bulk_processing import BulkProcessor
from measures.models.bulk_processing import MeasuresBulkCreator
from measures.models.bulk_processing import MeasuresBulkEditor
from measures.models.bulk_processing import ProcessingState
from measures.models.tracked_models import AdditionalCodeTypeMeasureType
from measures.models.tracked_models import DutyExpression
Expand All @@ -23,6 +24,7 @@
# - Classes exported from bulk_processing.py.
"BulkProcessor",
"MeasuresBulkCreator",
"MeasuresBulkEditor",
"ProcessingState",
# - Classes exported from tracked_model.py.
"AdditionalCodeTypeMeasureType",
Expand Down
Loading
Loading