From e0adddb049079a585cb2359559e3fecd181d6950 Mon Sep 17 00:00:00 2001 From: Irwan Fathurrahman Date: Fri, 21 Jun 2024 09:59:51 +0700 Subject: [PATCH] Refactor --- .run/Run Server.run.xml | 27 ---- deployment/docker-compose.yml | 8 +- django_project/core/models/__init__.py | 0 django_project/core/models/general.py | 30 ++++ django_project/core/settings/base.py | 11 +- django_project/core/settings/contrib.py | 1 - django_project/core/settings/project.py | 10 +- django_project/ground_observations/admin.py | 62 +++++++- django_project/ground_observations/apps.py | 12 +- .../migrations/0001_initial.py | 55 +++++--- django_project/ground_observations/models.py | 132 ++++++++++-------- django_project/ground_observations/tests.py | 7 +- django_project/ground_observations/views.py | 7 +- django_project/manage.py | 2 +- 14 files changed, 231 insertions(+), 133 deletions(-) delete mode 100644 .run/Run Server.run.xml create mode 100644 django_project/core/models/__init__.py create mode 100644 django_project/core/models/general.py diff --git a/.run/Run Server.run.xml b/.run/Run Server.run.xml deleted file mode 100644 index 1ba13836..00000000 --- a/.run/Run Server.run.xml +++ /dev/null @@ -1,27 +0,0 @@ - - - - - \ No newline at end of file diff --git a/deployment/docker-compose.yml b/deployment/docker-compose.yml index eb94e522..4c18036f 100644 --- a/deployment/docker-compose.yml +++ b/deployment/docker-compose.yml @@ -12,15 +12,13 @@ volumes: x-common-django: &default-common-django image: kartoza/${COMPOSE_PROJECT_NAME:-django_project}:${DJANGO_TAG:-1.0.0} - env_file: - - .env environment: - DJANGO_SETTINGS_MODULE=${DJANGO_SETTINGS_MODULE:-core.settings.dev} - + - ADMIN_USERNAME=${ADMIN_USERNAME:-admin} - ADMIN_PASSWORD=${ADMIN_PASSWORD:-admin} - ADMIN_EMAIL=${ADMIN_EMAIL:-admin@example.com} - + - DATABASE_NAME=${DATABASE_NAME:-django} - DATABASE_USERNAME=${DATABASE_USERNAME:-docker} - DATABASE_PASSWORD=${DATABASE_PASSWORD:-docker} @@ -28,7 +26,7 @@ x-common-django: - DATABASE_PORT=${DATABASE_PORT:-5432} - REDIS_HOST=${REDIS_HOST:-redis} - REDIS_PASSWORD=${REDIS_PASSWORD:-redis_password} - + - RABBITMQ_HOST=${RABBITMQ_HOST:-rabbitmq} - SENTRY_DSN=${SENTRY_DSN:-} - SECRET_KEY=SECRET_KEY diff --git a/django_project/core/models/__init__.py b/django_project/core/models/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/django_project/core/models/general.py b/django_project/core/models/general.py new file mode 100644 index 00000000..63c1d451 --- /dev/null +++ b/django_project/core/models/general.py @@ -0,0 +1,30 @@ +# coding=utf-8 +""" +Tomorrow Now GAP. + +.. note:: General models +""" + +from django.db import models + + +class Definition(models.Model): + """Abstract model for Model that has name and description. + + Attributes: + name (str): Name of object. + description (str): Description of object. + """ + + name = models.CharField( + max_length=512 + ) + description = models.TextField( + null=True, blank=True + ) + + def __str__(self): + return self.name + + class Meta: # noqa: D106 + abstract = True diff --git a/django_project/core/settings/base.py b/django_project/core/settings/base.py index 29bae4a9..6eaeaae4 100644 --- a/django_project/core/settings/base.py +++ b/django_project/core/settings/base.py @@ -78,10 +78,6 @@ # Python dotted path to the WSGI application used by Django's runserver. WSGI_APPLICATION = 'core.wsgi.application' -# import SECRET_KEY into current namespace -# noinspection PyUnresolvedReferences -from core.settings.secret import SECRET_KEY # noqa - TEMPLATES = [ { 'BACKEND': 'django.template.backends.django.DjangoTemplates', @@ -148,9 +144,4 @@ LOGIN_URL = '/account/login/' LOGIN_REDIRECT_URL = '/' -"""try: - SECRET_KEY = os.environ['SECRET_KEY'] - if SECRET_KEY in ['', "''"]: - raise Exception('SECRET_KEY is required in env.') -except KeyError: - raise Exception('SECRET_KEY is required in env.')""" +from .secret import SECRET_KEY # noqa diff --git a/django_project/core/settings/contrib.py b/django_project/core/settings/contrib.py index 24c2fe24..62d153fe 100644 --- a/django_project/core/settings/contrib.py +++ b/django_project/core/settings/contrib.py @@ -46,7 +46,6 @@ 'django.contrib.auth.backends.ModelBackend', # default 'guardian.backends.ObjectPermissionBackend', ) -DEFAULT_AUTO_FIELD = 'django.db.models.AutoField' CELERY_RESULT_BACKEND = 'django-db' TEMPLATES[0]['OPTIONS']['context_processors'] += [ diff --git a/django_project/core/settings/project.py b/django_project/core/settings/project.py index fccbd45f..cee65cdb 100644 --- a/django_project/core/settings/project.py +++ b/django_project/core/settings/project.py @@ -14,10 +14,10 @@ DATABASES = { 'default': { 'ENGINE': 'django.contrib.gis.db.backends.postgis', - 'NAME': 'django', - 'USER': 'docker', - 'PASSWORD': 'docker', - 'HOST': 'db', + 'NAME': os.environ['DATABASE_NAME'], + 'USER': os.environ['DATABASE_USERNAME'], + 'PASSWORD': os.environ['DATABASE_PASSWORD'], + 'HOST': os.environ['DATABASE_HOST'], 'PORT': 5432, 'TEST_NAME': 'unittests', } @@ -35,3 +35,5 @@ TEMPLATES[0]['DIRS'] += [ absolute_path('frontend', 'templates'), ] + +DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' diff --git a/django_project/ground_observations/admin.py b/django_project/ground_observations/admin.py index 8c38f3f3..5aaf2ab4 100644 --- a/django_project/ground_observations/admin.py +++ b/django_project/ground_observations/admin.py @@ -1,3 +1,63 @@ +# coding=utf-8 +""" +Tomorrow Now GAP. + +.. note:: Admins +""" from django.contrib import admin -# Register your models here. +from .models import ( + Attribute, Country, Provider, Measurement, Station +) + + +@admin.register(Attribute) +class AttributeAdmin(admin.ModelAdmin): + """Attribute admin.""" + + list_display = ( + 'name', 'description' + ) + search_fields = ('name',) + + +@admin.register(Country) +class CountryAdmin(admin.ModelAdmin): + """Country admin.""" + + list_display = ( + 'name', 'description' + ) + search_fields = ('name',) + + +@admin.register(Provider) +class ProviderAdmin(admin.ModelAdmin): + """Provider admin.""" + + list_display = ( + 'name', 'description' + ) + search_fields = ('name',) + + +@admin.register(Measurement) +class MeasurementAdmin(admin.ModelAdmin): + """Measurement admin.""" + + list_display = ( + 'station', 'attribute', 'date', 'value' + ) + list_filter = ('station', 'attribute') + search_fields = ('name',) + + +@admin.register(Station) +class StationAdmin(admin.ModelAdmin): + """Station admin.""" + + list_display = ( + 'name', 'country', 'provider' + ) + list_filter = ('country',) + search_fields = ('name',) diff --git a/django_project/ground_observations/apps.py b/django_project/ground_observations/apps.py index 8779c4f4..07f5ba96 100644 --- a/django_project/ground_observations/apps.py +++ b/django_project/ground_observations/apps.py @@ -1,6 +1,16 @@ +# coding=utf-8 +""" +Tomorrow Now GAP. + +.. note:: App Config +""" + from django.apps import AppConfig +from django.utils.translation import gettext_lazy as _ class GroundObservationsConfig(AppConfig): - default_auto_field = 'django.db.models.BigAutoField' + """App Config for GroundObservations.""" + name = 'ground_observations' + verbose_name = _('Ground Observations') diff --git a/django_project/ground_observations/migrations/0001_initial.py b/django_project/ground_observations/migrations/0001_initial.py index 69ab6af7..bf3c3b4e 100644 --- a/django_project/ground_observations/migrations/0001_initial.py +++ b/django_project/ground_observations/migrations/0001_initial.py @@ -1,9 +1,8 @@ -# Generated by Django 4.2.7 on 2024-06-20 07:46 +# Generated by Django 4.2.7 on 2024-06-21 02:55 import django.contrib.gis.db.models.fields from django.db import migrations, models import django.db.models.deletion -import uuid class Migration(migrations.Migration): @@ -17,40 +16,60 @@ class Migration(migrations.Migration): migrations.CreateModel( name='Attribute', fields=[ - ('id', models.AutoField(primary_key=True, serialize=False)), - ('attribute_id', models.UUIDField(default=uuid.uuid4, editable=False, unique=True)), - ('name', models.TextField()), - ('description', models.TextField()), + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=512)), + ('description', models.TextField(blank=True, null=True)), ], + options={ + 'abstract': False, + }, + ), + migrations.CreateModel( + name='Country', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=512)), + ('description', models.TextField(blank=True, null=True)), + ('iso_a3', models.TextField(unique=True)), + ('geometry', django.contrib.gis.db.models.fields.MultiPolygonField(srid=4326)), + ], + options={ + 'verbose_name_plural': 'countries', + }, ), migrations.CreateModel( name='Provider', fields=[ - ('id', models.AutoField(primary_key=True, serialize=False)), - ('provider_id', models.UUIDField(default=uuid.uuid4, editable=False, unique=True)), - ('name', models.TextField()), - ('description', models.TextField()), + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=512)), + ('description', models.TextField(blank=True, null=True)), ], + options={ + 'abstract': False, + }, ), migrations.CreateModel( name='Station', fields=[ - ('id', models.AutoField(primary_key=True, serialize=False)), - ('station_id', models.UUIDField(default=uuid.uuid4, editable=False, unique=True)), - ('name', models.TextField()), - ('country_ISO_A3', models.TextField()), + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=512)), + ('description', models.TextField(blank=True, null=True)), ('geometry', django.contrib.gis.db.models.fields.PointField(srid=4326)), - ('provider_id', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='ground_observations.provider', to_field='provider_id')), + ('country', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='ground_observations.country')), + ('provider', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='ground_observations.provider')), ], + options={ + 'abstract': False, + }, ), migrations.CreateModel( name='Measurement', fields=[ - ('id', models.AutoField(primary_key=True, serialize=False)), + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('date', models.DateField()), ('value', models.FloatField()), - ('attribute_id', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='ground_observations.attribute', to_field='attribute_id')), - ('station_id', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='ground_observations.station', to_field='station_id')), + ('attribute', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='ground_observations.attribute')), + ('station', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='ground_observations.station')), ], ), ] diff --git a/django_project/ground_observations/models.py b/django_project/ground_observations/models.py index 4afb97b5..41aaec8c 100644 --- a/django_project/ground_observations/models.py +++ b/django_project/ground_observations/models.py @@ -1,92 +1,102 @@ -from django.db import models +# coding=utf-8 +""" +Tomorrow Now GAP. -# Create your models here. +.. note:: Models +""" -from django.contrib.gis.db import models as gis_models -import uuid +from django.contrib.gis.db import models -class Provider(models.Model): - """ - Model representing a data provider. - - Attributes: - provider_id (UUID): Unique identifier for the provider, generated automatically. - name (str): Name of the provider. - description (str): Description of the provider. - """ - provider_id = models.UUIDField(unique=True, default=uuid.uuid4, editable=False) - name = models.TextField() - description = models.TextField() +from core.models.general import Definition - def __str__(self): - return self.name -class Attribute(models.Model): - """ - Model representing an attribute of a measurement. - - Attributes: - attribute_id (UUID): Unique identifier for the attribute, generated automatically. - name (str): Name of the attribute. - description (str): Description of the attribute. +class Provider(Definition): + """Model representing a data provider. + + Override Definition model that contains name and description . """ - attribute_id = models.UUIDField(unique=True, default=uuid.uuid4, editable=False) - name = models.TextField() - description = models.TextField() - def __str__(self): - return self.name + pass + -class Country(models.Model): +class Attribute(Definition): + """Model representing an attribute of a measurement. + + Override Definition model that contains name and description . """ - Model representing a country. - + pass + + +class Country(Definition): + """Model representing a country. + + Override Definition model that contains name and description . + Attributes: name (str): Name of the country. - country_ISO_A3 (str): ISO A3 country code, unique. - geometry (Polygon): Polygon geometry representing the country boundaries. + iso_a3 (str): ISO A3 country code, unique. + geometry (Polygon): + MultiPolygonField geometry representing the country boundaries. """ - name = models.TextField() - country_ISO_A3 = models.TextField(unique=True) - geometry = gis_models.PolygonField(srid=4326) - def __str__(self): - return self.name + iso_a3 = models.TextField( + unique=True + ) + geometry = models.MultiPolygonField( + srid=4326 + ) + + class Meta: + verbose_name_plural = "countries" + + +class Station(Definition): + """Model representing a ground observation station. + + Override Definition model that contains name and description . -class Station(models.Model): - """ - Model representing a ground observation station. - Attributes: - station_id (UUID): Unique identifier for the station, generated automatically. name (str): Name of the station. - country (ForeignKey): Foreign key referencing the Country model based on country_ISO_A3. - geometry (Point): Point geometry representing the location of the station. - provider_id (ForeignKey): Foreign key referencing the Provider model based on provider_id. + country (ForeignKey): + Foreign key referencing the Country model based on country_ISO_A3. + geometry (Point): + Point geometry representing the location of the station. + provider (ForeignKey): + Foreign key referencing the Provider model based on provider_id. """ - station_id = models.UUIDField(unique=True, default=uuid.uuid4, editable=False) - name = models.TextField() - country = models.ForeignKey(Country, on_delete=models.CASCADE, to_field='country_ISO_A3', db_column='country_ISO_A3') - geometry = gis_models.PointField(srid=4326) - provider_id = models.ForeignKey(Provider, on_delete=models.CASCADE, to_field='provider_id') - def __str__(self): - return self.name + country = models.ForeignKey( + Country, on_delete=models.CASCADE + ) + geometry = models.PointField( + srid=4326 + ) + provider = models.ForeignKey( + Provider, on_delete=models.CASCADE + ) + class Measurement(models.Model): """ Model representing a measurement taken at a station. - + Attributes: + station (ForeignKey): + Foreign key referencing the Station model based on station_id. + attribute (ForeignKey): + Foreign key referencing the Attribute model based on attribute_id. date (date): Date of the measurement. value (float): Value of the measurement. - station_id (ForeignKey): Foreign key referencing the Station model based on station_id. - attribute_id (ForeignKey): Foreign key referencing the Attribute model based on attribute_id. """ + + station = models.ForeignKey( + Station, on_delete=models.CASCADE + ) + attribute = models.ForeignKey( + Attribute, on_delete=models.CASCADE + ) date = models.DateField() value = models.FloatField() - station_id = models.ForeignKey(Station, on_delete=models.CASCADE, to_field='station_id') - attribute_id = models.ForeignKey(Attribute, on_delete=models.CASCADE, to_field='attribute_id') def __str__(self): return f'{self.date} - {self.value}' diff --git a/django_project/ground_observations/tests.py b/django_project/ground_observations/tests.py index 7ce503c2..225a5378 100644 --- a/django_project/ground_observations/tests.py +++ b/django_project/ground_observations/tests.py @@ -1,3 +1,6 @@ -from django.test import TestCase +# coding=utf-8 +""" +Tomorrow Now GAP. -# Create your tests here. +.. note:: Tests +""" diff --git a/django_project/ground_observations/views.py b/django_project/ground_observations/views.py index 91ea44a2..4bbea2dd 100644 --- a/django_project/ground_observations/views.py +++ b/django_project/ground_observations/views.py @@ -1,3 +1,6 @@ -from django.shortcuts import render +# coding=utf-8 +""" +Tomorrow Now GAP. -# Create your views here. +.. note:: App Config +""" diff --git a/django_project/manage.py b/django_project/manage.py index e8fda26d..f2a662cf 100644 --- a/django_project/manage.py +++ b/django_project/manage.py @@ -19,4 +19,4 @@ def main(): if __name__ == '__main__': - main() \ No newline at end of file + main()