get_pagination_context()   F
last analyzed

Complexity

Conditions 21

Size

Total Lines 83

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
c 2
b 0
f 0
dl 0
loc 83
rs 2.1114
cc 21

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

Complexity

Complex classes like get_pagination_context() often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

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