Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improvements #2

Open
wants to merge 17 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

setup(
name='django-template-utils',
version='0.1.1',
version=__import__('template_utils').__version__,
description='Just a collection of useful template tags and filters gathered in a single app.',
long_description=README,
author='Gerardo Orozco Mosqueda',
Expand All @@ -28,6 +28,6 @@
'Topic :: Utilities',
],
install_requires=[
'Django>=1.4',
'Django<3.1',
]
)
2 changes: 2 additions & 0 deletions template_utils/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
VERSION = (0, 1, 7,)
__version__ = '.'.join(map(str, VERSION))
3 changes: 0 additions & 3 deletions template_utils/models.py

This file was deleted.

108 changes: 107 additions & 1 deletion template_utils/templatetags/templateutils_filters.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from decimal import Decimal
import locale
import re
import datetime
from django.utils import timezone
from django import template
from django.template.defaultfilters import stringfilter
Expand Down Expand Up @@ -72,11 +73,24 @@ def startswith(value, arg):
<arg> must be a string.

Usage:
{{ value|startsvith:"arg" }}
{{ value|startswith:"arg" }}
"""
return value.startswith(arg)


@register.filter
@stringfilter
def endswith(value, arg):
"""
Returns whether the given value ends with the given string arg.
<arg> must be a string.

Usage:
{{ value|endswith:"arg" }}
"""
return value.endswith(arg)


@register.filter
def creditcard(value, arg=4):
"""
Expand Down Expand Up @@ -139,3 +153,95 @@ def verbose(bound_field, default=None):
today = today.date()
age = (today - bound_field.value()).days / 365
return age


@register.filter(name='has_group')
def has_group(user, group_name):
"""
Returns True if user belongs to group

Usage:
{% if user|has_group:"Administrators" %}

Arguments:
user {auth.User} -- User to test
group_name {str} -- Group name

Returns:
[bool] -- True or False
"""
return user.groups.filter(name=group_name).exists()


@register.filter(name='fieldtype')
def fieldtype(field):
"""
Returns the field type of the widget

Usage:
{% if field|fieldtype == "TextInput" %}

Arguments:
field {str} -- field object

Returns:
[str] -- Field type name
"""
return field.field.widget.__class__.__name__


@register.filter(name='hasattr')
def if_hasattr(object, attribute):
"""
Returns True if the object has attribute

Arguments:
object {object} -- Object to evaluate
attribute {str} -- Name of the attribute

Returns:
[bool] -- True or False
"""
return hasattr(object, attribute)


@register.filter(name='getattr')
def if_getattr(o, args):
"""Gets an attribute of an object dynamically from a string name"""

print(f"{o}: {args}")
try:
attribute, default = args.split(',')
except ValueError:
attribute, default = args, ''

if hasattr(o, str(attribute)):
return getattr(o, attribute, default)
else:
raise ValueError(f"{o} does not have {attribute} attribute")


@register.filter()
def addDays(date, days):
"""Adds a specific number of days to date object, it doesn't care if is timezone date"""
newDate = date + datetime.timedelta(days=days)
return newDate


@register.filter(name='has_perm')
def if_has_perm(user, perm_name):
"""
Returns True if user has_perm

Usage:
{% if user|has_perm:"auth.add_user" %}

Arguments:
user {auth.User} -- User to test
perm_name {str} -- Perm name

Returns:
[bool] -- True or False
"""
return user.has_perm(perm_name)

165 changes: 159 additions & 6 deletions template_utils/templatetags/templateutils_tags.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
from django import template
from django.template import resolve_variable, TemplateSyntaxError
from django.urls import reverse
from django.template import Variable, TemplateSyntaxError
from django.core.exceptions import ImproperlyConfigured
from django.contrib.auth.models import Group
from django.core.urlresolvers import reverse
from django.forms.models import model_to_dict
from django.utils.safestring import mark_safe
from django.core import serializers
from hashlib import md5
from urllib.parse import urlencode


register = template.Library()

Expand Down Expand Up @@ -73,7 +80,7 @@ def __init__(self, group, nodelist):
self.nodelist = nodelist

def render(self, context):
user = resolve_variable('user', context)
user = Variable('user').resolve(context)
if not user.is_authenticated:
return ''
try:
Expand Down Expand Up @@ -110,9 +117,9 @@ def mkrange(parser, token):
fnctl = tokens.pop(0)

def raise_error():
raise TemplateSyntaxError('%s accepts the syntax: {%% %s [start,] ' + \
'stop[, step] as context_name %%}, where "start", "stop" ' + \
'and "step" must all be integers.' % (fnctl, fnctl))
raise TemplateSyntaxError('%s accepts the syntax: {%% %s [start,] ' +
'stop[, step] as context_name %%}, where "start", "stop" ' +
'and "step" must all be integers.' % (fnctl, fnctl))

range_args = []

Expand Down Expand Up @@ -142,3 +149,149 @@ def __init__(self, range_args, context_name):
def render(self, context):
context[self.context_name] = range(*self.range_args)
return ''


# Model helpers
@register.simple_tag
def get_model_as_dict(instance):
"""
Returns a django model instance as dictionary

Usage: {% get_model_as_dict model_instance %}
"""
return model_to_dict(instance)


@register.simple_tag
def get_verbose_field_name(instance, field_name):
"""
Returns the name title of a django field model instance

Usage: {% get_verbose_field_name model_instance model_field %}
"""
return instance._meta.get_field(field_name).verbose_name.title()


@register.simple_tag
def get_modelfield_url(field):
"""
Returns url of filefield or imagefield object

Usage: {% get_field_url model_instance.model_field %}
"""
"""Regresa el field url de un FileField o ImageField """
return field.url


@register.simple_tag
def serialize_queryset(queryset, fields=None):
"""
Returns queryset, with filtered fields if included

Usage: {% serialize_queryset queryset %}
"""
if fields:
return serializers.serialize("python", queryset, fields=tuple(fields.split(",")))
return serializers.serialize("python", queryset)


# General helpers
@register.simple_tag
def sorted_dict_fields(dict, fields):
"""
Returns sorted dict based on list

Usage: {% sorted_dict_fields dict %}
"""
ordered_fields = fields.split(",")
new_dict = {k: v for k, v in dict.items() if k in ordered_fields}
return sorted(new_dict.items(), key=lambda pair: ordered_fields.index(pair[0]))


@register.simple_tag
def template_dir(this_object):
"""
Returns dir of object for introspection

Usage: {% template_dir object %}
"""
return mark_safe("<pre>" + str(dir(this_object)) + "</pre>")


@register.simple_tag(takes_context=True)
def get_gravatar(context, size=64, rating='g', default=None):
"""
Return url for a gravatar.

Usage {% get_gravatar %}
"""
if 'request' not in context:
raise ImproperlyConfigured(
"get_gravatar template tag requires 'django.core.context_processors.request'"
" context processor installed.")

user = context["user"]
if not user.is_authenticated:
raise ImproperlyConfigured("get_gravatar template tag requires authenticated user")

if not user.email:
raise ImproperlyConfigured("get_gravatar template tag requires user with email")

url = 'https://secure.gravatar.com/avatar/{0}.jpg'.format(
md5(user.email.strip().lower().encode('utf-8')).hexdigest()
)
options = {'s': size, 'r': rating}
if default:
options['d'] = default

url = '%s?%s' % (url, urlencode(options))
return url.replace('&', '&amp;')


@register.simple_tag(takes_context=True)
def get_uiavatar(context, size=64, rounded=True):
"""
Return url for a letter avatar.

Usage {% get_uiavatar %}
"""
colors = ['e6194B', '3cb44b', 'ffe119', '4363d8', 'f58231', '911eb4',
'42d4f4', 'f032e6', 'bfef45', 'fabebe', '469990', 'e6beff',
'9A6324', 'fffac8', '800000', 'aaffc3', '808000', 'ffd8b1',
'000075', 'a9a9a9']

if 'request' not in context:
raise ImproperlyConfigured(
"get_uiavatar template tag requires 'django.core.context_processors.request'"
" context processor installed.")

user = context["user"]
if not user.is_authenticated:
raise ImproperlyConfigured("get_uiavatar template tag requires authenticated user")

name = user.first_name if user.first_name else user.username
if user.last_name:
name += " " + user.last_name[0] # fix en caso de mas de 1 apellio

url = 'https://ui-avatars.com/api/'

options = {'name': name, 'size': size, 'color': 'fff', 'background': colors[user.id % 20]}
if rounded:
options['rounded'] = 'true'

url = '%s?%s' % (url, urlencode(options))
return url


@register.simple_tag(takes_context=True)
def get_userperms(context):
"""
Return user_perm

Usage {% get_userperms %}
"""
user = context["user"]
if not user.is_authenticated:
raise ImproperlyConfigured("get_userperms template tag requires authenticated user")

return user.get_all_permissions()
1 change: 0 additions & 1 deletion template_utils/views.py

This file was deleted.

10 changes: 0 additions & 10 deletions template_utils_project/manage.py

This file was deleted.

1 change: 0 additions & 1 deletion template_utils_project/template_utils

This file was deleted.

Empty file.
Loading