def render(self, context): url = self.url.resolve(context) parts = url.split("?") url = parts[0] original_query = QueryDict("&".join(parts[1:])).copy() query = MultiValueDict(dict((k, v.resolve(context)) for k, v in six.iteritems(self.kwargs))) args_to_set = [] args_to_remove = [] for arg in self.args: k = arg.resolve(context) if k.startswith("-"): args_to_remove.append(k[1:]) else: args_to_set.append(k) kwargs_to_set = MultiValueDict() kwargs_to_add = MultiValueDict() kwargs_to_remove = MultiValueDict() for (k, v) in query.lists(): # make sure val is a list of strings val = map(str, v if isinstance(v, list) else [v]) if k.startswith("+"): kwargs_to_add.setlistdefault(k[1:]).extend(val) elif k.startswith("-"): kwargs_to_remove.setlistdefault(k[1:]).extend(val) else: kwargs_to_set.setlist(k, val) filter_excluded_kwargs = lambda values: [ (k, list(set(v) - set(kwargs_to_remove.getlist(k)))) for k, v in values.iterlists() if k not in args_to_remove ] args = [arg for arg in args_to_set if arg not in args_to_remove] kwargs = MultiValueDict() for k, v in filter_excluded_kwargs(original_query): kwargs.setlistdefault(k).extend(v if isinstance(v, list) else [v]) for k, v in filter_excluded_kwargs(kwargs_to_set): kwargs.setlist(k, v) for k, v in filter_excluded_kwargs(kwargs_to_add): kwargs.setlistdefault(k).extend(v) output = list(set(args)) for k, l in kwargs.lists(): output.extend(["%s=%s" % (k, v) if v else six.text_type(k) for v in l]) if output: url = "?".join([url, "&".join(set(output))]) if self.asvar: context[self.asvar] = url return "" else: return url