diff --git a/ram/ram/db_router.py b/ram/ram/db_router.py new file mode 100644 index 0000000..64f20bd --- /dev/null +++ b/ram/ram/db_router.py @@ -0,0 +1,32 @@ +class TelemetryRouter: + db_table = "telemetry_10secs" + + def db_for_read(self, model, **hints): + """Send read operations to the correct database.""" + if model._meta.db_table == self.db_table: + return "telemetry" # Replace with your database name + return None # Default database + + def db_for_write(self, model, **hints): + """Send write operations to the correct database.""" + if model._meta.db_table == self.db_table: + return False # Prevent Django from writing RO tables + return None + + def allow_relation(self, obj1, obj2, **hints): + """ + Allow relations if a model in the auth or contenttypes apps is + involved. + """ + if ( + obj1._meta.db_table == self.db_table + or obj2._meta.db_table == self.db_table + ): + return True + return None + + def allow_migrate(self, db, app_label, model_name=None, **hints): + """Prevent Django from migrating this model if it's using a specific database.""" + if db == "telemetry": + return False # Prevent Django from creating/modifying tables + return None diff --git a/ram/ram/settings.py b/ram/ram/settings.py index 5071c9d..c232b2f 100644 --- a/ram/ram/settings.py +++ b/ram/ram/settings.py @@ -95,8 +95,16 @@ DATABASES = { "default": { "ENGINE": "django.db.backends.sqlite3", "NAME": STORAGE_DIR / "db.sqlite3", - } + }, + "telemetry": { + "ENGINE": "django.db.backends.postgresql", + "HOST": "127.0.0.1", + "NAME": "dccmonitor", + "USER": "dccmonitor", + "PASSWORD": "dccmonitor", + }, } +DATABASE_ROUTERS = ["ram.db_router.TelemetryRouter"] # Password validation diff --git a/ram/roster/admin.py b/ram/roster/admin.py index f1962aa..0ed9578 100644 --- a/ram/roster/admin.py +++ b/ram/roster/admin.py @@ -17,6 +17,7 @@ from roster.models import ( RollingStockImage, RollingStockProperty, RollingStockJournal, + RollingStockTelemetry, ) @@ -287,3 +288,29 @@ class RollingStockAdmin(SortableAdminBase, admin.ModelAdmin): download_csv.short_description = "Download selected items as CSV" actions = [publish, unpublish, download_csv] + + +@admin.register(RollingStockTelemetry) +class RollingTelemtryAdmin(admin.ModelAdmin): + list_filter = ("bucket", "cab") + list_display = ("bucket_highres", "cab", "max_speed", "avg_speed") + + def bucket_highres(self, obj): + return obj.bucket.strftime("%Y-%m-%d %H:%M:%S") + + bucket_highres.admin_order_field = "bucket" # Enable sorting + bucket_highres.short_description = "Bucket" # Column name in admin + + def get_changelist_instance(self, request): + changelist = super().get_changelist_instance(request) + changelist.list_display_links = None # Disable links + return changelist + + def has_add_permission(self, request): + return False # Disable adding new objects + + def has_change_permission(self, request, obj=None): + return False # Disable editing objects + + def has_delete_permission(self, request, obj=None): + return False # Disable deleting objects diff --git a/ram/roster/models.py b/ram/roster/models.py index 72fc261..e6dcf31 100644 --- a/ram/roster/models.py +++ b/ram/roster/models.py @@ -224,6 +224,20 @@ class RollingStockJournal(models.Model): objects = PublicManager() +# trick: this is technically an abstract class +# it is made readonly via db_router and admin to avoid any unwanted change +class RollingStockTelemetry(models.Model): + bucket = models.DateTimeField(primary_key=True, editable=False) + cab = models.PositiveIntegerField(editable=False) + avg_speed = models.FloatField(editable=False) + max_speed = models.PositiveIntegerField(editable=False) + + class Meta: + db_table = "telemetry_10secs" + ordering = ["cab", "bucket"] + verbose_name_plural = "Telemetries" + + # @receiver(models.signals.post_delete, sender=Cab) # def post_save_image(sender, instance, *args, **kwargs): # try: diff --git a/requirements.txt b/requirements.txt index bd3932c..38fa42f 100644 --- a/requirements.txt +++ b/requirements.txt @@ -8,7 +8,7 @@ django-countries django-health-check django-admin-sortable2 django-tinymce -# Optional: # psycopg2-binary +psycopg2-binary # Required by django-countries and not always installed # by default on modern venvs (like Python 3.12 on Fedora 39) setuptools