diff --git a/src/cal_bc/projects/forms/model_section.py b/src/cal_bc/projects/forms/model_section.py new file mode 100644 index 0000000..bff11ad --- /dev/null +++ b/src/cal_bc/projects/forms/model_section.py @@ -0,0 +1,12 @@ +from django.forms import ModelForm +from cal_bc.projects.models.model_section import ModelSection +from django.utils.translation import gettext as _ + + +class ModelSectionForm(ModelForm): + class Meta: + model = ModelSection + fields = ["section_fields"] + + def get_labels(self) -> dict[str, str]: + return {"section_fields": _(self.object.name)} diff --git a/src/cal_bc/projects/forms/project.py b/src/cal_bc/projects/forms/project.py index 9c5d916..a354226 100644 --- a/src/cal_bc/projects/forms/project.py +++ b/src/cal_bc/projects/forms/project.py @@ -16,23 +16,11 @@ class Meta: fields = [ "name", "district", - "type", - "location", - "construction_period_length", - "data_direction", - "peak_periods_length", + "model", ] labels = { "name": _("Project Name"), - "type": _("Project Type"), - "location": _("Project Location"), - "construction_period_length": _("Length of Construction Period"), - "data_direction": _("One- or Two-Way Data"), - "peak_periods_length": _("Length of Peak Period(s) (up to 24 hrs)"), - } - - help_texts = { - "construction_period_length": _("years"), - "peak_periods_length": _("hours"), + "model": _("Model"), + "district": _("District"), } diff --git a/src/cal_bc/projects/forms/project_field.py b/src/cal_bc/projects/forms/project_field.py new file mode 100644 index 0000000..ee1ca4c --- /dev/null +++ b/src/cal_bc/projects/forms/project_field.py @@ -0,0 +1,19 @@ +from django.forms import ModelForm +from cal_bc.projects.models.project_field import ProjectField +from django.utils.translation import gettext as _ + + +class ProjectFieldForm(ModelForm): + class Meta: + model = ProjectField + fields = ["value", "project"] + labels = {"value": _("Value")} + widgets = {"project": Hidden()} + + def get_labels(self) -> dict[str, str]: + return {"value": _(self.object.model_section_field.name)} + + +ProjectFieldFormset = inlineformset_factory( + ModelSectionField, ProjectField, form=ProjectFieldForm, allow_create=False +) diff --git a/src/cal_bc/projects/migrations/0001_create_models.py b/src/cal_bc/projects/migrations/0001_create_models.py new file mode 100644 index 0000000..5023892 --- /dev/null +++ b/src/cal_bc/projects/migrations/0001_create_models.py @@ -0,0 +1,28 @@ +# Generated by Django 5.2.7 on 2025-10-11 00:25 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + initial = True + + dependencies = [] + + operations = [ + migrations.CreateModel( + name="Model", + fields=[ + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("name", models.CharField(null=False)), + ("url", models.CharField(null=False)), + ], + ), + ] diff --git a/src/cal_bc/projects/migrations/0001_initial.py b/src/cal_bc/projects/migrations/0001_initial.py deleted file mode 100644 index 37bcd3f..0000000 --- a/src/cal_bc/projects/migrations/0001_initial.py +++ /dev/null @@ -1,11 +0,0 @@ -# Generated by Django 5.2.7 on 2025-10-11 00:25 - -from django.db import migrations - - -class Migration(migrations.Migration): - initial = True - - dependencies = [] - - operations = [] diff --git a/src/cal_bc/projects/migrations/0002_create_projects.py b/src/cal_bc/projects/migrations/0002_create_projects.py index 4d70b12..0aeb0f9 100644 --- a/src/cal_bc/projects/migrations/0002_create_projects.py +++ b/src/cal_bc/projects/migrations/0002_create_projects.py @@ -1,11 +1,12 @@ -# Generated by Django 5.2.7 on 2025-10-11 00:34 +# Generated by Django 5.2.7 on 2025-10-18 19:46 +import django.db.models.deletion from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ - ("projects", "0001_initial"), + ("projects", "0001_create_models"), ] operations = [ @@ -21,7 +22,15 @@ class Migration(migrations.Migration): verbose_name="ID", ), ), - ("name", models.CharField()), + ("name", models.CharField(null=False)), + ( + "model", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + to="projects.model", + null=False, + ), + ), ], ), ] diff --git a/src/cal_bc/projects/migrations/0003_add_project_district.py b/src/cal_bc/projects/migrations/0003_add_project_district.py new file mode 100644 index 0000000..7d6992c --- /dev/null +++ b/src/cal_bc/projects/migrations/0003_add_project_district.py @@ -0,0 +1,33 @@ +# Generated by Django 5.2.7 on 2025-10-15 22:42 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("projects", "0002_create_projects"), + ] + + operations = [ + migrations.AddField( + model_name="project", + name="district", + field=models.IntegerField( + choices=[ + (1, "District 1 - Eureka"), + (2, "District 2 - Redding"), + (3, "District 3 - Marysville / Sacramento"), + (4, "District 4 - Bay Area / Oakland"), + (5, "District 5 - Central Coast"), + (6, "District 6 - Fresno / Bakersfield"), + (7, "District 7 - Los Angeles / Ventura"), + (8, "District 8 - San Bernardino / Riverside"), + (9, "District 9 - Bishop"), + (10, "District 10 - Stockton"), + (11, "District 11 - San Diego"), + (12, "District 12 - Orange County"), + ], + null=False, + ), + ), + ] diff --git a/src/cal_bc/projects/migrations/0003_project_construction_period_length_and_more.py b/src/cal_bc/projects/migrations/0003_project_construction_period_length_and_more.py deleted file mode 100644 index 5b6ff8a..0000000 --- a/src/cal_bc/projects/migrations/0003_project_construction_period_length_and_more.py +++ /dev/null @@ -1,133 +0,0 @@ -# Generated by Django 5.2.7 on 2025-10-15 22:42 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - dependencies = [ - ("projects", "0002_create_projects"), - ] - - operations = [ - migrations.AddField( - model_name="project", - name="construction_period_length", - field=models.IntegerField(null=True), - ), - migrations.AddField( - model_name="project", - name="data_direction", - field=models.IntegerField( - choices=[(1, "One-Way"), (2, "Two-Way")], default=2 - ), - ), - migrations.AddField( - model_name="project", - name="district", - field=models.IntegerField( - choices=[ - (1, "District 1 - Eureka"), - (2, "District 2 - Redding"), - (3, "District 3 - Marysville / Sacramento"), - (4, "District 4 - Bay Area / Oakland"), - (5, "District 5 - Central Coast"), - (6, "District 6 - Fresno / Bakersfield"), - (7, "District 7 - Los Angeles / Ventura"), - (8, "District 8 - San Bernardino / Riverside"), - (9, "District 9 - Bishop"), - (10, "District 10 - Stockton"), - (11, "District 11 - San Diego"), - (12, "District 12 - Orange County"), - ], - null=True, - ), - ), - migrations.AddField( - model_name="project", - name="location", - field=models.IntegerField( - choices=[ - (1, "Southern California"), - (2, "Northern California"), - (3, "Rural"), - ], - null=True, - ), - ), - migrations.AddField( - model_name="project", - name="peak_periods_length", - field=models.IntegerField(default=5), - ), - migrations.AddField( - model_name="project", - name="type", - field=models.CharField( - choices=[ - ( - "Highway Capacity Expansion", - [ - ("general_highway", "General Highway"), - ("hov_lane_addition", "HOV Lane Addition"), - ("hot_lane_addition", "HOT Lane Addition"), - ("passing_lane", "Passing Lane"), - ("intersection", "Intersection"), - ("truck_only_lane", "Truck Only Lane"), - ("bypass", "Bypass"), - ("queuing", "Queuing"), - ("pavement", "Pavement"), - ], - ), - ( - "Rail or Transit Capacity Expansion", - [ - ("passenger_rail", "Passenger Rail"), - ("light_rail", "Light Rail (LRT)"), - ( - "highway_rail_grade_crossing", - "Highway-Rail Grade Crossing", - ), - ], - ), - ( - "Highway Operational Improvement", - [ - ("auxiliary_lane", "Auxiliary Lane"), - ("freeway_connector", "Freeway Connector"), - ("hov_connector", "HOV Connector"), - ("hov_drop_ramp", "HOV Drop Ramp"), - ("off_ramp_widening", "Off-Ramp Widening"), - ("on_ramp_widening", "On-Ramp Widening"), - ("hot_lane_conversion", "Hot Lane Conversion"), - ], - ), - ( - "Transportation Management Systems (TMS)", - [ - ("ramp_metering", "Ramp Metering"), - ( - "ramp_metering_signal_coordination", - "Ramp Metering Signal Coordination", - ), - ("incident_management", "Incident Management"), - ("traveler_information", "Traveler Information"), - ( - "arterial_signal_management", - "Arterial Signal Management", - ), - ( - "transit_vehicle_location", - "Transit Vehicle Location (AVL)", - ), - ( - "transit_vehicle_signal_priority", - "Transit Vehicle Signal Priority", - ), - ("bus_rapid_transit", "Bus Rapid Transit (BRT)"), - ], - ), - ], - null=True, - ), - ), - ] diff --git a/src/cal_bc/projects/migrations/0004_create_model_section.py b/src/cal_bc/projects/migrations/0004_create_model_section.py new file mode 100644 index 0000000..6fccc2f --- /dev/null +++ b/src/cal_bc/projects/migrations/0004_create_model_section.py @@ -0,0 +1,37 @@ +# Generated by Django 5.2.7 on 2025-10-18 20:18 + +import django.db.models.deletion +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("projects", "0003_add_project_district"), + ] + + operations = [ + migrations.CreateModel( + name="ModelSection", + fields=[ + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("name", models.CharField(null=False)), + ("help_text", models.CharField(null=False)), + ( + "model", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + to="projects.model", + null=False, + ), + ), + ], + ), + ] diff --git a/src/cal_bc/projects/migrations/0005_create_model_section_field.py b/src/cal_bc/projects/migrations/0005_create_model_section_field.py new file mode 100644 index 0000000..55b7a17 --- /dev/null +++ b/src/cal_bc/projects/migrations/0005_create_model_section_field.py @@ -0,0 +1,38 @@ +# Generated by Django 5.2.7 on 2025-10-18 23:24 + +import django.db.models.deletion +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("projects", "0004_create_model_section"), + ] + + operations = [ + migrations.CreateModel( + name="ModelSectionField", + fields=[ + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("name", models.CharField(null=False)), + ("cell", models.CharField(null=False)), + ("help_text", models.CharField(null=False)), + ( + "model_section", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + to="projects.modelsection", + null=False, + ), + ), + ], + ) + ] diff --git a/src/cal_bc/projects/migrations/0006_create_project_field.py b/src/cal_bc/projects/migrations/0006_create_project_field.py new file mode 100644 index 0000000..8ed1483 --- /dev/null +++ b/src/cal_bc/projects/migrations/0006_create_project_field.py @@ -0,0 +1,44 @@ +# Generated by Django 5.2.7 on 2025-10-18 23:24 + +import django.db.models.deletion +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("projects", "0005_create_model_section_field"), + ] + + operations = [ + migrations.CreateModel( + name="ProjectField", + fields=[ + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("value", models.CharField(null=False)), + ( + "model_section_field", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + to="projects.modelsectionfield", + null=False, + ), + ), + ( + "project", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + to="projects.project", + null=False, + ), + ), + ], + ), + ] diff --git a/src/cal_bc/projects/models/model.py b/src/cal_bc/projects/models/model.py new file mode 100644 index 0000000..3f76bca --- /dev/null +++ b/src/cal_bc/projects/models/model.py @@ -0,0 +1,9 @@ +from django.db import models + + +class Model(models.Model): + name = models.CharField(null=False) + url = models.CharField(null=False) + + def __str__(self): + return self.name diff --git a/src/cal_bc/projects/models/model_section.py b/src/cal_bc/projects/models/model_section.py new file mode 100644 index 0000000..50982ae --- /dev/null +++ b/src/cal_bc/projects/models/model_section.py @@ -0,0 +1,14 @@ +from django.db import models + +from .model import Model + + +class ModelSection(models.Model): + name = models.CharField(null=False) + help_text = models.CharField(null=False) + model = models.ForeignKey( + Model, on_delete=models.CASCADE, related_name="sections", null=False + ) + + def __str__(self): + return self.name diff --git a/src/cal_bc/projects/models/model_section_field.py b/src/cal_bc/projects/models/model_section_field.py new file mode 100644 index 0000000..d07668f --- /dev/null +++ b/src/cal_bc/projects/models/model_section_field.py @@ -0,0 +1,18 @@ +from django.db import models + +from .model_section import ModelSection + + +class ModelSectionField(models.Model): + name = models.CharField(null=False) + cell = models.CharField(null=False) + help_text = models.CharField(null=False) + section = models.ForeignKey( + ModelSection, + on_delete=models.CASCADE, + related_name="section_fields", + null=False, + ) + + def __str__(self): + return self.name diff --git a/src/cal_bc/projects/models/project.py b/src/cal_bc/projects/models/project.py index 2c0efde..6294727 100644 --- a/src/cal_bc/projects/models/project.py +++ b/src/cal_bc/projects/models/project.py @@ -1,6 +1,8 @@ from django.db import models from django.utils.translation import gettext as _ +from .model import Model + class Project(models.Model): class District(models.IntegerChoices): @@ -17,83 +19,86 @@ class District(models.IntegerChoices): ELEVEN = 11, _("District 11 - San Diego") TWELVE = 12, _("District 12 - Orange County") - class HighwayCapacityType(models.TextChoices): - GENERAL_HIGHWAY = "general_highway", _("General Highway") - HOV_LANE_ADDITION = "hov_lane_addition", _("HOV Lane Addition") - HOT_LANE_ADDITION = "hot_lane_addition", _("HOT Lane Addition") - PASSING_LANE = "passing_lane", _("Passing Lane") - INTERSECTION = "intersection", _("Intersection") - TRUCK_ONLY_LANE = "truck_only_lane", _("Truck Only Lane") - BYPASS = "bypass", _("Bypass") - QUEUING = "queuing", _("Queuing") - PAVEMENT = "pavement", _("Pavement") + # class HighwayCapacityType(models.TextChoices): + # GENERAL_HIGHWAY = "general_highway", _("General Highway") + # HOV_LANE_ADDITION = "hov_lane_addition", _("HOV Lane Addition") + # HOT_LANE_ADDITION = "hot_lane_addition", _("HOT Lane Addition") + # PASSING_LANE = "passing_lane", _("Passing Lane") + # INTERSECTION = "intersection", _("Intersection") + # TRUCK_ONLY_LANE = "truck_only_lane", _("Truck Only Lane") + # BYPASS = "bypass", _("Bypass") + # QUEUING = "queuing", _("Queuing") + # PAVEMENT = "pavement", _("Pavement") - class RailTransitCapacityType(models.TextChoices): - PASSENGER_RAIL = "passenger_rail", _("Passenger Rail") - LIGHT_RAIL = "light_rail", _("Light Rail (LRT)") - HIGHWAY_RAIL_GRADE_CROSSING = ( - "highway_rail_grade_crossing", - _("Highway-Rail Grade Crossing"), - ) + # class RailTransitCapacityType(models.TextChoices): + # PASSENGER_RAIL = "passenger_rail", _("Passenger Rail") + # LIGHT_RAIL = "light_rail", _("Light Rail (LRT)") + # HIGHWAY_RAIL_GRADE_CROSSING = ( + # "highway_rail_grade_crossing", + # _("Highway-Rail Grade Crossing"), + # ) - class HighwayOperationalType(models.TextChoices): - AUXILIARY_LANE = "auxiliary_lane", _("Auxiliary Lane") - FREEWAY_CONNECTOR = "freeway_connector", _("Freeway Connector") - HOV_CONNECTOR = "hov_connector", _("HOV Connector") - HOV_DROP_RAMP = "hov_drop_ramp", _("HOV Drop Ramp") - OFF_RAMP_WIDENING = "off_ramp_widening", _("Off-Ramp Widening") - ON_RAMP_WIDENING = "on_ramp_widening", _("On-Ramp Widening") - HOT_LANE_CONVERSION = "hot_lane_conversion", _("Hot Lane Conversion") + # class HighwayOperationalType(models.TextChoices): + # AUXILIARY_LANE = "auxiliary_lane", _("Auxiliary Lane") + # FREEWAY_CONNECTOR = "freeway_connector", _("Freeway Connector") + # HOV_CONNECTOR = "hov_connector", _("HOV Connector") + # HOV_DROP_RAMP = "hov_drop_ramp", _("HOV Drop Ramp") + # OFF_RAMP_WIDENING = "off_ramp_widening", _("Off-Ramp Widening") + # ON_RAMP_WIDENING = "on_ramp_widening", _("On-Ramp Widening") + # HOT_LANE_CONVERSION = "hot_lane_conversion", _("Hot Lane Conversion") - class TransportationManagmentSystemsType(models.TextChoices): - RAMP_METERING = "ramp_metering", _("Ramp Metering") - RAMP_METERING_SIGNAL_COORDINATION = ( - "ramp_metering_signal_coordination", - _("Ramp Metering Signal Coordination"), - ) - INCIDENT_MANAGEMENT = "incident_management", _("Incident Management") - TRAVELER_INFORMATION = "traveler_information", _("Traveler Information") - ARTERIAL_SIGNAL_MANAGEMENT = ( - "arterial_signal_management", - _("Arterial Signal Management"), - ) - TRANSIT_VEHICLE_LOCATION = ( - "transit_vehicle_location", - _("Transit Vehicle Location (AVL)"), - ) - TRANSIT_VEHICLE_SIGNAL_PRIORITY = ( - "transit_vehicle_signal_priority", - _("Transit Vehicle Signal Priority"), - ) - BUS_RAPID_TRANSIT = "bus_rapid_transit", _("Bus Rapid Transit (BRT)") + # class TransportationManagmentSystemsType(models.TextChoices): + # RAMP_METERING = "ramp_metering", _("Ramp Metering") + # RAMP_METERING_SIGNAL_COORDINATION = ( + # "ramp_metering_signal_coordination", + # _("Ramp Metering Signal Coordination"), + # ) + # INCIDENT_MANAGEMENT = "incident_management", _("Incident Management") + # TRAVELER_INFORMATION = "traveler_information", _("Traveler Information") + # ARTERIAL_SIGNAL_MANAGEMENT = ( + # "arterial_signal_management", + # _("Arterial Signal Management"), + # ) + # TRANSIT_VEHICLE_LOCATION = ( + # "transit_vehicle_location", + # _("Transit Vehicle Location (AVL)"), + # ) + # TRANSIT_VEHICLE_SIGNAL_PRIORITY = ( + # "transit_vehicle_signal_priority", + # _("Transit Vehicle Signal Priority"), + # ) + # BUS_RAPID_TRANSIT = "bus_rapid_transit", _("Bus Rapid Transit (BRT)") - TYPE_CHOICES = { - _("Highway Capacity Expansion"): HighwayCapacityType, - _("Rail or Transit Capacity Expansion"): RailTransitCapacityType, - _("Highway Operational Improvement"): HighwayOperationalType, - _( - "Transportation Management Systems (TMS)" - ): TransportationManagmentSystemsType, - } + # TYPE_CHOICES = { + # _("Highway Capacity Expansion"): HighwayCapacityType, + # _("Rail or Transit Capacity Expansion"): RailTransitCapacityType, + # _("Highway Operational Improvement"): HighwayOperationalType, + # _( + # "Transportation Management Systems (TMS)" + # ): TransportationManagmentSystemsType, + # } - class Location(models.IntegerChoices): - SO_CAL = 1, _("Southern California") - NO_CAL = 2, _("Northern California") - RURAL = 3, _("Rural") + # class Location(models.IntegerChoices): + # SO_CAL = 1, _("Southern California") + # NO_CAL = 2, _("Northern California") + # RURAL = 3, _("Rural") - class DataDirection(models.IntegerChoices): - ONE_WAY = 1, _("One-Way") - TWO_WAY = 2, _("Two-Way") + # class DataDirection(models.IntegerChoices): + # ONE_WAY = 1, _("One-Way") + # TWO_WAY = 2, _("Two-Way") - name = models.CharField() - district = models.IntegerField(choices=District, null=True) - type = models.CharField(choices=TYPE_CHOICES, null=True) - location = models.IntegerField(choices=Location, null=True) - construction_period_length = models.IntegerField(null=True) - data_direction = models.IntegerField( - choices=DataDirection, default=DataDirection.TWO_WAY + name = models.CharField(null=False) + district = models.IntegerField(choices=District, null=False) + model = models.ForeignKey( + Model, on_delete=models.CASCADE, related_name="projects", null=False ) - peak_periods_length = models.IntegerField(default=5) + # type = models.CharField(choices=TYPE_CHOICES, null=True) + # location = models.IntegerField(choices=Location, null=True) + # construction_period_length = models.IntegerField(null=True) + # data_direction = models.IntegerField( + # choices=DataDirection, default=DataDirection.TWO_WAY + # ) + # peak_periods_length = models.IntegerField(default=5) def __str__(self): return self.name diff --git a/src/cal_bc/projects/models/project_field.py b/src/cal_bc/projects/models/project_field.py new file mode 100644 index 0000000..d4d2260 --- /dev/null +++ b/src/cal_bc/projects/models/project_field.py @@ -0,0 +1,20 @@ +from django.db import models + +from .model_section_field import ModelSectionField +from .project import Project + + +class ProjectField(models.Model): + project = models.ForeignKey( + Project, on_delete=models.CASCADE, related_name="fields", null=False + ) + model_section_field = models.ForeignKey( + ModelSectionField, + on_delete=models.CASCADE, + related_name="project_fields", + null=False, + ) + value = models.CharField(null=False) + + def __str__(self): + return self.value diff --git a/src/cal_bc/projects/templates/projects/_form.html b/src/cal_bc/projects/templates/projects/_form.html index 33256ea..998222c 100644 --- a/src/cal_bc/projects/templates/projects/_form.html +++ b/src/cal_bc/projects/templates/projects/_form.html @@ -51,7 +51,7 @@