Skip to content

Commit

Permalink
feat(zone): add zone models, admin, and some changes to other models (#…
Browse files Browse the repository at this point in the history
…247)

* feat(zone): add zone models, admin, and some changes to other models

* fix(zone): fix weather ququery

* fix(zone): tests
  • Loading branch information
ollz272 authored May 1, 2023
1 parent a62b6ce commit 451a69d
Show file tree
Hide file tree
Showing 21 changed files with 174 additions and 22 deletions.
2 changes: 1 addition & 1 deletion apps/api/v1/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,6 @@ class PlantSerializer(serializers.ModelSerializer):

class Meta:
model = Plant
fields = ["id", "user", "name", "indoor", "sensors"]
fields = ["id", "user", "name", "sensors"]
read_only_fields = ("user",)
depth = 1
1 change: 0 additions & 1 deletion apps/plants/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
@admin.register(Plant)
class PlantAdmin(admin.ModelAdmin):
readonly_fields = ("slug",)
list_filter = ("indoor",)


@admin.register(DataPoint)
Expand Down
4 changes: 2 additions & 2 deletions apps/plants/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,15 +52,15 @@ def __init__(self, user=None, *args, **kwargs):
self.helper = FormHelper()
self.helper.layout = Layout(
"name",
"indoor",
"zone",
ButtonHolder(Submit("save", "Save", css_class="submit")),
)

class Meta:
model = Plant
fields = (
"name",
"indoor",
"zone",
)

def save(self, commit=True):
Expand Down
19 changes: 19 additions & 0 deletions apps/plants/migrations/0010_plant_zone.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Generated by Django 4.2 on 2023-05-01 08:04

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


class Migration(migrations.Migration):
dependencies = [
("zones", "0001_initial"),
("plants", "0009_alter_datapoint_options"),
]

operations = [
migrations.AddField(
model_name="plant",
name="zone",
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to="zones.zone"),
),
]
19 changes: 19 additions & 0 deletions apps/plants/migrations/0011_alter_plant_zone.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Generated by Django 4.2 on 2023-05-01 08:10

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


class Migration(migrations.Migration):
dependencies = [
("zones", "0002_make_plant_zones"),
("plants", "0010_plant_zone"),
]

operations = [
migrations.AlterField(
model_name="plant",
name="zone",
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="zones.zone"),
),
]
16 changes: 16 additions & 0 deletions apps/plants/migrations/0012_remove_plant_indoor.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# Generated by Django 4.2 on 2023-05-01 13:04

from django.db import migrations


class Migration(migrations.Migration):
dependencies = [
("plants", "0011_alter_plant_zone"),
]

operations = [
migrations.RemoveField(
model_name="plant",
name="indoor",
),
]
2 changes: 1 addition & 1 deletion apps/plants/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ class Plant(models.Model):
"""

user = models.ForeignKey(get_user_model(), on_delete=models.CASCADE)
zone = models.ForeignKey("zones.Zone", on_delete=models.CASCADE)
name = models.CharField(max_length=256)
indoor = models.BooleanField()
slug = models.SlugField()

class Meta:
Expand Down
3 changes: 2 additions & 1 deletion apps/plants/tests/factories.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,13 @@
from accounts.tests.factories import UserFactory
from factory.django import DjangoModelFactory
from plants import models
from zones.tests.factories import ZoneFactory


class PlantFactory(DjangoModelFactory):
user = factory.SubFactory(UserFactory)
name = factory.Sequence(lambda n: f"plant {n}")
indoor = True
zone = factory.SubFactory(ZoneFactory)

class Meta:
model = models.Plant
Expand Down
7 changes: 5 additions & 2 deletions apps/plants/tests/test_forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,22 @@
from plants.forms import PlantDataFilterForm, PlantForm, SensorForm
from plants.models import Plant, Sensor
from plants.tests.factories import DataPointFactory, PlantFactory, SensorFactory, SensorUnitFactory
from zones.tests.factories import ZoneFactory


class TestPlantForm(TestCase):
def test_create_plant(self):
user = UserFactory()
plant_form = PlantForm(user=user, data={"name": "test", "indoor": True})
zone = ZoneFactory()
plant_form = PlantForm(user=user, data={"name": "test", "zone": zone.id})
plant_form.save()

self.assertTrue(Plant.objects.filter(name="test").exists())

def test_create_plant_no_user(self):
UserFactory()
plant_form = PlantForm(data={"name": "test", "indoor": True})
zone = ZoneFactory()
plant_form = PlantForm(data={"name": "test", "zone": zone.id})

with self.assertRaises(IntegrityError):
plant_form.save()
Expand Down
9 changes: 3 additions & 6 deletions apps/plants/tests/test_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from django_webtest import WebTest
from plants.models import Plant, Sensor
from plants.tests.factories import PlantFactory, SensorFactory, SensorUnitFactory
from zones.tests.factories import ZoneFactory


class TestListPlantView(TestCase):
Expand Down Expand Up @@ -37,22 +38,21 @@ def test_create_plant_200(self):
self.assertEqual(resp.status_code, 200)

def test_create_plant_301_submit_form(self):
zone = ZoneFactory()
resp = self.app.get(reverse(self.url_name))
form = resp.forms[0]
form["name"] = "test"
form["indoor"] = True
form["zone"] = zone.id
resp = form.submit()
self.assertEqual(resp.status_code, 302)
self.assertEqual(Plant.objects.count(), 1)
plant = Plant.objects.get(name="test")
self.assertEqual(plant.user, self.user)
self.assertEqual(plant.indoor, True)
self.assertEqual(plant.slug, "test")

def test_create_plant_200_submit_form_error(self):
resp = self.app.get(reverse(self.url_name))
form = resp.forms[0]
form["indoor"] = True
resp = form.submit()
self.assertEqual(resp.status_code, 200)

Expand All @@ -77,19 +77,16 @@ def test_update_plant_301_submit_form(self):
resp = self.app.get(reverse(self.url_name, kwargs={"plant_pk": self.plant.id}))
form = resp.forms[0]
form["name"] = "test"
form["indoor"] = True
resp = form.submit()
self.assertEqual(resp.status_code, 302)
self.assertEqual(Plant.objects.count(), 1)
plant = Plant.objects.get(id=self.plant.id)
self.assertEqual(plant.user, self.user)
self.assertEqual(plant.indoor, True)
self.assertEqual(plant.slug, "test")

def test_update_plant_200_submit_form_error(self):
resp = self.app.get(reverse(self.url_name, kwargs={"plant_pk": self.plant.id}))
form = resp.forms[0]
form["indoor"] = True
form["name"] = ""
resp = form.submit()
self.assertEqual(resp.status_code, 200)
Expand Down
3 changes: 2 additions & 1 deletion apps/weather/management/commands/populate_weather.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from django.utils.timezone import datetime, now
from pytz import utc
from weather.models import Weather
from zones.models import Zone

# Get an instance of a logger
logger = logging.getLogger(__name__)
Expand All @@ -27,7 +28,7 @@ def get_weather_data(self, lat, lon):

def handle(self, *args, **options):
# TODO get lat/lon from database.
for lat, lon in [(52.52, 13.41), (52.40, -2.01)]:
for lat, lon in Zone.objects.order_by("location").distinct("location").values_list("location", flat=True):
self.stdout.write(f"Fetching data for {lat}, {lon}")
resp = self.get_weather_data(lat, lon)
time_now = now()
Expand Down
Empty file added apps/zones/__init__.py
Empty file.
8 changes: 8 additions & 0 deletions apps/zones/admin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
from django.contrib import admin

from zones.models import Zone


@admin.register(Zone)
class ZoneAdmin(admin.ModelAdmin):
pass
6 changes: 6 additions & 0 deletions apps/zones/apps.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
from django.apps import AppConfig


class ZonesConfig(AppConfig):
default_auto_field = "django.db.models.BigAutoField"
name = "zones"
34 changes: 34 additions & 0 deletions apps/zones/migrations/0001_initial.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# Generated by Django 4.2 on 2023-05-01 08:04

from django.conf import settings
import django.contrib.gis.db.models.fields
from django.db import migrations, models
import django.db.models.deletion


class Migration(migrations.Migration):
initial = True

dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]

operations = [
migrations.CreateModel(
name="Zone",
fields=[
("id", models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")),
("name", models.CharField(max_length=256)),
("location", django.contrib.gis.db.models.fields.PointField(srid=4326, blank=True, null=True)),
("user", models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
],
),
migrations.AddIndex(
model_name="zone",
index=models.Index(fields=["location"], name="zone_location_idx"),
),
migrations.AddConstraint(
model_name="zone",
constraint=models.UniqueConstraint(fields=("user", "name"), name="unique_zone_name_for_user"),
),
]
27 changes: 27 additions & 0 deletions apps/zones/migrations/0002_make_plant_zones.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
from django.db import migrations


def set_plant_zone(apps, schema_editor):
Zone = apps.get_model("zones", "Zone")
Plant = apps.get_model("plants", "Plant")
# Set the partners' region as the needs region as a default.
for plant in Plant.objects.all():
if plant.indoor:
zone = Zone.objects.get_or_create(user=plant.user, name="indoor")

else:
zone = Zone.objects.get_or_create(user=plant.user, name="outdoor")

plant.zone = zone
plant.save()


class Migration(migrations.Migration):
dependencies = [
("zones", "0001_initial"),
("plants", "0010_plant_zone"),
]

operations = [
migrations.RunPython(set_plant_zone),
]
Empty file.
16 changes: 16 additions & 0 deletions apps/zones/models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
from django.contrib.auth import get_user_model
from django.db import models
from django.contrib.gis.db import models as gis_models


class Zone(models.Model):
user = models.ForeignKey(get_user_model(), on_delete=models.CASCADE)
name = models.CharField(max_length=256)
location = gis_models.PointField(blank=True, null=True)

def __str__(self):
return self.name

class Meta:
constraints = [models.UniqueConstraint(fields=["user", "name"], name="unique_zone_name_for_user")]
indexes = [models.Index(fields=["location"], name="zone_location_idx")]
Empty file added apps/zones/tests/__init__.py
Empty file.
12 changes: 12 additions & 0 deletions apps/zones/tests/factories.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import factory
from accounts.tests.factories import UserFactory
from factory.django import DjangoModelFactory
from zones import models


class ZoneFactory(DjangoModelFactory):
user = factory.SubFactory(UserFactory)
name = factory.Sequence(lambda n: f"zone {n}")

class Meta:
model = models.Zone
8 changes: 1 addition & 7 deletions project/settings/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,13 +49,7 @@
"colorfield",
]

PROJECT_APPS = [
"plants",
"api",
"accounts",
"weather",
"alerts",
]
PROJECT_APPS = ["plants", "api", "accounts", "weather", "alerts", "zones"]

INSTALLED_APPS = DEFAULT_APPS + THIRD_PARTY_APPS + PROJECT_APPS

Expand Down

0 comments on commit 451a69d

Please sign in to comment.