edit route descriptions: only suggest neighbor spaces

This commit is contained in:
Laura Klünder 2017-12-19 01:49:54 +01:00
parent 0a0bf9972a
commit b32b5c2beb
2 changed files with 55 additions and 5 deletions

View file

@ -1,8 +1,11 @@
import json import json
import operator import operator
from functools import reduce from functools import reduce
from itertools import chain
from django.core.cache import cache
from django.core.exceptions import FieldDoesNotExist from django.core.exceptions import FieldDoesNotExist
from django.db.models import Q
from django.forms import (BooleanField, CharField, ChoiceField, Form, ModelChoiceField, ModelForm, MultipleChoiceField, from django.forms import (BooleanField, CharField, ChoiceField, Form, ModelChoiceField, ModelForm, MultipleChoiceField,
ValidationError) ValidationError)
from django.forms.widgets import HiddenInput from django.forms.widgets import HiddenInput
@ -13,10 +16,11 @@ from c3nav.editor.models import ChangeSet, ChangeSetUpdate
from c3nav.mapdata.fields import GeometryField from c3nav.mapdata.fields import GeometryField
from c3nav.mapdata.forms import I18nModelFormMixin from c3nav.mapdata.forms import I18nModelFormMixin
from c3nav.mapdata.models import GraphEdge from c3nav.mapdata.models import GraphEdge
from c3nav.mapdata.models.access import AccessPermission
class EditorFormBase(I18nModelFormMixin, ModelForm): class EditorFormBase(I18nModelFormMixin, ModelForm):
def __init__(self, *args, request=None, **kwargs): def __init__(self, *args, space_id=None, request=None, **kwargs):
self.request = request self.request = request
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
creating = not self.instance.pk creating = not self.instance.pk
@ -71,9 +75,36 @@ class EditorFormBase(I18nModelFormMixin, ModelForm):
self.fields['access_restriction'].label_from_instance = lambda obj: obj.title self.fields['access_restriction'].label_from_instance = lambda obj: obj.title
self.fields['access_restriction'].queryset = AccessRestriction.qs_for_request(self.request) self.fields['access_restriction'].queryset = AccessRestriction.qs_for_request(self.request)
if 'target_space' in self.fields: if space_id and 'target_space' in self.fields:
Space = self.request.changeset.wrap_model('Space') Space = self.request.changeset.wrap_model('Space')
space_qs = Space.qs_for_request(self.request)
GraphNode = self.request.changeset.wrap_model('GraphNode')
GraphEdge = self.request.changeset.wrap_model('GraphEdge')
cache_key = 'editor:neighbor_spaces:%s:%s%d' % (
self.request.changeset.raw_cache_key_by_changes,
AccessPermission.cache_key_for_request(request, with_update=False),
space_id
)
other_spaces = cache.get(cache_key, None)
if other_spaces is None:
AccessPermission.cache_key_for_request(request, with_update=False) + ':' + str(request.user.pk or 0)
space_nodes = set(GraphNode.objects.filter(space_id=space_id).values_list('pk', flat=True))
space_edges = GraphEdge.objects.filter(
Q(from_node_id__in=space_nodes) | Q(to_node_id__in=space_nodes)
).values_list('from_node_id', 'to_node_id')
other_nodes = set(chain(*space_edges)) - space_nodes
other_spaces = set(GraphNode.objects.filter(pk__in=other_nodes).values_list('space_id', flat=True))
other_spaces.discard(space_id)
cache.set(cache_key, other_spaces, 900)
for space_field in ('origin_space', 'target_space'):
other_space_id = getattr(self.instance, space_field+'_id', None)
if other_space_id:
other_spaces.add(other_space_id)
space_qs = Space.qs_for_request(self.request).filter(pk__in=other_spaces)
for space_field in ('origin_space', 'target_space'): for space_field in ('origin_space', 'target_space'):
if space_field in self.fields: if space_field in self.fields:
self.fields[space_field].label_from_instance = lambda obj: obj.title self.fields[space_field].label_from_instance = lambda obj: obj.title

View file

@ -142,6 +142,7 @@ def edit(request, pk=None, model=None, level=None, space=None, on_top_of=None, e
'geomtype': model._meta.get_field('geometry').geomtype, 'geomtype': model._meta.get_field('geometry').geomtype,
}) })
space_id = None
if model == Level: if model == Level:
ctx.update({ ctx.update({
'level': obj, 'level': obj,
@ -183,6 +184,7 @@ def edit(request, pk=None, model=None, level=None, space=None, on_top_of=None, e
'geometry_url': '/api/editor/geometries/?level='+str(level.primary_level_pk), 'geometry_url': '/api/editor/geometries/?level='+str(level.primary_level_pk),
}) })
elif hasattr(model, 'space'): elif hasattr(model, 'space'):
space_id = space.pk
if not new: if not new:
space = obj.space space = obj.space
ctx.update({ ctx.update({
@ -234,7 +236,8 @@ def edit(request, pk=None, model=None, level=None, space=None, on_top_of=None, e
ctx['obj_title'] = obj.title ctx['obj_title'] = obj.title
return render(request, 'editor/delete.html', ctx) return render(request, 'editor/delete.html', ctx)
form = model.EditorForm(instance=model() if new else obj, data=request.POST, request=request) form = model.EditorForm(instance=model() if new else obj, data=request.POST,
request=request, space_id=space_id)
if form.is_valid(): if form.is_valid():
# Update/create objects # Update/create objects
obj = form.save(commit=False) obj = form.save(commit=False)
@ -266,7 +269,7 @@ def edit(request, pk=None, model=None, level=None, space=None, on_top_of=None, e
messages.error(request, _('You can not edit changes on this changeset.')) messages.error(request, _('You can not edit changes on this changeset.'))
else: else:
form = model.EditorForm(instance=obj, request=request) form = model.EditorForm(instance=obj, request=request, space_id=space_id)
ctx.update({ ctx.update({
'form': form, 'form': form,
@ -319,12 +322,28 @@ def list_objects(request, model=None, level=None, space=None, explicit_edit=Fals
sub_qs = Space.objects.filter(Space.q_for_request(request)).select_related('level').defer('geometry') sub_qs = Space.objects.filter(Space.q_for_request(request)).select_related('level').defer('geometry')
space = get_object_or_404(sub_qs, pk=space) space = get_object_or_404(sub_qs, pk=space)
queryset = queryset.filter(space=space) queryset = queryset.filter(space=space)
try: try:
model._meta.get_field('geometry') model._meta.get_field('geometry')
except FieldDoesNotExist: except FieldDoesNotExist:
pass pass
else: else:
queryset = queryset.defer('geometry') queryset = queryset.defer('geometry')
try:
model._meta.get_field('origin_space')
except FieldDoesNotExist:
pass
else:
queryset = queryset.select_related('origin_space')
try:
model._meta.get_field('target_space')
except FieldDoesNotExist:
pass
else:
queryset = queryset.select_related('target_space')
ctx.update({ ctx.update({
'levels': Level.objects.filter(Level.q_for_request(request), on_top_of__isnull=True), 'levels': Level.objects.filter(Level.q_for_request(request), on_top_of__isnull=True),
'level': space.level, 'level': space.level,