Complete replacement of Thing types with tag system
This commit is contained in:
109
boxes/views.py
109
boxes/views.py
@@ -11,25 +11,28 @@ from .forms import (
|
||||
ThingLinkForm,
|
||||
ThingPictureForm,
|
||||
)
|
||||
from .models import Box, BoxType, Thing, ThingFile, ThingLink, ThingType
|
||||
from .models import Box, BoxType, Facet, Tag, Thing, ThingFile, ThingLink
|
||||
|
||||
|
||||
@login_required
|
||||
def index(request):
|
||||
"""Home page with boxes and thing types."""
|
||||
"""Home page with boxes and tags."""
|
||||
boxes = Box.objects.select_related('box_type').all().order_by('id')
|
||||
thing_types = ThingType.objects.all()
|
||||
|
||||
type_counts = {}
|
||||
for thing_type in thing_types:
|
||||
descendants = thing_type.get_descendants(include_self=True)
|
||||
count = Thing.objects.filter(thing_type__in=descendants).count()
|
||||
type_counts[thing_type.pk] = count
|
||||
|
||||
facets = Facet.objects.all().prefetch_related('tags')
|
||||
|
||||
facet_tag_counts = {}
|
||||
for facet in facets:
|
||||
for tag in facet.tags.all():
|
||||
count = tag.things.count()
|
||||
if count > 0:
|
||||
if facet not in facet_tag_counts:
|
||||
facet_tag_counts[facet] = []
|
||||
facet_tag_counts[facet].append((tag, count))
|
||||
|
||||
return render(request, 'boxes/index.html', {
|
||||
'boxes': boxes,
|
||||
'thing_types': thing_types,
|
||||
'type_counts': type_counts,
|
||||
'facets': facets,
|
||||
'facet_tag_counts': facet_tag_counts,
|
||||
})
|
||||
|
||||
|
||||
@@ -37,7 +40,7 @@ def index(request):
|
||||
def box_detail(request, box_id):
|
||||
"""Display contents of a box."""
|
||||
box = get_object_or_404(Box, pk=box_id)
|
||||
things = box.things.select_related('thing_type').all()
|
||||
things = box.things.all()
|
||||
return render(request, 'boxes/box_detail.html', {
|
||||
'box': box,
|
||||
'things': things,
|
||||
@@ -48,11 +51,12 @@ def box_detail(request, box_id):
|
||||
def thing_detail(request, thing_id):
|
||||
"""Display details of a thing."""
|
||||
thing = get_object_or_404(
|
||||
Thing.objects.select_related('thing_type', 'box', 'box__box_type').prefetch_related('files', 'links'),
|
||||
Thing.objects.select_related('box', 'box__box_type').prefetch_related('files', 'links', 'tags'),
|
||||
pk=thing_id
|
||||
)
|
||||
|
||||
boxes = Box.objects.select_related('box_type').all().order_by('id')
|
||||
facets = Facet.objects.all().prefetch_related('tags')
|
||||
picture_form = ThingPictureForm(instance=thing)
|
||||
file_form = ThingFileForm()
|
||||
link_form = ThingLinkForm()
|
||||
@@ -118,9 +122,34 @@ def thing_detail(request, thing_id):
|
||||
pass
|
||||
return redirect('thing_detail', thing_id=thing.id)
|
||||
|
||||
elif action == 'add_tag':
|
||||
tag_id = request.POST.get('tag_id')
|
||||
if tag_id:
|
||||
try:
|
||||
tag = Tag.objects.get(pk=tag_id)
|
||||
if tag.facet.cardinality == Facet.Cardinality.SINGLE:
|
||||
existing_tags = list(thing.tags.filter(facet=tag.facet))
|
||||
for existing_tag in existing_tags:
|
||||
thing.tags.remove(existing_tag)
|
||||
thing.tags.add(tag)
|
||||
except Tag.DoesNotExist:
|
||||
pass
|
||||
return redirect('thing_detail', thing_id=thing.id)
|
||||
|
||||
elif action == 'remove_tag':
|
||||
tag_id = request.POST.get('tag_id')
|
||||
if tag_id:
|
||||
try:
|
||||
tag = Tag.objects.get(pk=tag_id)
|
||||
thing.tags.remove(tag)
|
||||
except Tag.DoesNotExist:
|
||||
pass
|
||||
return redirect('thing_detail', thing_id=thing.id)
|
||||
|
||||
return render(request, 'boxes/thing_detail.html', {
|
||||
'thing': thing,
|
||||
'boxes': boxes,
|
||||
'facets': facets,
|
||||
'picture_form': picture_form,
|
||||
'file_form': file_form,
|
||||
'link_form': link_form,
|
||||
@@ -140,21 +169,34 @@ def search_api(request):
|
||||
if len(query) < 2:
|
||||
return JsonResponse({'results': []})
|
||||
|
||||
things = Thing.objects.filter(
|
||||
Q(name__icontains=query) |
|
||||
Q(description__icontains=query) |
|
||||
Q(thing_type__name__icontains=query) |
|
||||
Q(files__title__icontains=query) |
|
||||
Q(files__file__icontains=query) |
|
||||
Q(links__title__icontains=query) |
|
||||
Q(links__url__icontains=query)
|
||||
).prefetch_related('files', 'links').select_related('thing_type', 'box').distinct()[:50]
|
||||
# Check for "Facet:Word" format
|
||||
if ':' in query:
|
||||
parts = query.split(':',1)
|
||||
facet_name = parts[0].strip()
|
||||
tag_name = parts[1].strip()
|
||||
|
||||
# Search for things with specific facet and tag
|
||||
things = Thing.objects.filter(
|
||||
Q(tags__facet__name__icontains=facet_name) &
|
||||
Q(tags__name__icontains=tag_name)
|
||||
).prefetch_related('files', 'links').select_related('box').distinct()[:50]
|
||||
else:
|
||||
# Normal search
|
||||
things = Thing.objects.filter(
|
||||
Q(name__icontains=query) |
|
||||
Q(description__icontains=query) |
|
||||
Q(files__title__icontains=query) |
|
||||
Q(files__file__icontains=query) |
|
||||
Q(links__title__icontains=query) |
|
||||
Q(links__url__icontains=query) |
|
||||
Q(tags__name__icontains=query) |
|
||||
Q(tags__facet__name__icontains=query)
|
||||
).prefetch_related('files', 'links').select_related('box').distinct()[:50]
|
||||
|
||||
results = [
|
||||
{
|
||||
'id': thing.id,
|
||||
'name': thing.name,
|
||||
'type': thing.thing_type.name,
|
||||
'box': thing.box.id,
|
||||
'description': thing.description[:100] if thing.description else '',
|
||||
'files': [
|
||||
@@ -208,25 +250,6 @@ def add_things(request, box_id):
|
||||
})
|
||||
|
||||
|
||||
@login_required
|
||||
def thing_type_detail(request, type_id):
|
||||
"""Display details of a thing type with its hierarchy and things."""
|
||||
thing_type = get_object_or_404(ThingType, pk=type_id)
|
||||
|
||||
descendants = thing_type.get_descendants(include_self=True)
|
||||
things_by_type = {}
|
||||
|
||||
for descendant in descendants:
|
||||
things = descendant.things.select_related('box', 'box__box_type').all()
|
||||
if things:
|
||||
things_by_type[descendant] = things
|
||||
|
||||
return render(request, 'boxes/thing_type_detail.html', {
|
||||
'thing_type': thing_type,
|
||||
'things_by_type': things_by_type,
|
||||
})
|
||||
|
||||
|
||||
@login_required
|
||||
def box_management(request):
|
||||
"""Main page for managing boxes and box types."""
|
||||
|
||||
Reference in New Issue
Block a user