diff --git a/spejstore/urls.py b/spejstore/urls.py index 8fec492..366fa95 100644 --- a/spejstore/urls.py +++ b/spejstore/urls.py @@ -15,6 +15,7 @@ from storage import apiviews router = routers.DefaultRouter() router.register(r'items', apiviews.ItemViewSet) +router.register(r'labels', apiviews.LabelViewSet) # Wire up our API using automatic URL routing. # Additionally, we include login URLs for the browsable API. diff --git a/storage/admin.py b/storage/admin.py index bcb4f21..df53b54 100644 --- a/storage/admin.py +++ b/storage/admin.py @@ -1,6 +1,6 @@ from django import forms from django.contrib import admin -from .models import Item, ItemImage, Category +from .models import Item, ItemImage, Category, Label from django_select2.forms import Select2Widget, Select2MultipleWidget @@ -19,11 +19,14 @@ class ItemImageInline(admin.TabularInline): model = ItemImage extra = 1 +class LabelInline(admin.TabularInline): + model = Label + class ItemAdmin(admin.ModelAdmin): list_display = ('_name',) list_filter = ('categories',) form = ItemForm - inlines = [ItemImageInline] + inlines = [ItemImageInline, LabelInline] save_on_top = True def _name(self, obj): diff --git a/storage/apiviews.py b/storage/apiviews.py index 8ca834b..b2bfed1 100644 --- a/storage/apiviews.py +++ b/storage/apiviews.py @@ -1,11 +1,18 @@ -from rest_framework import viewsets, generics +from rest_framework import viewsets, generics, filters from rest_framework.response import Response from rest_framework.decorators import detail_route -from storage.models import Item -from storage.serializers import ItemSerializer +from storage.models import Item, Label +from storage.serializers import ItemSerializer, LabelSerializer from django.shortcuts import get_object_or_404 +class LabelViewSet(viewsets.ModelViewSet): + """ + API endpoint that allows items to be viewed or edited. + """ + queryset = Label.objects + serializer_class = LabelSerializer + class ItemViewSet(viewsets.ModelViewSet): """ diff --git a/storage/migrations/0003_auto_20170424_2002.py b/storage/migrations/0003_auto_20170424_2002.py new file mode 100644 index 0000000..5fbe73a --- /dev/null +++ b/storage/migrations/0003_auto_20170424_2002.py @@ -0,0 +1,43 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.1 on 2017-04-24 20:02 +from __future__ import unicode_literals + +from django.db import migrations, models +import django.db.models.deletion +import django_hstore.fields + + +class Migration(migrations.Migration): + + dependencies = [ + ('storage', '0002_auto_20170215_0115'), + ] + + operations = [ + migrations.CreateModel( + name='Label', + fields=[ + ('id', models.CharField(max_length=64, primary_key=True, serialize=False)), + ('revision', models.IntegerField()), + ], + ), + migrations.AlterModelOptions( + name='item', + options={'ordering': ('path',)}, + ), + migrations.AlterField( + model_name='item', + name='categories', + field=models.ManyToManyField(blank=True, to='storage.Category'), + ), + migrations.AlterField( + model_name='item', + name='props', + field=django_hstore.fields.DictionaryField(blank=True), + ), + migrations.AddField( + model_name='label', + name='item', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='labels', to='storage.Item'), + ), + ] diff --git a/storage/models.py b/storage/models.py index d3ee291..5bf5ce0 100644 --- a/storage/models.py +++ b/storage/models.py @@ -60,3 +60,9 @@ class Item(models.Model, TreeModelMixin): class ItemImage(models.Model): item = models.ForeignKey(Item, related_name='images') image = models.ImageField() + + +class Label(models.Model): + id = models.CharField(max_length=64, primary_key=True) + item = models.ForeignKey(Item, related_name='labels') + revision = models.IntegerField() diff --git a/storage/serializers.py b/storage/serializers.py index 384e35b..fcd27cc 100644 --- a/storage/serializers.py +++ b/storage/serializers.py @@ -1,4 +1,4 @@ -from storage.models import Item +from storage.models import Item, Label from rest_framework import serializers from rest_framework_hstore.serializers import HStoreSerializer @@ -7,3 +7,9 @@ class ItemSerializer(HStoreSerializer): class Meta: model = Item fields = ('uuid', 'name', 'description', 'props', 'state', 'parent') + +class LabelSerializer(serializers.ModelSerializer): + item = ItemSerializer() + class Meta: + model = Label + fields = ('id', 'item', 'revision') diff --git a/storage/templates/item.html b/storage/templates/item.html index bbc82c8..345ec8e 100644 --- a/storage/templates/item.html +++ b/storage/templates/item.html @@ -41,6 +41,13 @@ {% endfor %} {% endif %} + + {% if labels %} +

Labels

+ {% for label in labels %} + {{ label.id }} ({{ label.revision }}) + {% endfor %} + {% endif %}
diff --git a/storage/urls.py b/storage/urls.py index 4151968..4d861b3 100644 --- a/storage/urls.py +++ b/storage/urls.py @@ -1,8 +1,9 @@ from django.conf.urls import include, url -from storage.views import index, search, item_display +from storage.views import index, search, item_display, label_lookup urlpatterns = [ url(r'^$', index), url(r'^search$', search), url(r'^item/(?P.*)$', item_display, name='item-display'), + url(r'^(?P[^/]*)$', label_lookup, name='label-lookup'), ] diff --git a/storage/views.py b/storage/views.py index 587b14d..acc6ffd 100644 --- a/storage/views.py +++ b/storage/views.py @@ -1,5 +1,5 @@ -from django.shortcuts import render, get_object_or_404 -from storage.models import Item +from django.shortcuts import render, get_object_or_404, redirect +from storage.models import Item, Label from django.contrib.postgres.search import SearchVector import shlex @@ -61,6 +61,11 @@ def item_display(request, pk): return render(request, 'item.html', { 'item': item, 'images': item.images.all(), + 'labels': item.labels.all(), 'ancestors': item.get_ancestors(), 'children': item.get_children(), }) + +def label_lookup(request, pk): + label = get_object_or_404(Label, pk=pk) + return redirect(label.item)