def edit_queue(request, queue_id=None): template = 'admin/queues/form.html' if queue_id: queue = Queue.objects.get(pk=queue_id) queue_form = QueueForm(instance=queue, prefix='queue') else: queue = Queue() queue_form = QueueForm(prefix='queue') if request.method == 'POST': if queue_id is None: queue_form = QueueForm(request.POST, request.FILES, prefix='queue') else: queue = Queue.objects.get(pk=queue_id) queue_form = QueueForm(request.POST, request.FILES, instance=queue, prefix='queue') if not queue_form.is_valid(): return render(request, template, {'queue_form': queue_form}) queue_form.save() # process queue's statuses queue.queuestatus_set.all().delete() data = DotExpandedDict(request.POST) if data.get('status'): for s in data['status'].values(): if s.get('status_id'): # status is selected... qs = s qs['queue'] = queue QueueStatus.objects.create(**qs) messages.add_message(request, messages.INFO, _(u'Jono tallennettu')) return redirect('/admin/queues/') selected = list() for s in queue.queuestatus_set.all(): selected.append(s.status.pk) statuses = list() for s in Status.objects.all(): if s.id in selected: stat = queue.queuestatus_set.get(status_id=s.id) s.limit_green = stat.limit_green s.limit_yellow = stat.limit_yellow s.limit_factor = stat.limit_factor statuses.append(s) return render(request, template, { 'queue_form': queue_form, 'statuses': statuses, 'selected': selected })
def test_dotexpandeddict(self): d = DotExpandedDict({ 'person.1.firstname': ['Simon'], 'person.1.lastname': ['Willison'], 'person.2.firstname': ['Adrian'], 'person.2.lastname': ['Holovaty'] }) self.assertEqual(d['person']['1']['lastname'], ['Willison']) self.assertEqual(d['person']['2']['lastname'], ['Holovaty']) self.assertEqual(d['person']['2']['firstname'], ['Adrian'])
def value_from_datadict(self, data, files, name, *args, **kwargs): reminder_events_raw = {} for key in data: if key[0:16] == "reminder_events.": reminder_events_raw[key] = data[key] event_dict = DotExpandedDict(reminder_events_raw) events = [] if len(event_dict) > 0: for key in sorted(event_dict["reminder_events"].iterkeys()): events.append(event_dict["reminder_events"][key]) return events
def value_from_datadict(self, data, files, name, *args, **kwargs): input_name = self.attrs["input_name"] raw = {} for key in data: if key.startswith(input_name + "."): raw[key] = data[key] data_dict = DotExpandedDict(raw) data_list = [] if len(data_dict) > 0: for key in sorted(data_dict[input_name].iterkeys()): data_list.append(data_dict[input_name][key]) return data_list
def save(self, new_data): # TODO: big cleanup when core fields go -> use recursive manipulators. params = {} for f in self.opts.fields: # Fields with auto_now_add should keep their original value in the change stage. auto_now_add = self.change and getattr(f, 'auto_now_add', False) if self.follow.get(f.name, None) and not auto_now_add: param = f.get_manipulator_new_data(new_data) else: if self.change: param = getattr(self.original_object, f.attname) else: param = f.get_default() params[f.attname] = param if self.change: params[self.opts.pk.attname] = self.obj_key # First, create the basic object itself. new_object = self.model(**params) # Now that the object's been created, save any uploaded files. for f in self.opts.fields: if isinstance(f, FileField): f.save_file(new_data, new_object, self.change and self.original_object or None, self.change, rel=False, save=False) # Now save the object new_object.save() # Calculate which primary fields have changed. if self.change: self.fields_added, self.fields_changed, self.fields_deleted = [], [], [] for f in self.opts.fields: if not f.primary_key and smart_str( getattr(self.original_object, f.attname)) != smart_str( getattr(new_object, f.attname)): self.fields_changed.append(f.verbose_name) # Save many-to-many objects. Example: Set sites for a poll. for f in self.opts.many_to_many: if self.follow.get(f.name, None): if not f.rel.edit_inline: new_vals = new_data.getlist(f.name) # First, clear the existing values. rel_manager = getattr(new_object, f.name) rel_manager.clear() # Then, set the new values. for n in new_vals: rel_manager.add(f.rel.to._default_manager.get(pk=n)) # TODO: Add to 'fields_changed' expanded_data = DotExpandedDict(dict(new_data)) # Save many-to-one objects. Example: Add the Choice objects for a Poll. for related in self.opts.get_all_related_objects(): # Create obj_list, which is a DotExpandedDict such as this: # [('0', {'id': ['940'], 'choice': ['This is the first choice']}), # ('1', {'id': ['941'], 'choice': ['This is the second choice']}), # ('2', {'id': [''], 'choice': ['']})] child_follow = self.follow.get(related.name, None) if child_follow: obj_list = expanded_data.get(related.var_name, {}).items() if not obj_list: continue obj_list.sort(lambda x, y: cmp(int(x[0]), int(y[0]))) # For each related item... for _, rel_new_data in obj_list: params = {} # Keep track of which core=True fields were provided. # If all core fields were given, the related object will be saved. # If none of the core fields were given, the object will be deleted. # If some, but not all, of the fields were given, the validator would # have caught that. all_cores_given, all_cores_blank = True, True # Get a reference to the old object. We'll use it to compare the # old to the new, to see which fields have changed. old_rel_obj = None if self.change: if rel_new_data[related.opts.pk.name][0]: try: old_rel_obj = getattr( self.original_object, related.get_accessor_name()).get( **{ '%s__exact' % related.opts.pk.name: rel_new_data[ related.opts.pk.attname][0] }) except ObjectDoesNotExist: pass for f in related.opts.fields: if f.core and not isinstance( f, FileField) and f.get_manipulator_new_data( rel_new_data, rel=True) in (None, ''): all_cores_given = False elif f.core and not isinstance( f, FileField) and f.get_manipulator_new_data( rel_new_data, rel=True) not in (None, ''): all_cores_blank = False # If this field isn't editable, give it the same value it had # previously, according to the given ID. If the ID wasn't # given, use a default value. FileFields are also a special # case, because they'll be dealt with later. if f == related.field: param = getattr( new_object, related.field.rel.get_related_field().attname) elif (not self.change) and isinstance(f, AutoField): param = None elif self.change and ( isinstance(f, FileField) or not child_follow.get(f.name, None)): if old_rel_obj: param = getattr(old_rel_obj, f.column) else: param = f.get_default() else: param = f.get_manipulator_new_data(rel_new_data, rel=True) if param != None: params[f.attname] = param # Create the related item. new_rel_obj = related.model(**params) # If all the core fields were provided (non-empty), save the item. if all_cores_given: new_rel_obj.save() # Save any uploaded files. for f in related.opts.fields: if child_follow.get(f.name, None): if isinstance(f, FileField) and rel_new_data.get( f.name, False): f.save_file(rel_new_data, new_rel_obj, self.change and old_rel_obj or None, old_rel_obj is not None, rel=True) # Calculate whether any fields have changed. if self.change: if not old_rel_obj: # This object didn't exist before. self.fields_added.append( '%s "%s"' % (related.opts.verbose_name, new_rel_obj)) else: for f in related.opts.fields: if not f.primary_key and f != related.field and smart_str( getattr(old_rel_obj, f.attname) ) != smart_str( getattr(new_rel_obj, f.attname)): self.fields_changed.append( '%s for %s "%s"' % (f.verbose_name, related.opts.verbose_name, new_rel_obj)) # Save many-to-many objects. for f in related.opts.many_to_many: if child_follow.get( f.name, None) and not f.rel.edit_inline: new_value = rel_new_data[f.attname] setattr( new_rel_obj, f.name, f.rel.to.objects.filter(pk__in=new_value)) if self.change: self.fields_changed.append( '%s for %s "%s"' % (f.verbose_name, related.opts.verbose_name, new_rel_obj)) # If, in the change stage, all of the core fields were blank and # the primary key (ID) was provided, delete the item. if self.change and all_cores_blank and old_rel_obj: new_rel_obj.delete() self.fields_deleted.append( '%s "%s"' % (related.opts.verbose_name, old_rel_obj)) # Save the order, if applicable. if self.change and self.opts.get_ordered_objects(): order = new_data['order_'] and map( int, new_data['order_'].split(',')) or [] for rel_opts in self.opts.get_ordered_objects(): getattr(new_object, 'set_%s_order' % rel_opts.object_name.lower())(order) return new_object
def save(self, new_data): # TODO: big cleanup when core fields go -> use recursive manipulators. params = {} for f in self.opts.fields: # Fields with auto_now_add should keep their original value in the change stage. auto_now_add = self.change and getattr(f, 'auto_now_add', False) if self.follow.get(f.name, None) and not auto_now_add: param = f.get_manipulator_new_data(new_data) else: if self.change: param = getattr(self.original_object, f.attname) else: param = f.get_default() params[f.attname] = param if self.change: params[self.opts.pk.attname] = self.obj_key # First, create the basic object itself. new_object = self.model(**params) # Now that the object's been created, save any uploaded files. for f in self.opts.fields: if isinstance(f, FileField): f.save_file(new_data, new_object, self.change and self.original_object or None, self.change, rel=False, save=False) # Now save the object new_object.save() # Calculate which primary fields have changed. if self.change: self.fields_added, self.fields_changed, self.fields_deleted = [], [], [] for f in self.opts.fields: if not f.primary_key and str(getattr(self.original_object, f.attname)) != str(getattr(new_object, f.attname)): self.fields_changed.append(f.verbose_name) # Save many-to-many objects. Example: Set sites for a poll. for f in self.opts.many_to_many: if self.follow.get(f.name, None): if not f.rel.edit_inline: if f.rel.raw_id_admin: new_vals = new_data.get(f.name, ()) else: new_vals = new_data.getlist(f.name) # First, clear the existing values. rel_manager = getattr(new_object, f.name) rel_manager.clear() # Then, set the new values. for n in new_vals: rel_manager.add(f.rel.to._default_manager.get(pk=n)) # TODO: Add to 'fields_changed' expanded_data = DotExpandedDict(dict(new_data)) # Save many-to-one objects. Example: Add the Choice objects for a Poll. for related in self.opts.get_all_related_objects(): # Create obj_list, which is a DotExpandedDict such as this: # [('0', {'id': ['940'], 'choice': ['This is the first choice']}), # ('1', {'id': ['941'], 'choice': ['This is the second choice']}), # ('2', {'id': [''], 'choice': ['']})] child_follow = self.follow.get(related.name, None) if child_follow: obj_list = expanded_data.get(related.var_name, {}).items() if not obj_list: continue obj_list.sort(lambda x, y: cmp(int(x[0]), int(y[0]))) # For each related item... for _, rel_new_data in obj_list: params = {} # Keep track of which core=True fields were provided. # If all core fields were given, the related object will be saved. # If none of the core fields were given, the object will be deleted. # If some, but not all, of the fields were given, the validator would # have caught that. all_cores_given, all_cores_blank = True, True # Get a reference to the old object. We'll use it to compare the # old to the new, to see which fields have changed. old_rel_obj = None if self.change: if rel_new_data[related.opts.pk.name][0]: try: old_rel_obj = getattr(self.original_object, related.get_accessor_name()).get(**{'%s__exact' % related.opts.pk.name: rel_new_data[related.opts.pk.attname][0]}) except ObjectDoesNotExist: pass for f in related.opts.fields: if f.core and not isinstance(f, FileField) and f.get_manipulator_new_data(rel_new_data, rel=True) in (None, ''): all_cores_given = False elif f.core and not isinstance(f, FileField) and f.get_manipulator_new_data(rel_new_data, rel=True) not in (None, ''): all_cores_blank = False # If this field isn't editable, give it the same value it had # previously, according to the given ID. If the ID wasn't # given, use a default value. FileFields are also a special # case, because they'll be dealt with later. if f == related.field: param = getattr(new_object, related.field.rel.get_related_field().attname) elif (not self.change) and isinstance(f, AutoField): param = None elif self.change and (isinstance(f, FileField) or not child_follow.get(f.name, None)): if old_rel_obj: param = getattr(old_rel_obj, f.column) else: param = f.get_default() else: param = f.get_manipulator_new_data(rel_new_data, rel=True) if param != None: params[f.attname] = param # Create the related item. new_rel_obj = related.model(**params) # If all the core fields were provided (non-empty), save the item. if all_cores_given: new_rel_obj.save() # Save any uploaded files. for f in related.opts.fields: if child_follow.get(f.name, None): if isinstance(f, FileField) and rel_new_data.get(f.name, False): f.save_file(rel_new_data, new_rel_obj, self.change and old_rel_obj or None, old_rel_obj is not None, rel=True) # Calculate whether any fields have changed. if self.change: if not old_rel_obj: # This object didn't exist before. self.fields_added.append('%s "%s"' % (related.opts.verbose_name, new_rel_obj)) else: for f in related.opts.fields: if not f.primary_key and f != related.field and str(getattr(old_rel_obj, f.attname)) != str(getattr(new_rel_obj, f.attname)): self.fields_changed.append('%s for %s "%s"' % (f.verbose_name, related.opts.verbose_name, new_rel_obj)) # Save many-to-many objects. for f in related.opts.many_to_many: if child_follow.get(f.name, None) and not f.rel.edit_inline: new_value = rel_new_data[f.attname] if f.rel.raw_id_admin: new_value = new_value[0] setattr(new_rel_obj, f.name, f.rel.to.objects.filter(pk__in=new_value)) if self.change: self.fields_changed.append('%s for %s "%s"' % (f.verbose_name, related.opts.verbose_name, new_rel_obj)) # If, in the change stage, all of the core fields were blank and # the primary key (ID) was provided, delete the item. if self.change and all_cores_blank and old_rel_obj: new_rel_obj.delete() self.fields_deleted.append('%s "%s"' % (related.opts.verbose_name, old_rel_obj)) # Save the order, if applicable. if self.change and self.opts.get_ordered_objects(): order = new_data['order_'] and map(int, new_data['order_'].split(',')) or [] for rel_opts in self.opts.get_ordered_objects(): getattr(new_object, 'set_%s_order' % rel_opts.object_name.lower())(order) return new_object
def post(self, request, *args, **kwargs): error = False dotdict = DotExpandedDict(request.POST) self.object = self.get_object() if self.request.user.is_authenticated(): if dotdict.has_key('assignment') and self.object.status == 'C': messages.error(self.request, 'You cannot change the assignment of a closed activity.') error = True elif dotdict.get('assignment', ''): user_id = dotdict['assignment'].get('user', '') priority = dotdict['assignment'].get('priority', '') escalation_status = dotdict['assignment'].get('escalation_status', '') user = None if user_id: try: user = User.objects.get(pk=int(user_id)) except (User.DoesNotExist, ValueError): messages.error(self.request, 'User with id %s does not exist.' % user_id) error = True if priority: try: priority = int(priority) except ValueError: messages.error(self.request, 'Priority must be an integer.') error = True if not error: error = not self.assign_user(user, priority, escalation_status) if dotdict.has_key('approved_id'): approved_id = dotdict.get('approved_id', '').strip() if self.object.status == 'C': messages.error(self.request, 'You cannot approve a closed activity.') error = True elif approved_id and not error: error = not self.approve_activity(approved_id) else: messages.error(self.request, 'You must provide an Approved ID.') error = True if dotdict.has_key('task'): assigned_user_id = dotdict['task'].get('assigned_user', '') assigned_user = None id = dotdict['task'].get('id', '') task_id = dotdict['task'].get('task_id', '') task = None status = dotdict['task'].get('status', '') if assigned_user_id: try: assigned_user = User.objects.get(pk=int(assigned_user_id)) except (User.DoesNotExist, ValueError): messages.error(self.request, 'User with id %s does not exist.' % user_id) error = True elif not id: messages.error(self.request, 'You must assign the task to a user.') error = True if not id: try: task = Task.objects.get(pk=int(task_id)) except(Task.DoesNotExist, ValueError): messages.error(self.request, 'Task with id %s is not a valid task.' % task_id) error = True if not error: error = not self.update_task(id, task, assigned_user, status) if dotdict.get('note', ''): message = dotdict['note'].get('message', '').strip() if not error: error = not self.add_note(message, self.request.user) status = dotdict.get('status', '') if status == 'C': if not error: error = not self.close_activity() else: messages.error(self.request, 'You must be logged in to edit an activity.') error = True if error: context = self.get_context_data() return self.render_to_response(context) else: return HttpResponseRedirect(self.request.get_full_path())
def pick_sightings(request, redirect_to): """ A replacement for the old add_sightings view. This one is designed to sit in between two different parts of the interface. It narrows down the list of entered text to concrete species as before, then forwards the user on to the redirect_to URL with concrete species IDs attached. For example, the resulting redirect may look like this: /gb/london-zoo/add-trip/?saw=x:2ab1&saw=s:123&saw=A+baby+tiger Note that there are now three types of saw IDs: x:* = a Xapian search ID s:* = an animals_species table ID * = free text not matched in our database Our sightings recording mechanism is now expected to be able to deal with free text, which will be recorded using species_inexact on a Sighting. The INPUT to this view should start off as something like this: ../pick-sightings/?saw.1.s=tiger&saw.2.s=pony If there are any ?saw= items, the view redirects straight away turning them in to that format. So, the easiest way to get started with the process is to send someone to: ../pick-sightings/?saw=tiger&saw=pony If called with no arguments, starts off with an empty "I saw" form Additionally, if you include a `trip` parameter in the query string, that's the id of the trip we'll add to directly; this just gets passed through to (This is an ugly implementation in terms of URLs, but was the easiest.) """ if request.GET.getlist('saw'): # Convert ?saw= arguments to ?saw.1.s= type things return Redirect(request.path + '?' + urllib.urlencode([ ('saw.%d.s' % i, saw.strip()) for i, saw in enumerate(request.GET.getlist('saw')) if saw.strip() ])) saw = DotExpandedDict(request.GET).get('saw') if request.GET and not saw: # Clear out the invalid query string return Redirect(request.path) if not saw: assert False, "Jump straight to showing the empty form" # saw should now of format {'0': {'s': 'tiger', 'o': 'x:ba3'}...} # Essentially a dictionary of key/dict pairs. The key doesn't actually # matter, it's just used to group values. The dict looks like this: # s = The text the user entered (required) # o = The option they picked to fulfill it (optional) # r = The replacement search they want to run (defaults to same as s) # The 'o' value comes from a radio select and can be of these formats: # x_* = a Xapian search ID they have selected # s_* = a Species ID they have selected # cancel = don't save this at all (e.g. "I made a mistake") # as-is = save it using species_inexact # search-again = run the replacement search instead # Are we done yet? The aim is for every key to have a valid option # provided that isn't 'search-again'. if saw and is_valid_saw_list(saw.values()): next_vars = [ urllib.urlencode({ 'saw': d['o'] == 'as-is' and d.get('s') or d['o'] }) for d in saw.values() if d.get('s') and (d['o'] != 'cancel') ] if request.GET.get('trip', None): next_vars.append( urllib.urlencode({ 'trip': request.GET['trip'] }) ) return Redirect(redirect_to + '?' + '&'.join(next_vars)) # We aren't done, so we need to build up all of the information required # to construct our big form full of options, search results etc sections = [] section_id = 0 label_id = 0 if saw: for key in sorted(saw.keys(), key = lambda k: int(k)): d = saw[key] search = d.get('r', d['s']).strip() if not search: continue results = list(search_species(search, 20)) db_matches = list(Species.objects.filter(freebase_id__in = [ r['freebase_id'] for r in results ])) choices = [] is_first = True for row in results: try: id = 's_%s' % [ s for s in db_matches if s.freebase_id == row['freebase_id'] ][0].id except IndexError: id = 'x_%s' % row['search_id'] choices.append({ 'id': id, 'common_name': row['common_name'], 'scientific_name': row['scientific_name'], 'label_id': label_id, 'checked': (d.get('o') == id or ( is_first and d.get('o') != 'cancel' )), }) label_id += 1 is_first = False sections.append({ 'id': section_id, 'search': d.get('r', d['s']), # Pick up replacement search 'options': choices, 'o': d.get('o'), }) section_id += 1 return render(request, 'trips/pick_sightings.html', { 'sections': sections, 'redirect_to': redirect_to, 'bonus_label_id': section_id, 'trip_id': request.GET.get('trip', None), })