From ed585e6a569ea58efd77e065373d6c616ad23079 Mon Sep 17 00:00:00 2001 From: pacnpal <183241239+pacnpal@users.noreply.github.com> Date: Sun, 3 Nov 2024 20:21:39 +0000 Subject: [PATCH] fix commas --- history_tracking/__init__.py | 2 + history_tracking/admin.py | 3 + history_tracking/apps.py | 20 ++++ history_tracking/management/__init__.py | 0 .../management/commands/__init__.py | 0 .../management/commands/initialize_history.py | 99 +++++++++++++++++ history_tracking/migrations/0001_initial.py | 76 +++++++++++++ history_tracking/migrations/__init__.py | 0 history_tracking/mixins.py | 23 ++++ history_tracking/models.py | 17 +++ history_tracking/tests.py | 3 + history_tracking/views.py | 3 + parks/__pycache__/models.cpython-312.pyc | Bin 9881 -> 10429 bytes ..._alter_historicalpark_latitude_and_more.py | 80 ++++++++++++++ parks/models.py | 103 +++++++++--------- static/css/tailwind.css | 28 ----- templates/parks/park_detail.html | 17 ++- templates/parks/partials/park_list.html | 9 +- templates/rides/ride_detail.html | 4 +- .../__pycache__/settings.cpython-312.pyc | Bin 5627 -> 5645 bytes thrillwiki/settings.py | 1 + 21 files changed, 390 insertions(+), 98 deletions(-) create mode 100644 history_tracking/__init__.py create mode 100644 history_tracking/admin.py create mode 100644 history_tracking/apps.py create mode 100644 history_tracking/management/__init__.py create mode 100644 history_tracking/management/commands/__init__.py create mode 100644 history_tracking/management/commands/initialize_history.py create mode 100644 history_tracking/migrations/0001_initial.py create mode 100644 history_tracking/migrations/__init__.py create mode 100644 history_tracking/mixins.py create mode 100644 history_tracking/models.py create mode 100644 history_tracking/tests.py create mode 100644 history_tracking/views.py create mode 100644 parks/migrations/0006_alter_historicalpark_latitude_and_more.py diff --git a/history_tracking/__init__.py b/history_tracking/__init__.py new file mode 100644 index 00000000..946f71a0 --- /dev/null +++ b/history_tracking/__init__.py @@ -0,0 +1,2 @@ +# history_tracking/__init__.py +default_app_config = "history_tracking.apps.HistoryTrackingConfig" diff --git a/history_tracking/admin.py b/history_tracking/admin.py new file mode 100644 index 00000000..8c38f3f3 --- /dev/null +++ b/history_tracking/admin.py @@ -0,0 +1,3 @@ +from django.contrib import admin + +# Register your models here. diff --git a/history_tracking/apps.py b/history_tracking/apps.py new file mode 100644 index 00000000..cf058912 --- /dev/null +++ b/history_tracking/apps.py @@ -0,0 +1,20 @@ +# history_tracking/apps.py +from django.apps import AppConfig + + +class HistoryTrackingConfig(AppConfig): + default_auto_field = "django.db.models.BigAutoField" + name = "history_tracking" + + def ready(self): + from .mixins import HistoricalChangeMixin + from .models import Park + + models_with_history = [Park] + + for model in models_with_history: + # Check if mixin is already applied + if HistoricalChangeMixin not in model.history.model.__bases__: + model.history.model.__bases__ = ( + HistoricalChangeMixin, + ) + model.history.model.__bases__ diff --git a/history_tracking/management/__init__.py b/history_tracking/management/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/history_tracking/management/commands/__init__.py b/history_tracking/management/commands/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/history_tracking/management/commands/initialize_history.py b/history_tracking/management/commands/initialize_history.py new file mode 100644 index 00000000..51bd636f --- /dev/null +++ b/history_tracking/management/commands/initialize_history.py @@ -0,0 +1,99 @@ +# history_tracking/management/commands/initialize_history.py +from django.core.management.base import BaseCommand +from django.utils import timezone +from django.apps import apps +from django.db.models import Model +from simple_history.models import HistoricalRecords + + +class Command(BaseCommand): + help = "Initialize history records for existing objects with historical records" + + def add_arguments(self, parser): + parser.add_argument( + "--model", + type=str, + help="Specify model in format app_name.ModelName (e.g., history_tracking.Park)", + ) + parser.add_argument( + "--all", + action="store_true", + help="Initialize history for all models with historical records", + ) + parser.add_argument( + "--force", + action="store_true", + help="Create history even if records already exist", + ) + + def initialize_model(self, model, force=False): + total = model.objects.count() + initialized = 0 + model_name = f"{model._meta.app_label}.{model._meta.model_name}" + + self.stdout.write(f"Processing {model_name}: Found {total} records") + + for obj in model.objects.all(): + try: + if force or not obj.history.exists(): + obj.history.create( + history_date=timezone.now(), + history_type="+", + history_change_reason="Initial history record", + **{ + field.name: getattr(obj, field.name) + for field in obj._meta.fields + if not isinstance(field, HistoricalRecords) + }, + ) + initialized += 1 + self.stdout.write(f"Created history for {model_name} id={obj.pk}") + except Exception as e: + self.stdout.write( + self.style.ERROR( + f"Error creating history for {model_name} id={obj.pk}: {str(e)}" + ) + ) + + return initialized, total + + def handle(self, *args, **options): + if not options["model"] and not options["all"]: + self.stdout.write( + self.style.ERROR("Please specify either --model or --all") + ) + return + + force = options["force"] + total_initialized = 0 + total_records = 0 + + if options["model"]: + try: + app_label, model_name = options["model"].split(".") + model = apps.get_model(app_label, model_name) + if hasattr(model, "history"): + initialized, total = self.initialize_model(model, force) + total_initialized += initialized + total_records += total + else: + self.stdout.write( + self.style.ERROR( + f'Model {options["model"]} does not have historical records' + ) + ) + except Exception as e: + self.stdout.write(self.style.ERROR(str(e))) + else: + # Process all models with historical records + for model in apps.get_models(): + if hasattr(model, "history"): + initialized, total = self.initialize_model(model, force) + total_initialized += initialized + total_records += total + + self.stdout.write( + self.style.SUCCESS( + f"Successfully initialized {total_initialized} of {total_records} total records" + ) + ) diff --git a/history_tracking/migrations/0001_initial.py b/history_tracking/migrations/0001_initial.py new file mode 100644 index 00000000..e8d71312 --- /dev/null +++ b/history_tracking/migrations/0001_initial.py @@ -0,0 +1,76 @@ +# Generated by Django 5.1.2 on 2024-11-03 19:59 + +import django.db.models.deletion +import history_tracking.mixins +import simple_history.models +from django.conf import settings +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.CreateModel( + name="Park", + fields=[ + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("name", models.CharField(max_length=200)), + ], + ), + migrations.CreateModel( + name="HistoricalPark", + fields=[ + ( + "id", + models.BigIntegerField( + auto_created=True, blank=True, db_index=True, verbose_name="ID" + ), + ), + ("name", models.CharField(max_length=200)), + ("history_id", models.AutoField(primary_key=True, serialize=False)), + ("history_date", models.DateTimeField(db_index=True)), + ("history_change_reason", models.CharField(max_length=100, null=True)), + ( + "history_type", + models.CharField( + choices=[("+", "Created"), ("~", "Changed"), ("-", "Deleted")], + max_length=1, + ), + ), + ( + "history_user", + models.ForeignKey( + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name="+", + to=settings.AUTH_USER_MODEL, + ), + ), + ], + options={ + "verbose_name": "historical park", + "verbose_name_plural": "historical parks", + "ordering": ("-history_date", "-history_id"), + "get_latest_by": ("history_date", "history_id"), + }, + bases=( + history_tracking.mixins.HistoricalChangeMixin, + simple_history.models.HistoricalChanges, + models.Model, + ), + ), + ] diff --git a/history_tracking/migrations/__init__.py b/history_tracking/migrations/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/history_tracking/mixins.py b/history_tracking/mixins.py new file mode 100644 index 00000000..fd81e158 --- /dev/null +++ b/history_tracking/mixins.py @@ -0,0 +1,23 @@ +# history_tracking/mixins.py + + +class HistoricalChangeMixin: + @property + def diff_against_previous(self): + prev_record = self.prev_record + if not prev_record: + return {} + + changes = {} + for field in self.__dict__: + if field not in [ + "history_date", + "history_id", + "history_type", + "history_user_id", + ] and not field.startswith("_"): + old_value = getattr(prev_record, field) + new_value = getattr(self, field) + if old_value != new_value: + changes[field] = {"old": old_value, "new": new_value} + return changes diff --git a/history_tracking/models.py b/history_tracking/models.py new file mode 100644 index 00000000..8fc5524b --- /dev/null +++ b/history_tracking/models.py @@ -0,0 +1,17 @@ +# history_tracking/models.py +from django.db import models +from simple_history.models import HistoricalRecords +from .mixins import HistoricalChangeMixin + + +class Park(models.Model): + name = models.CharField(max_length=200) + # ... other fields ... + history = HistoricalRecords() + + @property + def _history_model(self): + return self.history.model + + +# Apply the mixin diff --git a/history_tracking/tests.py b/history_tracking/tests.py new file mode 100644 index 00000000..7ce503c2 --- /dev/null +++ b/history_tracking/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/history_tracking/views.py b/history_tracking/views.py new file mode 100644 index 00000000..91ea44a2 --- /dev/null +++ b/history_tracking/views.py @@ -0,0 +1,3 @@ +from django.shortcuts import render + +# Create your views here. diff --git a/parks/__pycache__/models.cpython-312.pyc b/parks/__pycache__/models.cpython-312.pyc index a575f4dd27167f7107665715dcaf7fae62414852..e2a426ed08dcde68de439aefa557f8a524999f00 100644 GIT binary patch delta 1170 zcmZXTZD?Cn7{~9qH@VI7c9S&C`zuLPvyS$|O1qY_mZ3vr#w)ZBUgJCx>f?K z`i;E@Hv$JYodfH83z1Fj@g0sestd}xiZQgv&nRvod3K*KtgI>GDJfUuW7%vnov0~ADJCUrP4Udxw1jgt z#i>jx9cJYeR{{v0VDDVyi*75kPp0CwMO-$UC`acpUWVE51VKeSyH*OoR^ z6`D)AVy@h>DR}Ryyt2`M3z2)~Y10H<=o(k!;$tEnr5aC?OiL&FfXui2iF!%J@}YoF zgFg;PQ^-*(-Q-Df!e(=;vN)4XVkw8u&`3=aAB&0Ncv5;Plfctt#@4|fpuV_BKD8a! zm0ww%Y;dfe&mXRb>LWwUoQ( z2Py-r=C$bEqtDThj?X`FpC`XLMojwqtV-$I;TT?D2UR!AgU%bQa+xmt6=}F{qi@LP zp1;v;`KC9BI@h6|5JjH3Cs?XlZ`I$rY+tl5dlo%wi7!*1r8b(MY$!Q{y3TNW)O4eM zL1B^3Ka3?xe3l}LUj})RLWG0pd(db4%btKe^dkgc1Ur19?90&0G+uiQm?shkq?w@xyGo6-b=9p9xSt?{`iP?h>*<8!asc`R1r)D>j zno*dX2VI6z6xdsJDT3-jd=M%yvFI{{3VNwP=D1P5MCW8L-G>j~`#T(dKhE!EQ=)-; zZ8jSz{Oz0eb&T+jIF&Yp@vlUsv@Bw^9^aI1mP>H=`sbn#L(dwQ1NF;g^(($3?@pYW z;#Qo&6>EE3_sNnaH*4nsa^-Bs15ko0^b1gqe(L=o$t4*>T4S6VfYv}WRa_v?o0c?i z15H>i!%aEc`UV(;JBpoXEzcusZ3ci@#BK4(2lJl;+OS`;_2AALhRdm~pI diff --git a/parks/migrations/0006_alter_historicalpark_latitude_and_more.py b/parks/migrations/0006_alter_historicalpark_latitude_and_more.py new file mode 100644 index 00000000..cbd59494 --- /dev/null +++ b/parks/migrations/0006_alter_historicalpark_latitude_and_more.py @@ -0,0 +1,80 @@ +# Generated by Django 5.1.2 on 2024-11-03 19:59 + +import django.core.validators +import parks.models +from decimal import Decimal +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("parks", "0005_normalize_coordinates"), + ] + + operations = [ + migrations.AlterField( + model_name="historicalpark", + name="latitude", + field=models.DecimalField( + blank=True, + decimal_places=6, + help_text="Latitude coordinate (-90 to 90)", + max_digits=9, + null=True, + validators=[ + django.core.validators.MinValueValidator(Decimal("-90")), + django.core.validators.MaxValueValidator(Decimal("90")), + parks.models.validate_latitude_digits, + ], + ), + ), + migrations.AlterField( + model_name="historicalpark", + name="longitude", + field=models.DecimalField( + blank=True, + decimal_places=6, + help_text="Longitude coordinate (-180 to 180)", + max_digits=10, + null=True, + validators=[ + django.core.validators.MinValueValidator(Decimal("-180")), + django.core.validators.MaxValueValidator(Decimal("180")), + parks.models.validate_longitude_digits, + ], + ), + ), + migrations.AlterField( + model_name="park", + name="latitude", + field=models.DecimalField( + blank=True, + decimal_places=6, + help_text="Latitude coordinate (-90 to 90)", + max_digits=9, + null=True, + validators=[ + django.core.validators.MinValueValidator(Decimal("-90")), + django.core.validators.MaxValueValidator(Decimal("90")), + parks.models.validate_latitude_digits, + ], + ), + ), + migrations.AlterField( + model_name="park", + name="longitude", + field=models.DecimalField( + blank=True, + decimal_places=6, + help_text="Longitude coordinate (-180 to 180)", + max_digits=10, + null=True, + validators=[ + django.core.validators.MinValueValidator(Decimal("-180")), + django.core.validators.MaxValueValidator(Decimal("180")), + parks.models.validate_longitude_digits, + ], + ), + ), + ] diff --git a/parks/models.py b/parks/models.py index 6db7525d..b3f1f95c 100644 --- a/parks/models.py +++ b/parks/models.py @@ -16,12 +16,14 @@ def normalize_coordinate(value, max_digits, decimal_places): try: if value is None: return None - + # Convert to Decimal for precise handling value = Decimal(str(value)) # Round to specified decimal places - value = Decimal(value.quantize(Decimal('0.' + '0' * decimal_places), rounding=ROUND_DOWN)) - + value = Decimal( + value.quantize(Decimal("0." + "0" * decimal_places), rounding=ROUND_DOWN) + ) + return value except (TypeError, ValueError, InvalidOperation): return None @@ -34,10 +36,10 @@ def validate_coordinate_digits(value, max_digits, decimal_places): # Convert to Decimal for precise handling value = Decimal(str(value)) # Round to exactly 6 decimal places - value = value.quantize(Decimal('0.000001'), rounding=ROUND_DOWN) + value = value.quantize(Decimal("0.000001"), rounding=ROUND_DOWN) return value except (InvalidOperation, TypeError): - raise ValidationError('Invalid coordinate value.') + raise ValidationError("Invalid coordinate value.") return value @@ -53,21 +55,19 @@ def validate_longitude_digits(value): class Park(models.Model): STATUS_CHOICES = [ - ('OPERATING', 'Operating'), - ('CLOSED_TEMP', 'Temporarily Closed'), - ('CLOSED_PERM', 'Permanently Closed'), - ('UNDER_CONSTRUCTION', 'Under Construction'), - ('DEMOLISHED', 'Demolished'), - ('RELOCATED', 'Relocated'), + ("OPERATING", "Operating"), + ("CLOSED_TEMP", "Temporarily Closed"), + ("CLOSED_PERM", "Permanently Closed"), + ("UNDER_CONSTRUCTION", "Under Construction"), + ("DEMOLISHED", "Demolished"), + ("RELOCATED", "Relocated"), ] name = models.CharField(max_length=255) slug = models.SlugField(max_length=255, unique=True) description = models.TextField(blank=True) status = models.CharField( - max_length=20, - choices=STATUS_CHOICES, - default='OPERATING' + max_length=20, choices=STATUS_CHOICES, default="OPERATING" ) # Location fields @@ -76,24 +76,24 @@ class Park(models.Model): decimal_places=6, null=True, blank=True, - help_text='Latitude coordinate (-90 to 90)', + help_text="Latitude coordinate (-90 to 90)", validators=[ - MinValueValidator(Decimal('-90')), - MaxValueValidator(Decimal('90')), + MinValueValidator(Decimal("-90")), + MaxValueValidator(Decimal("90")), validate_latitude_digits, - ] + ], ) longitude = models.DecimalField( max_digits=10, decimal_places=6, null=True, blank=True, - help_text='Longitude coordinate (-180 to 180)', + help_text="Longitude coordinate (-180 to 180)", validators=[ - MinValueValidator(Decimal('-180')), - MaxValueValidator(Decimal('180')), + MinValueValidator(Decimal("-180")), + MaxValueValidator(Decimal("180")), validate_longitude_digits, - ] + ], ) street_address = models.CharField(max_length=255, blank=True) city = models.CharField(max_length=255, blank=True) @@ -106,32 +106,22 @@ class Park(models.Model): closing_date = models.DateField(null=True, blank=True) operating_season = models.CharField(max_length=255, blank=True) size_acres = models.DecimalField( - max_digits=10, - decimal_places=2, - null=True, - blank=True + max_digits=10, decimal_places=2, null=True, blank=True ) website = models.URLField(blank=True) # Statistics average_rating = models.DecimalField( - max_digits=3, - decimal_places=2, - null=True, - blank=True + max_digits=3, decimal_places=2, null=True, blank=True ) total_rides = models.IntegerField(null=True, blank=True) total_roller_coasters = models.IntegerField(null=True, blank=True) # Relationships owner = models.ForeignKey( - Company, - on_delete=models.SET_NULL, - null=True, - blank=True, - related_name='parks' + Company, on_delete=models.SET_NULL, null=True, blank=True, related_name="parks" ) - photos = GenericRelation(Photo, related_query_name='park') + photos = GenericRelation(Photo, related_query_name="park") # Metadata created_at = models.DateTimeField(auto_now_add=True, null=True) @@ -139,7 +129,7 @@ class Park(models.Model): history = HistoricalRecords() class Meta: - ordering = ['name'] + ordering = ["name"] def __str__(self): return self.name @@ -147,17 +137,28 @@ class Park(models.Model): def save(self, *args, **kwargs): if not self.slug: self.slug = slugify(self.name) - + # Normalize coordinates before saving if self.latitude is not None: self.latitude = normalize_coordinate(self.latitude, 9, 6) if self.longitude is not None: self.longitude = normalize_coordinate(self.longitude, 10, 6) - + super().save(*args, **kwargs) def get_absolute_url(self): - return reverse('parks:park_detail', kwargs={'slug': self.slug}) + return reverse("parks:park_detail", kwargs={"slug": self.slug}) + + @property + def formatted_location(self): + parts = [] + if self.city: + parts.append(self.city) + if self.state: + parts.append(self.state) + if self.country: + parts.append(self.country) + return ", ".join(parts) @classmethod def get_by_slug(cls, slug): @@ -166,7 +167,7 @@ class Park(models.Model): return cls.objects.get(slug=slug), False except cls.DoesNotExist: # Check historical slugs - history = cls.history.filter(slug=slug).order_by('-history_date').first() + history = cls.history.filter(slug=slug).order_by("-history_date").first() if history: try: return cls.objects.get(id=history.id), True @@ -176,11 +177,7 @@ class Park(models.Model): class ParkArea(models.Model): - park = models.ForeignKey( - Park, - on_delete=models.CASCADE, - related_name='areas' - ) + park = models.ForeignKey(Park, on_delete=models.CASCADE, related_name="areas") name = models.CharField(max_length=255) slug = models.SlugField(max_length=255) description = models.TextField(blank=True) @@ -193,8 +190,8 @@ class ParkArea(models.Model): history = HistoricalRecords() class Meta: - ordering = ['name'] - unique_together = ['park', 'slug'] + ordering = ["name"] + unique_together = ["park", "slug"] def __str__(self): return f"{self.name} at {self.park.name}" @@ -205,10 +202,10 @@ class ParkArea(models.Model): super().save(*args, **kwargs) def get_absolute_url(self): - return reverse('parks:area_detail', kwargs={ - 'park_slug': self.park.slug, - 'area_slug': self.slug - }) + return reverse( + "parks:area_detail", + kwargs={"park_slug": self.park.slug, "area_slug": self.slug}, + ) @classmethod def get_by_slug(cls, slug): @@ -217,7 +214,7 @@ class ParkArea(models.Model): return cls.objects.get(slug=slug), False except cls.DoesNotExist: # Check historical slugs - history = cls.history.filter(slug=slug).order_by('-history_date').first() + history = cls.history.filter(slug=slug).order_by("-history_date").first() if history: try: return cls.objects.get(id=history.id), True diff --git a/static/css/tailwind.css b/static/css/tailwind.css index 5cb989cd..a27ec1c5 100644 --- a/static/css/tailwind.css +++ b/static/css/tailwind.css @@ -2401,10 +2401,6 @@ select { height: 300px; } -.h-\[400px\] { - height: 400px; -} - .h-full { height: 100%; } @@ -2860,11 +2856,6 @@ select { background-color: rgb(202 138 4 / var(--tw-bg-opacity)); } -.bg-purple-100 { - --tw-bg-opacity: 1; - background-color: rgb(243 232 255 / var(--tw-bg-opacity)); -} - .bg-opacity-50 { --tw-bg-opacity: 0.5; } @@ -3165,11 +3156,6 @@ select { color: rgb(133 77 14 / var(--tw-text-opacity)); } -.text-purple-800 { - --tw-text-opacity: 1; - color: rgb(107 33 168 / var(--tw-text-opacity)); -} - .opacity-0 { opacity: 0; } @@ -3569,11 +3555,6 @@ select { background-color: rgb(113 63 18 / var(--tw-bg-opacity)); } -.dark\:bg-purple-700:is(.dark *) { - --tw-bg-opacity: 1; - background-color: rgb(126 34 206 / var(--tw-bg-opacity)); -} - .dark\:from-gray-950:is(.dark *) { --tw-gradient-from: #030712 var(--tw-gradient-from-position); --tw-gradient-to: rgb(3 7 18 / 0) var(--tw-gradient-to-position); @@ -3689,11 +3670,6 @@ select { color: rgb(254 252 232 / var(--tw-text-opacity)); } -.dark\:text-purple-50:is(.dark *) { - --tw-text-opacity: 1; - color: rgb(250 245 255 / var(--tw-text-opacity)); -} - .dark\:ring-1:is(.dark *) { --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color); --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color); @@ -3838,10 +3814,6 @@ select { margin-right: 1.5rem; } - .lg\:mt-0 { - margin-top: 0px; - } - .lg\:flex { display: flex; } diff --git a/templates/parks/park_detail.html b/templates/parks/park_detail.html index d78f0673..b9d78caf 100644 --- a/templates/parks/park_detail.html +++ b/templates/parks/park_detail.html @@ -13,14 +13,11 @@

{{ park.name }}

{% if park.city or park.state or park.country %} -

- - {% if park.city %}{{ park.city }}{% endif %} - {% if park.city and park.state %}, {% endif %} - {% if park.state %}{{ park.state }}{% endif %} - {% if park.country and park.state or park.city %}, {% endif %} - {% if park.country %}{{ park.country }}{% endif %} -

+ {% spaceless %} +

+ {% if park.city %}{{ park.city }}{% endif %}{% if park.city and park.state %}, {% endif %}{% if park.state %}{{ park.state }}{% endif %}{% if park.country and park.state or park.city %}, {% endif %}{% if park.country %}{{ park.country }}{% endif %} +

+ {% endspaceless %} {% endif %}
{% if user.is_authenticated %} @@ -191,10 +188,10 @@ {% endif %}
- {% for field, change in record.diff_against_previous %} + {% for field, changes in record.diff_against_previous.items %}
{{ field }}: - {{ change.old }} → {{ change.new }} + {{ changes.old }} → {{ changes.new }}
{% endfor %}
diff --git a/templates/parks/partials/park_list.html b/templates/parks/partials/park_list.html index 8db88643..21d4e46b 100644 --- a/templates/parks/partials/park_list.html +++ b/templates/parks/partials/park_list.html @@ -19,11 +19,10 @@ {% if park.city or park.state or park.country %}

- {% if park.city %}{{ park.city }}{% endif %} - {% if park.city and park.state %}, {% endif %} - {% if park.state %}{{ park.state }}{% endif %} - {% if park.country and park.state or park.city %}, {% endif %} - {% if park.country %}{{ park.country }}{% endif %} + {% spaceless %} + {% if park.city %}{{ park.city }}{% endif %}{% if park.city and park.state %}, {% endif %}{% if park.state %}{{ park.state }}{% endif %}{% if park.country and park.state or park.city %}, {% endif %}{% if park.country %}{{ park.country }}{% endif %} +

+ {% endspaceless %}

{% endif %}
diff --git a/templates/rides/ride_detail.html b/templates/rides/ride_detail.html index 3b5ded95..7c406a56 100644 --- a/templates/rides/ride_detail.html +++ b/templates/rides/ride_detail.html @@ -205,10 +205,10 @@ {% endif %}
- {% for field, change in record.diff_against_previous %} + {% for field, changes in record.diff_against_previous.items %}
{{ field }}: - {{ change.old }} → {{ change.new }} + {{ changes.old }} → {{ changes.new }}
{% endfor %}
diff --git a/thrillwiki/__pycache__/settings.cpython-312.pyc b/thrillwiki/__pycache__/settings.cpython-312.pyc index dce84ffa7d2782d0e42a801386170810fee91bb2..0de634859a82c2863f026c2ffa45d0c6cca94019 100644 GIT binary patch delta 130 zcmeyZ-K)cUnwOW00SL6Ns;A%I$lJioD6_eb`6HvyErE>8;*$KL%J`C^#N_PEy!6fW ztan(H#es@%arpQ@$_}|4-F}j0*b$61QJCGo9nnDnAyxhY>Ulzcw<=^ bYbIL>N3qKaF*WdgvfDgcIEIO(3MdT#Q+Fku delta 93 zcmeCx`K`@+nwOW00SGi+s-+*_$lJioD80Fl`6J`ziL7^67{w;%afx$F0_9&a0*NB| r%@epHnAyxgZ1c_Ucw<=^t0(&iN3qKYF*Wdgve~>=IEIO(5-1G-w}u#d diff --git a/thrillwiki/settings.py b/thrillwiki/settings.py index 9449c51a..ac80c1c7 100644 --- a/thrillwiki/settings.py +++ b/thrillwiki/settings.py @@ -44,6 +44,7 @@ INSTALLED_APPS = [ "email_service", "media.apps.MediaConfig", "moderation", + "history_tracking", ] MIDDLEWARE = [