bloombase/plants/views/plants.py
Stephan Kerkman dff1c88748 feat: show plant card button on detail page when card photos exist
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-28 21:59:04 +02:00

170 lines
5.8 KiB
Python

from datetime import date
from django.shortcuts import render, get_object_or_404, redirect
from django.views.decorators.csrf import ensure_csrf_cookie
from django.views.decorators.http import require_POST, require_GET
from plants.models import Plant, Species, PruningLog, PlantPhoto, PlantCardPhoto
from plants.forms import PlantForm, PruningLogForm
from plants.utils.pruning import pruning_status
def plant_list(request):
qs = Plant.objects.select_related('species', 'location').all()
q = request.GET.get('q', '')
indoor_filter = request.GET.get('filter', '')
if q:
qs = qs.filter(name__icontains=q) | qs.filter(location__name__icontains=q)
if indoor_filter == 'indoor':
qs = qs.filter(is_indoor=True)
elif indoor_filter == 'outdoor':
qs = qs.filter(is_indoor=False)
template = (
'plants/partials/plant_list_results.html'
if request.htmx
else 'plants/plant_list.html'
)
return render(request, template, {'plants': qs, 'q': q, 'filter': indoor_filter})
def plant_detail(request, pk):
plant = get_object_or_404(
Plant.objects.select_related('species', 'location').prefetch_related('pruning_logs', 'photos', 'card_photos'),
pk=pk,
)
today = date.today()
return render(request, 'plants/plant_detail.html', {
'plant': plant,
'pruning_status': pruning_status(plant, today),
'log_form': PruningLogForm(initial={'pruned_on': today}),
'today': today,
})
@require_POST
def log_pruning(request, pk):
plant = get_object_or_404(
Plant.objects.prefetch_related('pruning_logs'), pk=pk
)
form = PruningLogForm(request.POST)
if form.is_valid():
log = form.save(commit=False)
log.plant = plant
log.save()
today = date.today()
return render(request, 'plants/partials/pruning_strip.html', {
'plant': plant,
'pruning_status': pruning_status(plant, today),
'log_form': PruningLogForm(initial={'pruned_on': today}),
})
@ensure_csrf_cookie
def plant_add(request):
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 = {'bloom_months': species.bloom_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):
plant = get_object_or_404(Plant, pk=pk)
if request.method == 'POST':
form = PlantForm(request.POST, request.FILES, instance=plant)
if form.is_valid():
form.save()
return redirect('plant_detail', pk=plant.pk)
else:
form = PlantForm(instance=plant)
return render(request, 'plants/plant_form.html', {
'form': form,
'plant': plant,
'species': plant.species,
'title': 'Edit Plant',
})
def plant_delete(request, pk):
plant = get_object_or_404(Plant, pk=pk)
if request.method == 'POST':
plant.delete()
return redirect('plant_list')
return render(request, 'plants/plant_confirm_delete.html', {'plant': plant})
@require_GET
def plant_card(request, pk):
plant = get_object_or_404(
Plant.objects.prefetch_related('card_photos'), pk=pk
)
return render(request, 'plants/plant_card.html', {'plant': plant})
@require_POST
def upload_card_photo(request, pk):
plant = get_object_or_404(Plant, pk=pk)
if request.FILES.get('image') and plant.card_photos.count() < 3:
PlantCardPhoto.objects.create(plant=plant, image=request.FILES['image'])
plant = Plant.objects.prefetch_related('card_photos').get(pk=pk)
return render(request, 'plants/partials/card_gallery.html', {'plant': plant})
@require_POST
def delete_card_photo(request, card_photo_pk):
card_photo = get_object_or_404(PlantCardPhoto, pk=card_photo_pk)
plant_pk = card_photo.plant_id
card_photo.image.delete(save=False)
card_photo.delete()
plant = Plant.objects.prefetch_related('card_photos').get(pk=plant_pk)
return render(request, 'plants/partials/card_gallery.html', {'plant': plant})
@require_POST
def upload_photo(request, pk):
plant = get_object_or_404(Plant.objects.prefetch_related('photos'), pk=pk)
if request.FILES.get('image'):
PlantPhoto.objects.create(plant=plant, image=request.FILES['image'])
return render(request, 'plants/partials/photo_gallery.html', {'plant': plant})
@require_POST
def set_thumbnail(request, photo_pk):
photo = get_object_or_404(PlantPhoto, pk=photo_pk)
PlantPhoto.objects.filter(plant=photo.plant).update(is_thumbnail=False)
photo.is_thumbnail = True
photo.save(update_fields=['is_thumbnail'])
plant = Plant.objects.prefetch_related('photos').get(pk=photo.plant_id)
return render(request, 'plants/partials/photo_gallery.html', {'plant': plant})
@require_POST
def delete_photo(request, photo_pk):
photo = get_object_or_404(PlantPhoto, pk=photo_pk)
plant = Plant.objects.prefetch_related('photos').get(pk=photo.plant_id)
photo.image.delete(save=False)
photo.delete()
plant.refresh_from_db()
plant = Plant.objects.prefetch_related('photos').get(pk=plant.pk)
return render(request, 'plants/partials/photo_gallery.html', {'plant': plant})