38180-vm/core/views.py
2026-02-04 23:13:52 +00:00

370 lines
13 KiB
Python

import datetime
import json
from django.shortcuts import render, redirect, get_object_or_404
from django.db.models import Count, Q
from django.views.decorators.http import require_POST
from django.http import JsonResponse
from django.contrib.auth.models import User
from .models import Category, WardrobeItem, Accessory, Outfit, OutfitFolder, CalendarAssignment, UserProfile
from .forms import WardrobeItemForm, AccessoryForm, OutfitForm, UserProfileForm
def get_current_user_profile(request):
if request.user.is_authenticated:
profile, _ = UserProfile.objects.get_or_create(user=request.user)
return profile
else:
# Fallback to first user if not authenticated (common for simple dev setups)
user = User.objects.first()
if user:
profile, _ = UserProfile.objects.get_or_create(user=user)
return profile
return None
def home(request):
"""Dashboard view with current week calendar and total items count."""
season_filter = request.GET.get('season', 'summer')
total_wardrobe = WardrobeItem.objects.count()
total_accessories = Accessory.objects.count()
total_items = total_wardrobe + total_accessories
today = datetime.date.today()
start_of_week = today - datetime.timedelta(days=today.weekday())
week_dates = [start_of_week + datetime.timedelta(days=i) for i in range(7)]
day_names = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"]
calendar_data = []
assignments = {a.date: a.outfit for a in CalendarAssignment.objects.filter(date__in=week_dates)}
for i, date in enumerate(week_dates):
calendar_data.append({
'day': day_names[i],
'date': date,
'outfit': assignments.get(date)
})
# All outfits for the "quick add" modal on home screen
all_outfits = Outfit.objects.all().order_by('-date_created')
profile = get_current_user_profile(request)
avatar_form = UserProfileForm(instance=profile)
context = {
'total_items': total_items,
'calendar_data': calendar_data,
'today': today,
'season_filter': season_filter,
'all_outfits': all_outfits,
'week_dates_json': json.dumps([d.strftime('%Y-%m-%d') for d in week_dates]),
'day_names': day_names,
'profile': profile,
'avatar_form': avatar_form,
}
return render(request, 'core/index.html', context)
@require_POST
def update_avatar(request):
profile = get_current_user_profile(request)
if profile:
form = UserProfileForm(request.POST, request.FILES, instance=profile)
if form.is_valid():
form.save()
return redirect('home')
@require_POST
def remove_assignment(request, date):
CalendarAssignment.objects.filter(date=date).delete()
return redirect('home')
@require_POST
def assign_outfit(request):
outfit_id = request.POST.get('outfit_id')
date_str = request.POST.get('date')
if outfit_id and date_str:
outfit = get_object_or_404(Outfit, id=outfit_id)
try:
date_obj = datetime.datetime.strptime(date_str, '%Y-%m-%d').date()
CalendarAssignment.objects.update_or_create(
date=date_obj,
defaults={'outfit': outfit}
)
except ValueError:
pass
return redirect(request.META.get('HTTP_REFERER', 'home'))
def wardrobe_list(request):
query = request.GET.get('q')
main_category_id = request.GET.get('main_category')
subcategory_id = request.GET.get('subcategory')
sort = request.GET.get('sort', 'recent')
main_categories = Category.objects.filter(item_type='wardrobe', parent=None).annotate(
num_items=Count('wardrobe_items', distinct=True),
num_child_items=Count('children__wardrobe_items', distinct=True)
).filter(Q(is_preset=True) | Q(num_items__gt=0) | Q(num_child_items__gt=0))
subcategories = None
current_main = None
current_sub = None
if sort == 'alpha':
items = WardrobeItem.objects.all().order_by('name')
else:
items = WardrobeItem.objects.all().order_by('-date_added')
if main_category_id:
current_main = get_object_or_404(Category, id=main_category_id, parent=None)
subcategories = Category.objects.filter(parent=current_main).annotate(
num_items=Count('wardrobe_items', distinct=True)
).filter(Q(is_preset=True) | Q(num_items__gt=0))
items = items.filter(Q(category=current_main) | Q(category__parent=current_main))
if subcategory_id:
current_sub = get_object_or_404(Category, id=subcategory_id, parent=current_main)
items = items.filter(category=current_sub)
if query:
items = items.filter(Q(name__icontains=query) | Q(category__name__icontains=query))
context = {
'main_categories': main_categories,
'subcategories': subcategories,
'current_main': current_main,
'current_sub': current_sub,
'items': items,
'title': 'Wardrobe',
'sort': sort
}
return render(request, 'core/wardrobe_list.html', context)
def add_wardrobe_item(request):
if request.method == 'POST':
form = WardrobeItemForm(request.POST, request.FILES)
if form.is_valid():
form.save()
return redirect('wardrobe_list')
else:
form = WardrobeItemForm()
return render(request, 'core/item_form.html', {'form': form, 'title': 'Add Wardrobe Item', 'type': 'wardrobe'})
def accessory_list(request):
query = request.GET.get('q')
main_category_id = request.GET.get('main_category')
subcategory_id = request.GET.get('subcategory')
sort = request.GET.get('sort', 'recent')
main_categories = Category.objects.filter(item_type='accessory', parent=None).annotate(
num_items=Count('accessories', distinct=True),
num_child_items=Count('children__accessories', distinct=True)
).filter(Q(is_preset=True) | Q(num_items__gt=0) | Q(num_child_items__gt=0))
subcategories = None
current_main = None
current_sub = None
if sort == 'alpha':
items = Accessory.objects.all().order_by('name')
else:
items = Accessory.objects.all().order_by('-date_added')
if main_category_id:
current_main = get_object_or_404(Category, id=main_category_id, parent=None)
subcategories = Category.objects.filter(parent=current_main).annotate(
num_items=Count('accessories', distinct=True)
).filter(Q(is_preset=True) | Q(num_items__gt=0))
items = items.filter(Q(category=current_main) | Q(category__parent=current_main))
if subcategory_id:
current_sub = get_object_or_404(Category, id=subcategory_id, parent=current_main)
items = items.filter(category=current_sub)
if query:
items = items.filter(Q(name__icontains=query) | Q(category__name__icontains=query))
context = {
'main_categories': main_categories,
'subcategories': subcategories,
'current_main': current_main,
'current_sub': current_sub,
'items': items,
'title': 'Accessories',
'sort': sort
}
return render(request, 'core/accessory_list.html', context)
def add_accessory_item(request):
if request.method == 'POST':
form = AccessoryForm(request.POST, request.FILES)
if form.is_valid():
form.save()
return redirect('accessory_list')
else:
form = AccessoryForm()
return render(request, 'core/item_form.html', {'form': form, 'title': 'Add Accessory', 'type': 'accessory'})
def outfit_list(request):
query = request.GET.get('q')
folder_id = request.GET.get('folder')
sort = request.GET.get('sort', 'recent')
def get_valid_folders(parent=None):
return OutfitFolder.objects.filter(parent=parent).annotate(
num_outfits=Count('outfits', distinct=True),
num_child_outfits=Count('children__outfits', distinct=True)
).filter(Q(is_preset=True) | Q(num_outfits__gt=0) | Q(num_child_outfits__gt=0))
folders = get_valid_folders(None)
if sort == 'alpha':
outfits = Outfit.objects.all().order_by('name')
else:
outfits = Outfit.objects.all().order_by('-date_created')
if folder_id:
current_folder = get_object_or_404(OutfitFolder, id=folder_id)
folders = get_valid_folders(current_folder)
if not folders.exists():
folders = get_valid_folders(current_folder.parent)
outfits = outfits.filter(Q(folder=current_folder) | Q(folder__parent=current_folder))
else:
current_folder = None
if query:
outfits = outfits.filter(Q(name__icontains=query))
# For weekday assignment in the list view
today = datetime.date.today()
start_of_week = today - datetime.timedelta(days=today.weekday())
week_dates = [start_of_week + datetime.timedelta(days=i) for i in range(7)]
day_names = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"]
week_data = [{'day': day_names[i], 'date': week_dates[i].strftime('%Y-%m-%d')} for i in range(7)]
# All folders for categorization
all_folders = OutfitFolder.objects.all().order_by('name')
context = {
'outfits': outfits,
'folders': folders,
'all_folders': all_folders,
'current_folder': current_folder,
'title': 'Outfits',
'week_data': week_data,
'sort': sort
}
return render(request, 'core/outfit_list.html', context)
def new_fit(request):
date_str = request.GET.get('date')
if request.method == 'POST':
form = OutfitForm(request.POST)
if form.is_valid():
outfit = form.save()
if date_str:
try:
date_obj = datetime.datetime.strptime(date_str, '%Y-%m-%d').date()
CalendarAssignment.objects.update_or_create(
date=date_obj,
defaults={'outfit': outfit}
)
return redirect('home')
except ValueError:
pass
return redirect('outfit_list')
else:
form = OutfitForm()
wardrobe_items = WardrobeItem.objects.all().order_by('-date_added')
accessories = Accessory.objects.all().order_by('-date_added')
main_categories = Category.objects.filter(parent=None)
return render(request, 'core/new_fit.html', {
'form': form,
'title': f'New Fit for {date_str}' if date_str else 'New Fit',
'wardrobe_items': wardrobe_items,
'accessories': accessories,
'main_categories': main_categories,
'date_str': date_str
})
def get_subcategories(request):
parent_id = request.GET.get('parent_id')
if parent_id:
subcategories = Category.objects.filter(parent_id=parent_id).values('id', 'name')
return JsonResponse(list(subcategories), safe=False)
return JsonResponse([], safe=False)
def wardrobe_item_detail(request, pk):
item = get_object_or_404(WardrobeItem, pk=pk)
return render(request, 'core/item_detail.html', {'item': item, 'type': 'wardrobe'})
def accessory_item_detail(request, pk):
item = get_object_or_404(Accessory, pk=pk)
return render(request, 'core/item_detail.html', {'item': item, 'type': 'accessory'})
def cleanup_category(category):
if category and not category.is_preset:
if not category.wardrobe_items.exists() and not category.accessories.exists() and not category.children.exists():
parent = category.parent
category.delete()
if parent:
cleanup_category(parent)
def cleanup_folder(folder):
if folder and not folder.is_preset:
if not folder.outfits.exists() and not folder.children.exists():
parent = folder.parent
folder.delete()
if parent:
cleanup_folder(parent)
@require_POST
def delete_wardrobe_item(request, pk):
item = get_object_or_404(WardrobeItem, pk=pk)
category = item.category
item.delete()
cleanup_category(category)
return redirect('wardrobe_list')
@require_POST
def delete_accessory_item(request, pk):
item = get_object_or_404(Accessory, pk=pk)
category = item.category
item.delete()
cleanup_category(category)
return redirect('accessory_list')
@require_POST
def delete_outfit(request, pk):
outfit = get_object_or_404(Outfit, pk=pk)
folder = outfit.folder
outfit.delete()
cleanup_folder(folder)
return redirect('outfit_list')
@require_POST
def move_outfit(request, pk):
outfit = get_object_or_404(Outfit, pk=pk)
folder_id = request.POST.get('folder_id')
new_folder_name = request.POST.get('new_folder_name')
old_folder = outfit.folder
if new_folder_name:
folder = OutfitFolder.objects.create(name=new_folder_name)
outfit.folder = folder
elif folder_id:
folder = get_object_or_404(OutfitFolder, id=folder_id)
outfit.folder = folder
else:
outfit.folder = None
outfit.save()
cleanup_folder(old_folder)
return redirect('outfit_list')