Completed
Pull Request — master (#31)
by
unknown
01:02
created

get_model_fields()   B

Complexity

Conditions 7

Size

Total Lines 15

Duplication

Lines 0
Ratio 0 %

Importance

Changes 3
Bugs 0 Features 0
Metric Value
c 3
b 0
f 0
dl 0
loc 15
rs 7.3333
cc 7
1
import re
2
from math import floor
3
from django import template
4
from itertools import chain
5
from django.template.defaultfilters import stringfilter
6
from collections import namedtuple
7
8
try:
9
    from django.utils.encoding import force_text
10
except ImportError:
11
    from django.utils.encoding import force_unicode as force_text
12
13
register = template.Library()
14
Field = namedtuple('Field', 'name verbose_name')
15
16
17
@register.filter
18
@stringfilter
19
def undertospaced(value):
20
    return value.replace("_", " ").title()
21
22
23
@register.filter
24
def get_value(obj, field):
25
    try:
26
        return getattr(obj, 'get_%s_display' % field)()
27
    except:
28
        return getattr(obj, field)
29
30
31
@register.filter
32
def get_model_fields(obj):
33
    model = obj.__class__
34
    excludes = ['pk']
35
36
    property_fields = []
37
    for name in dir(model):
38
        if name not in excludes and isinstance(
39
            getattr(model, name, None), property
40
        ):
41
            property_fields.append(Field(name=name, verbose_name=name))
42
    ret = chain(obj._meta.fields, property_fields)
43
    if exclude:
44
        return chain(i for i in ret if not i.name in exclude)
45
    return ret
46
47
@register.filter
48
def get_verbose_field_name(instance, field_name):
49
    """
50
    Returns verbose_name for a field.
51
    """
52
    fields = [field.name for field in instance._meta.fields]
53
    if field_name in fields:
54
        return instance._meta.get_field(field_name).verbose_name.title()
55
    else:
56
        return field_name.title()
57
58
59
@register.filter(is_safe=True)
60
def label_with_class(value, arg):
61
    """Style adjustments"""
62
    return value.label_tag(attrs={'class': arg})
63
64
65
@register.filter(is_safe=True)
66
def input_with_class(value, arg):
67
    value.field.widget.attrs['class'] = arg
68
    return value
69
70
71
@register.filter(is_safe=True)
72
def inline_objects(object, inline_fk):
73
    inline_model = inline_fk.model
74
    related_filter = {inline_fk.name: object}
75
    return inline_model.objects.filter(**related_filter)
76
77
78
@register.inclusion_tag('widgets/tables/pagination.html')
79
def bootstrap_pagination(page, **kwargs):
80
    pagination_kwargs = kwargs.copy()
81
    pagination_kwargs['page'] = page
82
    return get_pagination_context(**pagination_kwargs)
83
84
85
def get_pagination_context(page, pages_to_show=11,
86
                           url=None, size=None, extra=None,
87
                           parameter_name='page'):
88
    """
89
    Generate Bootstrap pagination context from a page object
90
    """
91
    pages_to_show = int(pages_to_show)
92
    if pages_to_show < 1:
93
        raise ValueError(
94
            "Pagination pages_to_show should be a positive"
95
            "integer, you specified {pages}".format(
96
                pages=pages_to_show)
97
        )
98
    num_pages = page.paginator.num_pages
99
    current_page = page.number
100
    half_page_num = int(floor(pages_to_show / 2))
101
    if half_page_num < 0:
102
        half_page_num = 0
103
    first_page = current_page - half_page_num
104
    if first_page <= 1:
105
        first_page = 1
106
    if first_page > 1:
107
        pages_back = first_page - half_page_num
108
        if pages_back < 1:
109
            pages_back = 1
110
    else:
111
        pages_back = None
112
    last_page = first_page + pages_to_show - 1
113
    if pages_back is None:
114
        last_page += 1
115
    if last_page > num_pages:
116
        last_page = num_pages
117
    if last_page < num_pages:
118
        pages_forward = last_page + half_page_num
119
        if pages_forward > num_pages:
120
            pages_forward = num_pages
121
    else:
122
        pages_forward = None
123
        if first_page > 1:
124
            first_page -= 1
125
        if pages_back is not None and pages_back > 1:
126
            pages_back -= 1
127
        else:
128
            pages_back = None
129
    pages_shown = []
130
    for i in range(first_page, last_page + 1):
131
        pages_shown.append(i)
132
        # Append proper character to url
133
    if url:
134
        # Remove existing page GET parameters
135
        url = force_text(url)
136
        url = re.sub(r'\?{0}\=[^\&]+'.format(parameter_name), '?', url)
137
        url = re.sub(r'\&{0}\=[^\&]+'.format(parameter_name), '', url)
138
        # Append proper separator
139
        if '?' in url:
140
            url += '&'
141
        else:
142
            url += '?'
143
            # Append extra string to url
144
    if extra:
145
        if not url:
146
            url = '?'
147
        url += force_text(extra) + '&'
148
    if url:
149
        url = url.replace('?&', '?')
150
    # Set CSS classes, see http://getbootstrap.com/components/#pagination
151
    pagination_css_classes = ['pagination']
152
    if size == 'small':
153
        pagination_css_classes.append('pagination-sm')
154
    elif size == 'large':
155
        pagination_css_classes.append('pagination-lg')
156
        # Build context object
157
    return {
158
        'bootstrap_pagination_url': url,
159
        'num_pages': num_pages,
160
        'current_page': current_page,
161
        'first_page': first_page,
162
        'last_page': last_page,
163
        'pages_shown': pages_shown,
164
        'pages_back': pages_back,
165
        'pages_forward': pages_forward,
166
        'pagination_css_classes': ' '.join(pagination_css_classes),
167
        'parameter_name': parameter_name,
168
    }
169