Skip to content

Commit

Permalink
Merge pull request #68 from luftdaten-at/database_migration
Browse files Browse the repository at this point in the history
Database migration
  • Loading branch information
n11ik authored Dec 10, 2024
2 parents 57eed0d + b4b7ced commit 696600f
Show file tree
Hide file tree
Showing 12 changed files with 498 additions and 27 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -154,4 +154,5 @@ dmypy.json
cython_debug/

# docker compose production environment
docker-compose.prod.yml
docker-compose.prod.yml
db_backup
27 changes: 27 additions & 0 deletions app/api/migrations/0002_alter_fk.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Generated by Django 5.1.2 on 2024-12-09 08:58

from django.db import migrations, models
from devices.models import Sensor


class Migration(migrations.Migration):

dependencies = [
('api', '0001_initial'),
('devices', '0004_alter_device_model_remove_device_sensor_bme280_and_more')
]
# TODO: migrate data aswell
operations = [
migrations.RemoveField(
model_name='measurement',
name='sensor',
),
migrations.AddField(
model_name='measurement',
name='sensor',
field=models.ForeignKey(
to='devices.Sensor',
on_delete=models.CASCADE,
),
),
]
46 changes: 46 additions & 0 deletions app/api/migrations/0003_devicelogs_measurementnew_values.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# Generated by Django 5.1.2 on 2024-12-09 11:06

import django.db.models.deletion
from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('api', '0002_alter_fk'),
('campaign', '0002_alter_campaign_id_alter_campaign_name_organization_and_more'),
('devices', '0004_alter_device_model_remove_device_sensor_bme280_and_more'),
]

operations = [
migrations.CreateModel(
name='DeviceLogs',
fields=[
('id', models.IntegerField(primary_key=True, serialize=False)),
('timestamp', models.DateTimeField()),
('level', models.IntegerField()),
('message', models.TextField()),
('device', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='devices.device')),
],
),
migrations.CreateModel(
name='MeasurementNew',
fields=[
('id', models.IntegerField(primary_key=True, serialize=False)),
('time_received', models.DateTimeField()),
('time_measured', models.DateTimeField()),
('sensor_model', models.IntegerField()),
('device', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='devices.device')),
('room', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='campaign.room')),
],
),
migrations.CreateModel(
name='Values',
fields=[
('id', models.IntegerField(primary_key=True, serialize=False)),
('dimension', models.IntegerField()),
('value', models.FloatField()),
('measurement', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='api.measurementnew')),
],
),
]
43 changes: 43 additions & 0 deletions app/api/models.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from django.db import models
from workshops.models import Participant, Workshop
from devices.models import Device, Sensor
from campaign.models import Room
#from campaign.models import Campaign


Expand Down Expand Up @@ -75,3 +76,45 @@ class AirQualityRecord(models.Model):
lon = models.FloatField(null=True, blank=True)
location_precision = models.FloatField(null=True, blank=True)
mode = models.ForeignKey(MobilityMode, on_delete=models.CASCADE, null=True, blank=True)


class MeasurementNew(models.Model):
"""
Measurement taken by a device in a room.
"""
id = models.IntegerField(primary_key=True)
time_received = models.DateTimeField()
time_measured = models.DateTimeField()
sensor_model = models.IntegerField()
device = models.ForeignKey(Device, on_delete=models.CASCADE)
room = models.ForeignKey(Room, on_delete=models.CASCADE)

def __str__(self):
return f'Measurement {self.id} from Device {self.device.id}'


class Values(models.Model):
"""
Values associated with a measurement.
"""
id = models.IntegerField(primary_key=True)
dimension = models.IntegerField()
value = models.FloatField()
measurement = models.ForeignKey(MeasurementNew, on_delete=models.CASCADE)

def __str__(self):
return f'Value {self.id} for Measurement {self.measurement.id}'


class DeviceLogs(models.Model):
"""
Logs for each device.
"""
id = models.IntegerField(primary_key=True)
device = models.ForeignKey(Device, on_delete=models.CASCADE)
timestamp = models.DateTimeField()
level = models.IntegerField()
message = models.TextField()

def __str__(self):
return f'Log {self.id} for Device {self.device.id}'
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
# Generated by Django 5.1.2 on 2024-12-09 11:06

import django.db.models.deletion
from django.conf import settings
from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('campaign', '0001_initial'),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]

operations = [
migrations.AlterField(
model_name='campaign',
name='id',
field=models.IntegerField(primary_key=True, serialize=False),
),
migrations.AlterField(
model_name='campaign',
name='name',
field=models.CharField(max_length=255),
),
migrations.CreateModel(
name='Organization',
fields=[
('id', models.IntegerField(primary_key=True, serialize=False)),
('name', models.CharField(max_length=255)),
('description', models.TextField(blank=True, null=True)),
('owner', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='owned_organizations', to=settings.AUTH_USER_MODEL)),
],
),
migrations.AddField(
model_name='campaign',
name='organization',
field=models.ForeignKey(default=None, on_delete=django.db.models.deletion.CASCADE, related_name='campaigns', to='campaign.organization'),
preserve_default=False,
),
migrations.CreateModel(
name='Room',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=255)),
('campaign', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='rooms', to='campaign.campaign')),
],
options={
'unique_together': {('campaign', 'name')},
},
),
migrations.CreateModel(
name='UserCampaign',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('campaign', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='campaign.campaign')),
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
],
options={
'unique_together': {('user', 'campaign')},
},
),
migrations.CreateModel(
name='UserOrganization',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('organization', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='campaign.organization')),
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
],
options={
'unique_together': {('user', 'organization')},
},
),
]
87 changes: 70 additions & 17 deletions app/campaign/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,11 @@
import random

class Campaign(models.Model):
name = models.CharField(max_length=100)
"""
Represents a campaign.
"""
id = models.IntegerField(primary_key=True)
name = models.CharField(max_length=255)
description = models.TextField(null=True, blank=True)
start_date = models.DateTimeField()
end_date = models.DateTimeField()
Expand All @@ -13,25 +17,74 @@ class Campaign(models.Model):
owner = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE,
related_name='owned_campaigns', # Allows user.owned_campaigns.all() to get all owned workshops
related_name='owned_campaigns',
null=True,
blank=True
)
organization = models.ForeignKey(
'Organization',
on_delete=models.CASCADE,
related_name='campaigns'
)

def __str__(self):
return self.name

def save(self, *args, **kwargs):
if not self.id_token:
# Generate a unique ID for new workshops
self.id_token = self.generate_id_token()
super(Campaign, self).save(*args, **kwargs)

@staticmethod
def generate_id_token():
length = 8
# Ensure the generated ID is unique
while Campaign.objects.filter(id_token=id_token).exists():
# Generate a random string of letters and digits
id_token = ''.join(random.choices(string.ascii_letters + string.digits, k=length))
return id_token


class Room(models.Model):
"""
Represents a room where a campaign takes place.
"""
campaign = models.ForeignKey('Campaign', on_delete=models.CASCADE, related_name='rooms')
name = models.CharField(max_length=255)

class Meta:
unique_together = ('campaign', 'name')

def __str__(self):
return f'{self.name} in {self.campaign}'


class Organization(models.Model):
"""
Represents an organization that owns campaigns and users can be part of.
"""
id = models.IntegerField(primary_key=True)
name = models.CharField(max_length=255)
description = models.TextField(null=True, blank=True)
owner = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE,
related_name='owned_organizations'
)

def __str__(self):
return self.name


class UserOrganization(models.Model):
"""
Represents the many-to-many relationship between users and organizations.
"""
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
organization = models.ForeignKey(Organization, on_delete=models.CASCADE)

class Meta:
unique_together = ('user', 'organization')

def __str__(self):
return f'{self.user} in {self.organization}'


class UserCampaign(models.Model):
"""
Represents the many-to-many relationship between users and campaigns.
"""
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
campaign = models.ForeignKey('Campaign', on_delete=models.CASCADE)

class Meta:
unique_together = ('user', 'campaign')

def __str__(self):
return f'{self.user} in {self.campaign}'
Loading

0 comments on commit 696600f

Please sign in to comment.