diff --git a/plants/forms.py b/plants/forms.py
index 2a3f165..3fe77a5 100644
--- a/plants/forms.py
+++ b/plants/forms.py
@@ -9,16 +9,16 @@ MONTH_CHOICES = [
class PlantForm(forms.ModelForm):
- pruning_months = forms.MultipleChoiceField(
+ bloom_months = forms.MultipleChoiceField(
choices=MONTH_CHOICES,
widget=forms.CheckboxSelectMultiple,
required=False,
- label='Pruning months',
+ label='Bloom months',
)
class Meta:
model = Plant
- fields = ['name', 'location', 'is_indoor', 'pruning_months', 'photo', 'notes']
+ fields = ['name', 'location', 'is_indoor', 'bloom_months', 'photo', 'notes']
widgets = {
'notes': forms.Textarea(attrs={'rows': 3}),
'name': forms.TextInput(attrs={'class': 'form-control'}),
@@ -27,14 +27,13 @@ class PlantForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
- # JSONField stores ints; CheckboxSelectMultiple expects strings matching choice values
- if self.instance.pk and self.instance.pruning_months:
- self.initial['pruning_months'] = [str(m) for m in self.instance.pruning_months]
- elif not self.instance.pk and self.initial.get('pruning_months'):
- self.initial['pruning_months'] = [str(m) for m in self.initial['pruning_months']]
+ if self.instance.pk and self.instance.bloom_months:
+ self.initial['bloom_months'] = [str(m) for m in self.instance.bloom_months]
+ elif not self.instance.pk and self.initial.get('bloom_months'):
+ self.initial['bloom_months'] = [str(m) for m in self.initial['bloom_months']]
- def clean_pruning_months(self):
- return [int(m) for m in self.cleaned_data.get('pruning_months', [])]
+ def clean_bloom_months(self):
+ return [int(m) for m in self.cleaned_data.get('bloom_months', [])]
class PruningLogForm(forms.ModelForm):
diff --git a/plants/migrations/0003_add_bloom_months.py b/plants/migrations/0003_add_bloom_months.py
new file mode 100644
index 0000000..4784f98
--- /dev/null
+++ b/plants/migrations/0003_add_bloom_months.py
@@ -0,0 +1,23 @@
+# Generated by Django 5.2.1 on 2026-05-28 15:00
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('plants', '0002_alter_pruninglog_plant_alter_species_max_height_cm'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='plant',
+ name='bloom_months',
+ field=models.JSONField(default=list),
+ ),
+ migrations.AddField(
+ model_name='species',
+ name='bloom_months',
+ field=models.JSONField(default=list),
+ ),
+ ]
diff --git a/plants/models.py b/plants/models.py
index eda0716..4f2b663 100644
--- a/plants/models.py
+++ b/plants/models.py
@@ -12,6 +12,7 @@ class Species(models.Model):
growth_rate = models.CharField(max_length=100, blank=True)
growth_season = models.CharField(max_length=100, blank=True)
pruning_months = models.JSONField(default=list)
+ bloom_months = models.JSONField(default=list)
api_image_url = models.URLField(blank=True)
perenual_id = models.IntegerField(unique=True, null=True, blank=True)
@@ -32,6 +33,7 @@ class Plant(models.Model):
location = models.CharField(max_length=200)
is_indoor = models.BooleanField(default=False)
pruning_months = models.JSONField(default=list)
+ bloom_months = models.JSONField(default=list)
photo = models.ImageField(upload_to='plants/', blank=True)
notes = models.TextField(blank=True)
date_added = models.DateField(auto_now_add=True)
diff --git a/plants/templates/plants/base.html b/plants/templates/plants/base.html
index 4aac15e..4d6608c 100644
--- a/plants/templates/plants/base.html
+++ b/plants/templates/plants/base.html
@@ -30,7 +30,6 @@
🌿 PlantDB
diff --git a/plants/templates/plants/dashboard.html b/plants/templates/plants/dashboard.html
index 41dd125..4a431f8 100644
--- a/plants/templates/plants/dashboard.html
+++ b/plants/templates/plants/dashboard.html
@@ -1,4 +1,5 @@
{% extends "plants/base.html" %}
+{% load plant_extras %}
{% block title %}Dashboard — PlantDB{% endblock %}
{% block content %}
{{ today|date:"F Y" }}
@@ -15,39 +16,26 @@
-{% if overdue or due_this_month %}
+{% if blooming_now %}
-
+
diff --git a/plants/templates/plants/plant_detail.html b/plants/templates/plants/plant_detail.html
index 3f8e756..e09c0b4 100644
--- a/plants/templates/plants/plant_detail.html
+++ b/plants/templates/plants/plant_detail.html
@@ -52,7 +52,13 @@
{% endif %}
{% endif %}
-{% include "plants/partials/pruning_strip.html" %}
+{% load plant_extras %}
+{% if plant.bloom_months %}
+
+
🌸 Bloom
+
{% month_strip plant.bloom_months %}
+
+{% endif %}
{% if plant.notes %}
diff --git a/plants/templates/plants/plant_form.html b/plants/templates/plants/plant_form.html
index 9a6c9e0..3315b1d 100644
--- a/plants/templates/plants/plant_form.html
+++ b/plants/templates/plants/plant_form.html
@@ -41,9 +41,9 @@
-
+
- {% for widget in form.pruning_months %}
+ {% for widget in form.bloom_months %}
{{ widget.tag }}
diff --git a/plants/tests/test_views.py b/plants/tests/test_views.py
index 1b72c4c..6b5b8ca 100644
--- a/plants/tests/test_views.py
+++ b/plants/tests/test_views.py
@@ -16,21 +16,18 @@ class TestDashboard:
resp = client.get(reverse('dashboard'))
assert resp.context['total_plants'] == 2
- def test_overdue_plant_appears_in_context(self, client):
- plant = Plant.objects.create(name='Rose', location='Garden', pruning_months=[3])
- # No log — overdue relative to current date (month 3 is more than 6 months ago only if checked after September)
- # Use a month that's definitely in the recent past: use today's month - 1
- resp = client.get(reverse('dashboard'))
- # Just check the view works; pruning logic is tested separately
- assert 'overdue' in resp.context
-
- def test_due_this_month_plant_appears_in_context(self, client):
+ def test_blooming_now_plant_appears_in_context(self, client):
today = date.today()
- plant = Plant.objects.create(
- name='Apple', location='Garden', pruning_months=[today.month]
- )
+ plant = Plant.objects.create(name='Rose', location='Garden', bloom_months=[today.month])
resp = client.get(reverse('dashboard'))
- assert plant in resp.context['due_this_month']
+ assert plant in resp.context['blooming_now']
+
+ def test_non_blooming_plant_not_in_blooming_now(self, client):
+ today = date.today()
+ other_month = today.month % 12 + 1
+ plant = Plant.objects.create(name='Apple', location='Garden', bloom_months=[other_month])
+ resp = client.get(reverse('dashboard'))
+ assert plant not in resp.context['blooming_now']
@pytest.mark.django_db
diff --git a/plants/views/dashboard.py b/plants/views/dashboard.py
index 23019e0..a1443c6 100644
--- a/plants/views/dashboard.py
+++ b/plants/views/dashboard.py
@@ -1,26 +1,16 @@
from datetime import date
from django.shortcuts import render
from plants.models import Plant
-from plants.utils.pruning import pruning_status
def dashboard(request):
today = date.today()
- all_plants = list(
- Plant.objects.select_related('species').prefetch_related('pruning_logs')
- )
- overdue, due_this_month = [], []
- for plant in all_plants:
- status = pruning_status(plant, today)
- if status == 'overdue':
- overdue.append(plant)
- elif status == 'due_this_month':
- due_this_month.append(plant)
+ all_plants = list(Plant.objects.select_related('species').all())
+ blooming_now = [p for p in all_plants if today.month in (p.bloom_months or [])]
return render(request, 'plants/dashboard.html', {
'total_plants': len(all_plants),
- 'overdue': overdue,
- 'due_this_month': due_this_month,
- 'needs_pruning_count': len(overdue) + len(due_this_month),
+ 'blooming_now': blooming_now,
+ 'blooming_now_count': len(blooming_now),
'today': today,
})
diff --git a/plants/views/plants.py b/plants/views/plants.py
index 6a04355..3efcb8f 100644
--- a/plants/views/plants.py
+++ b/plants/views/plants.py
@@ -78,7 +78,7 @@ def plant_add(request):
plant.save()
return redirect('plant_detail', pk=plant.pk)
else:
- initial = {'pruning_months': species.pruning_months} if species else {}
+ initial = {'bloom_months': species.bloom_months} if species else {}
form = PlantForm(initial=initial)
return render(request, 'plants/plant_form.html', {