From 3bc27a345fec02d549392464603f704d2a6ed06c Mon Sep 17 00:00:00 2001 From: Stephan Kerkman Date: Thu, 28 May 2026 10:05:18 +0200 Subject: [PATCH] feat: add plant form with species pre-fill Co-Authored-By: Claude Sonnet 4.6 --- plants/templates/plants/plant_form.html | 70 +++++++++++++++++++++++++ plants/tests/test_views.py | 33 ++++++++++++ plants/views/plants.py | 27 +++++++++- 3 files changed, 129 insertions(+), 1 deletion(-) create mode 100644 plants/templates/plants/plant_form.html diff --git a/plants/templates/plants/plant_form.html b/plants/templates/plants/plant_form.html new file mode 100644 index 0000000..23cb235 --- /dev/null +++ b/plants/templates/plants/plant_form.html @@ -0,0 +1,70 @@ +{% extends "plants/base.html" %} +{% block title %}{{ title }} — PlantDB{% endblock %} +{% block content %} +
+ +
{{ title }}
+
+ +{% if species %} +
+ {% if species.api_image_url %} + + {% endif %} +
+ {{ species.common_name }} + {% if species.scientific_name %}{{ species.scientific_name }}{% endif %} +
Care info pre-filled from species database.
+
+
+{% endif %} + +
+ {% csrf_token %} + + +
+ + {{ form.name }} + {% if form.name.errors %}
{{ form.name.errors }}
{% endif %} +
+ +
+ + {{ form.location }} + {% if form.location.errors %}
{{ form.location.errors }}
{% endif %} +
+ +
+ {{ form.is_indoor }} + +
+ +
+ +
+ {% for widget in form.pruning_months %} +
+ {{ widget.tag }} + +
+ {% endfor %} +
+
+ +
+ + {{ form.photo }} +
Take a photo with your camera or upload one.
+
+ +
+ + {{ form.notes }} +
+ +
+ +
+
+{% endblock %} diff --git a/plants/tests/test_views.py b/plants/tests/test_views.py index 0563bab..0c378bf 100644 --- a/plants/tests/test_views.py +++ b/plants/tests/test_views.py @@ -149,3 +149,36 @@ class TestSpeciesSearch: 'api_image_url': '', }) assert Species.objects.filter(perenual_id=99).count() == 1 + + +@pytest.mark.django_db +class TestPlantAdd: + def test_add_with_species_shows_prefilled_form(self, client): + from plants.models import Species + s = Species.objects.create(common_name='Rose', pruning_months=[2, 8]) + resp = client.get(reverse('plant_add') + f'?species_id={s.pk}') + assert resp.status_code == 200 + assert resp.context['species'] == s + + def test_post_creates_plant_and_redirects(self, client): + resp = client.post(reverse('plant_add'), { + 'name': 'New Fern', + 'location': 'Office', + 'is_indoor': 'on', + 'notes': '', + 'pruning_months': [], + }) + assert Plant.objects.filter(name='New Fern').exists() + plant = Plant.objects.get(name='New Fern') + assert resp.status_code == 302 + assert resp['Location'] == f'/plants/{plant.pk}/' + + def test_post_with_species_links_species(self, client): + from plants.models import Species + s = Species.objects.create(common_name='Rose', pruning_months=[2]) + client.post( + reverse('plant_add') + f'?species_id={s.pk}', + {'name': 'Garden Rose', 'location': 'Garden', 'notes': '', 'pruning_months': ['2']}, + ) + plant = Plant.objects.get(name='Garden Rose') + assert plant.species == s diff --git a/plants/views/plants.py b/plants/views/plants.py index 5e6dae2..cda06df 100644 --- a/plants/views/plants.py +++ b/plants/views/plants.py @@ -59,7 +59,32 @@ def log_pruning(request, pk): def plant_add(request): - return render(request, 'plants/species_search.html') + species_id = request.GET.get('species_id') or request.POST.get('species_id') + species = None + + if species_id and species_id != 'skip': + species = get_object_or_404(Species, pk=species_id) + + if species_id is None and request.method == 'GET': + return render(request, 'plants/species_search.html') + + if request.method == 'POST': + form = PlantForm(request.POST, request.FILES) + if form.is_valid(): + plant = form.save(commit=False) + plant.species = species + plant.save() + return redirect('plant_detail', pk=plant.pk) + else: + initial = {'pruning_months': species.pruning_months} if species else {} + form = PlantForm(initial=initial) + + return render(request, 'plants/plant_form.html', { + 'form': form, + 'species': species, + 'species_id': species_id, + 'title': 'Add Plant', + }) def plant_edit(request, pk):