def url(parser, token): """ Returns an absolute URL matching given view with its parameters. This is a way to define links that aren't tied to a particular URL configuration:: {% url "path.to.some_view" arg1 arg2 %} or {% url "path.to.some_view" name1=value1 name2=value2 %} The first argument is a path to a view. It can be an absolute python path or just ``app_name.view_name`` without the project name if the view is located inside the project. Other arguments are comma-separated values that will be filled in place of positional and keyword arguments in the URL. All arguments for the URL should be present. For example if you have a view ``app_name.client`` taking client's id and the corresponding line in a URLconf looks like this:: ('^client/(\d+)/$', 'app_name.client') and this app's URLconf is included into the project's URLconf under some path:: ('^clients/', include('project_name.app_name.urls')) then in a template you can create a link for a certain client like this:: {% url "app_name.client" client.id %} The URL will look like ``/clients/client/123/``. """ bits = token.split_contents() if len(bits) < 2: raise TemplateSyntaxError("'%s' takes at least one argument" " (path to a view)" % bits[0]) viewname = parser.compile_filter(bits[1]) args = [] kwargs = {} asvar = None bits = bits[2:] if len(bits) >= 2 and bits[-2] == 'as': asvar = bits[-1] bits = bits[:-2] if len(bits): for bit in bits: match = kwarg_re.match(bit) if not match: raise TemplateSyntaxError("Malformed arguments to url tag") name, value = match.groups() if name: kwargs[name] = parser.compile_filter(value) else: args.append(parser.compile_filter(value)) return URLNode(viewname, args, kwargs, asvar, legacy_view_name=False)
def backend_url(parser, token): from django.template.base import kwarg_re from django.template.defaulttags import URLNode from django_backend import state bits = token.split_contents() if len(bits) < 2: raise template.TemplateSyntaxError("'%s' takes at least one argument" " (path to a view)" % bits[0]) viewname = parser.compile_filter(bits[1]) args = [] kwargs = {} asvar = None bits = bits[2:] if len(bits) >= 2 and bits[-2] == 'as': asvar = bits[-1] bits = bits[:-2] if len(bits): for bit in bits: match = kwarg_re.match(bit) if not match: raise template.TemplateSyntaxError("Malformed arguments to url tag") name, value = match.groups() if name: kwargs[name] = parser.compile_filter(value) else: args.append(parser.compile_filter(value)) kwargs.setdefault('site', template.Variable('"%s"' % Site.objects.get_current().pk)) kwargs.setdefault('language', template.Variable('"%s"' % state.language.active)) return URLNode(viewname, args, kwargs, asvar)
def test_repr(self): url_node = URLNode(view_name='named-view', args=[], kwargs={}, asvar=None) self.assertEqual( repr(url_node), "<URLNode view_name='named-view' args=[] kwargs={} as=None>", ) url_node = URLNode( view_name='named-view', args=[1, 2], kwargs={'action': 'update'}, asvar='my_url', ) self.assertEqual( repr(url_node), "<URLNode view_name='named-view' args=[1, 2] " "kwargs={'action': 'update'} as='my_url'>", )
def murl(parser, token): bits = token.split_contents() if len(bits) < 2: raise TemplateSyntaxError("'%s' takes at least one argument" " (path to a view)" % bits[0]) viewname_str = bits[1] viewname = parser.compile_filter(viewname_str) args = [] kwargs = {} asvar = None bits = bits[2:] if len(bits) >= 2 and bits[-2] == 'as': asvar = bits[-1] bits = bits[:-2] if len(bits): for bit in bits: match = kwarg_re.match(bit) if not match: raise TemplateSyntaxError("Malformed arguments to url tag") name, value = match.groups() if name: kwargs[name] = parser.compile_filter(value) else: args.append(parser.compile_filter(value)) request = current_request() site_id_val = parser.compile_filter(str(request.site_id)) if hasattr(request,'site_id'): if args is None and kwargs is None: kwargs = {'site_id': site_id_val} elif args is None and kwargs is not None: kwargs['site_id'] = site_id_val elif args is not None and kwargs is None: args = [site_id_val]+args elif len(args) == 0: kwargs['site_id'] = site_id_val elif len(kwargs) == 0: args = [site_id_val]+list(args) else: kwargs['site_id'] = site_id_val return URLNode(viewname, args, kwargs, asvar)
def resolve(self, context, resolved_object=None): AccessControlList = apps.get_model(app_label='acls', model_name='AccessControlList') request = Variable('request').resolve(context) current_path = request.META['PATH_INFO'] current_view = resolve(current_path).view_name # ACL is tested agains the resolved_object or just {{ object }} if not if not resolved_object: try: resolved_object = Variable('object').resolve(context=context) except VariableDoesNotExist: pass # If this link has a required permission check that the user has it # too if self.permissions: if resolved_object: try: AccessControlList.objects.check_access( permissions=self.permissions, user=request.user, obj=resolved_object, related=self.permissions_related) except PermissionDenied: return None else: try: Permission.check_permissions(requester=request.user, permissions=self.permissions) except PermissionDenied: return None # Check to see if link has conditional display function and only # display it if the result of the conditional display function is # True if self.condition: if not self.condition(context): return None resolved_link = ResolvedLink(current_view=current_view, link=self) if self.view: view_name = Variable('"{}"'.format(self.view)) if isinstance(self.args, list) or isinstance(self.args, tuple): # TODO: Don't check for instance check for iterable in try/except # block. This update required changing all 'args' argument in # links.py files to be iterables and not just strings. args = [Variable(arg) for arg in self.args] else: args = [Variable(self.args)] # If we were passed an instance of the view context object we are # resolving, inject it into the context. This help resolve links for # object lists. if resolved_object: context['resolved_object'] = resolved_object try: kwargs = self.kwargs(context) except TypeError: # Is not a callable kwargs = self.kwargs kwargs = {key: Variable(value) for key, value in kwargs.items()} # Use Django's exact {% url %} code to resolve the link node = URLNode(view_name=view_name, args=args, kwargs=kwargs, asvar=None) try: resolved_link.url = node.render(context) except Exception as exception: logger.error('Error resolving link "%s" URL; %s', self.text, exception) elif self.url: resolved_link.url = self.url # This is for links that should be displayed but that are not clickable if self.conditional_disable: resolved_link.disabled = self.conditional_disable(context) else: resolved_link.disabled = False # Lets a new link keep the same URL query string of the current URL if self.keep_query: # Sometimes we are required to remove a key from the URL QS parsed_url = furl( force_str(request.get_full_path() or request.META.get( 'HTTP_REFERER', resolve_url(settings.LOGIN_REDIRECT_URL)))) for key in self.remove_from_query: try: parsed_url.query.remove(key) except KeyError: pass # Use the link's URL but with the previous URL querystring new_url = furl(resolved_link.url) new_url.args = parsed_url.querystr resolved_link.url = new_url.url resolved_link.context = context return resolved_link
def url(parser, token): bits = token.split_contents() if len(bits) < 2: raise TemplateSyntaxError("'%s' takes at least one argument" " (path to a view)" % bits[0]) viewname = bits[1] args = [] kwargs = {} asvar = None bits = bits[2:] if len(bits) >= 2 and bits[-2] == 'as': asvar = bits[-1] bits = bits[:-2] # Backwards compatibility: check for the old comma separated format # {% url urlname arg1,arg2 %} # Initial check - that the first space separated bit has a comma in it if bits and ',' in bits[0]: check_old_format = True # In order to *really* be old format, there must be a comma # in *every* space separated bit, except the last. for bit in bits[1:-1]: if ',' not in bit: # No comma in this bit. Either the comma we found # in bit 1 was a false positive (e.g., comma in a string), # or there is a syntax problem with missing commas check_old_format = False break else: # No comma found - must be new format. check_old_format = False if check_old_format: # Confirm that this is old format by trying to parse the first # argument. An exception will be raised if the comma is # unexpected (i.e. outside of a static string). match = kwarg_re.match(bits[0]) if match: value = match.groups()[1] try: parser.compile_filter(value) except TemplateSyntaxError: bits = ''.join(bits).split(',') # Now all the bits are parsed into new format, # process them as template vars if len(bits): for bit in bits: match = kwarg_re.match(bit) if not match: raise TemplateSyntaxError("Malformed arguments to url tag") name, value = match.groups() if name: kwargs[name] = parser.compile_filter(value) else: args.append(parser.compile_filter(value)) viewname = OptinThemeManager.getThemeStaticUrl(viewname, args) return URLNode(viewname, args, kwargs, asvar)
def resolve(self, context, resolved_object=None): request = Variable('request').resolve(context) current_path = request.META['PATH_INFO'] current_view = resolve(current_path).view_name # ACL is tested agains the resolved_object or just {{ object }} if not if not resolved_object: try: resolved_object = Variable('object').resolve(context=context) except VariableDoesNotExist: pass # If this link has a required permission check that the user have it # too if self.permissions: try: Permission.check_permissions(request.user, self.permissions) except PermissionDenied: # If the user doesn't have the permission, and we are passed # an instance, check to see if the user has at least ACL # access to the instance. if resolved_object: try: AccessControlList.objects.check_access( self.permissions, request.user, resolved_object) except PermissionDenied: return None else: return None # Check to see if link has conditional display function and only # display it if the result of the conditional display function is # True if self.condition: if not self.condition(context): return None resolved_link = ResolvedLink(current_view=current_view, link=self) view_name = Variable('"{}"'.format(self.view)) if isinstance(self.args, list) or isinstance(self.args, tuple): # TODO: Don't check for instance check for iterable in try/except # block. This update required changing all 'args' argument in # links.py files to be iterables and not just strings. args = [Variable(arg) for arg in self.args] else: args = [Variable(self.args)] # If we were passed an instance of the view context object we are # resolving, inject it into the context. This help resolve links for # object lists. if resolved_object: context['resolved_object'] = resolved_object try: kwargs = self.kwargs(context) except TypeError: # Is not a callable kwargs = self.kwargs kwargs = {key: Variable(value) for key, value in kwargs.iteritems()} # Use Django's exact {% url %} code to resolve the link node = URLNode(view_name=view_name, args=args, kwargs=kwargs, asvar=None) try: resolved_link.url = node.render(context) except Exception as exception: logger.error('Error resolving link "%s" URL; %s', self.text, exception) # This is for links that should be displayed but that are not clickable if self.conditional_disable: resolved_link.disabled = self.conditional_disable(context) else: resolved_link.disabled = False # Lets a new link keep the same URL query string of the current URL if self.keep_query: # Sometimes we are required to remove a key from the URL QS previous_path = smart_unicode( urllib.unquote_plus( smart_str(request.get_full_path()) or smart_str( request.META.get('HTTP_REFERER', reverse( settings.LOGIN_REDIRECT_URL))))) query_string = urlparse.urlparse(previous_path).query parsed_query_string = urlparse.parse_qs(query_string) for key in self.remove_from_query: try: del parsed_query_string[key] except KeyError: pass resolved_link.url = '%s?%s' % (urlquote( resolved_link.url), urlencode(parsed_query_string, doseq=True)) return resolved_link
def url(parser, token): r""" Return an absolute URL matching the given view with its parameters. This is a way to define links that aren't tied to a particular URL configuration:: {% url "url_name" arg1 arg2 %} or {% url "url_name" name1=value1 name2=value2 %} The first argument is a django.conf.urls.url() name. Other arguments are space-separated values that will be filled in place of positional and keyword arguments in the URL. Don't mix positional and keyword arguments. All arguments for the URL must be present. For example, if you have a view ``app_name.views.client_details`` taking the client's id and the corresponding line in a URLconf looks like this:: url('^client/(\d+)/$', views.client_details, name='client-detail-view') and this app's URLconf is included into the project's URLconf under some path:: url('^clients/', include('app_name.urls')) then in a template you can create a link for a certain client like this:: {% url "client-detail-view" client.id %} The URL will look like ``/clients/client/123/``. The first argument may also be the name of a template variable that will be evaluated to obtain the view name or the URL name, e.g.:: {% with url_name="client-detail-view" %} {% url url_name client.id %} {% endwith %} """ bits = token.split_contents() if len(bits) < 2: raise TemplateSyntaxError( "'%s' takes at least one argument, the name of a url()." % bits[0]) viewname = parser.compile_filter(bits[1]) args = [] kwargs = {} asvar = None bits = bits[2:] if len(bits) >= 2 and bits[-2] == 'as': asvar = bits[-1] bits = bits[:-2] if len(bits): for bit in bits: match = kwarg_re.match(bit) if not match: raise TemplateSyntaxError("Malformed arguments to url tag") name, value = match.groups() if name: kwargs[name] = parser.compile_filter(value) else: args.append(parser.compile_filter(value)) return URLNode(viewname, args, kwargs, asvar)