Skip to content

Instantly share code, notes, and snippets.

@jamstooks
Created July 6, 2011 16:40
Show Gist options
  • Save jamstooks/1067706 to your computer and use it in GitHub Desktop.
Save jamstooks/1067706 to your computer and use it in GitHub Desktop.
Orderable List Mixins
from leaguejam.apps.manage.org.views import OrgContextMixin
from leaguejam.apps.manage.org.participants.forms import ParticipantSearchForm
from django.views.generic.list import ListView, MultipleObjectMixin
from django.views.generic.edit import FormMixin
from django.db.models import Q
import re
class FormMixinGET(FormMixin):
def get_form_kwargs(self):
"""
Use get every time
"""
kwargs = {
'initial': self.get_initial(),
'data': self.request.GET,
}
return kwargs
class ListFilterView(FormMixinGET, ListView):
"""
Show a filterable list of participants
Uses a form to filter the queryset.
Extenders should provide a get_queryset_from_form_data method
"""
context_object_name = "object_list"
def get_queryset(self):
# save form to object to pass to context
self.form = self.get_form(self.get_form_class())
data = {}
if self.form.is_valid():
data = self.form.cleaned_data
return self.get_queryset_from_form_data(data)
def get_queryset_from_form_data(self, data):
"""
Updates the queryset based on form data.
Override this
"""
return super(ListFilterView, self).get_queryset()
def get_context_data(self, **kwargs):
_kwargs = {}
_kwargs.update(kwargs)
# provide the form to the context
_kwargs['form'] = self.form
# provide the GET Request w/out the page for paging links
# this is so that we can keep the form submission when we page
_kwargs['get_request_vars_sans_page'] = re.sub("&?page=\d+", "", self.request.GET.urlencode())
# I have to return this, because FormMixin doesn't use super
return ListView.get_context_data(self, **_kwargs)
# return super(ParticipantListView, self).get_context_data(**_kwargs)
class OrderableListMixin(MultipleObjectMixin):
"""
Uses get_columns, get_ordered_columns, and self.order_queryset_by
to provide ordering tools
simply use the self.order_queryset_by property in your get_queryset method
"""
order_queryset_by = None
def get_queryset(self):
if self.request.GET.has_key('order_by'):
self.order_queryset_by = self.request.GET['order_by']
return self.get_ordered_queryset(self.order_queryset_by)
def get_columns(self):
"""
Can be overridden to update the columns
should update self.columns and then call super to keep the update functionality below
columns are in the form:
[
{
'title': "", # the title of the column
'property': "", # the property to filter by
'default': "", # the default ordering (asc or desc)
},
]
"""
return []
def get_ordered_columns(self):
_columns = self.get_columns()
# update the column attributes to indicate if they are being used for ordering
if hasattr(self, "order_queryset_by"):
for c in _columns:
if self.order_queryset_by == c['property']:
c['asc'] = True
elif self.order_queryset_by == "-%s" % c['property']:
c['desc'] = True
return _columns
def get_context_data(self, **kwargs):
"""
Provides the columns to the context along with the
get_request_vars_sans_order property to use in links
"""
_context = super(OrderableListMixin, self).get_context_data(**kwargs)
# provide the GET Request w/out the page for paging links
get_request_vars = re.sub("&?page=\d+", "", self.request.GET.urlencode())
_context['get_request_vars_sans_page'] = get_request_vars
get_request_vars = re.sub("&?order_by=[^&]+", "", get_request_vars)
_context['get_request_vars_sans_order'] = get_request_vars
_context['columns'] = self.get_ordered_columns()
qs = _context[self.get_context_object_name(None)]
return _context
class ListFilterOrderView(OrderableListMixin, ListFilterView):
"""
"""
def get_context_data(self, **kwargs):
_context = {}
_context.update(OrderableListMixin.get_context_data(self, **kwargs))
_context.update(ListFilterView.get_context_data(self, **kwargs))
return _context
def get_ordered_queryset(self, order_by):
"""
Use the ListFilterView get_queryset method
so the form is processed
"""
return self.order_queryset(ListFilterView.get_queryset(self), order_by)
def order_queryset(self, qs, order_by):
if order_by:
qs = qs.order_by(order_by)
return qs
@jamstooks
Copy link
Author

Template:

{% if page_obj.has_previous %}
    <a href="?{% if get_request_vars_sans_page %}{{ get_request_vars_sans_page }}{% endif %}&page={{ page_obj.previous_page_number }}">
        &lt;
        {% if previous %}{{ previous }}{% else %}previous{% endif %}
    </a>
{% endif %}

<span class="current">
    Page {{ page_obj.number }} of {{ paginator.num_pages }}
</span>

{% if page_obj.has_next %}
    <a href="?{% if get_request_vars_sans_page %}{{ get_request_vars_sans_page }}{% endif %}&page={{ page_obj.next_page_number }}">
        {% if next %}{{ next }}{% else %}next{% endif %}
        &gt;
    </a>
{% endif %}

@jamstooks
Copy link
Author

Columns in template:

{% for column in columns %}
    <th>
        {% if column.property %}
            <a
                href='?{{ get_request_vars_sans_order }}&order_by={% if column.asc %}-{% else %}{% if not column.asc and not column.desc and column.default == "desc" %}-{% endif %}{% endif %}{{ column.property }}'
                title='Sort by {{ column.title }}'>
                    {{ column.title }}
            {% if column.asc %}
                <img src='/static/images/icons/bullet_arrow_up.png' alt='^'/>
            {% endif %}{% if column.desc %}
                <img src='/static/images/icons/bullet_arrow_down.png' alt='' />
            {% endif %}
            </a>
        {% else %}
            {{ column.title }}
        {% endif %}
    </th>
{% endfor %}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment