<commit_before>from flask import abort, request

from .base import BaseView, TemplateResponseMixin
from .exceptions import ImproperlyConfigured
from .utils import camelcase_to_underscore


class MultipleObjectMixin(object):
    query_object = None
    model = None
    context_object_name = None
    paginate_by = None
    sort_by = None

    def get_query_object(self):
        if self.query_object is not None:
            query_object = self.query_object
        elif self.model:
            query_object = getattr(self.model, "query")
        else:
            raise ImproperlyConfigured("Either a model or query_object must be defined.")

        return query_object

    def get_paginate_by(self):
        return self.paginate_by

    def paginate_query_object(self, query_object, page_size):
        page = request.args.get("page") or 1
        try:
            page_number = int(page)
        except ValueError:
            abort(404)

        paginator = query_object.paginate(page_number, page_size)

        return (paginator, paginator.items, paginator.has_prev or paginator.has_next)

    def get_sort_by(self):
        return self.sort_by

    def sort_query_object(self, query_object):
        sort_by = request.args.get("sort_by", self.get_sort_by())

        if sort_by:
            if sort_by[0] == "-":
                query_object = query_object.order_by(
                    getattr(query_object._entities[0].entity_zero.class_, sort_by[1:]).desc())
            else:
                query_object = query_object.order_by(
                    getattr(query_object._entities[0].entity_zero.class_, sort_by))

        return query_object

    def get_context_object_name(self, object_list):
        if self.context_object_name:
            return self.context_object_name
        elif hasattr(object_list, "column_descriptions"):
            return str("%s_list" % camelcase_to_underscore(
                object_list.column_descriptions[0]["name"]))
        else:
            return None

    def get_context_data(self, **kwargs):
        query_object = kwargs.pop("object_list")
        page_size = self.get_paginate_by()
        context_object_name = self.get_context_object_name(query_object)

        if self.sort_by:
            query_object = self.sort_query_object(query_object)

        if page_size:
            paginator, query_object, is_paginated = self.paginate_query_object(query_object, page_size)
            context = {
                "paginator": paginator,
                "is_paginated": is_paginated,
                "object_list": query_object<commit_msg>added ability to sort by relationship (currently only 1 deep)<commit_after>from flask import abort, request

from .base import BaseView, TemplateResponseMixin
from .exceptions import ImproperlyConfigured
from .utils import camelcase_to_underscore


class MultipleObjectMixin(object):
    query_object = None
    model = None
    context_object_name = None
    paginate_by = None
    sort_by = None

    def get_query_object(self):
        if self.query_object is not None:
            query_object = self.query_object
        elif self.model:
            query_object = getattr(self.model, "query")
        else:
            raise ImproperlyConfigured("Either a model or query_object must be defined.")

        return query_object

    def get_paginate_by(self):
        return self.paginate_by

    def paginate_query_object(self, query_object, page_size):
        page = request.args.get("page") or 1
        try:
            page_number = int(page)
        except ValueError:
            abort(404)

        paginator = query_object.paginate(page_number, page_size)

        return (paginator, paginator.items, paginator.has_prev or paginator.has_next)

    def get_sort_by(self):
        return self.sort_by

    def sort_query_object(self, query_object):
        sort_by = request.args.get("sort_by", self.get_sort_by())
        query_object_entity = query_object._entities[0].entity_zero.class_

        if sort_by:
            if "." in sort_by:
                # parse the fields out
                # needed for sorting on relationship fields
                tokens = sort_by.rsplit(".", 1)

                if sort_by[0] == "-":
                    rel_class = getattr(query_object.first(), tokens[0][1:]).__class__
                    query_object = query_object.join(getattr(
                        query_object_entity, tokens[0][1:])).order_by(getattr(
                            rel_class, tokens[1]).desc())
                else:
                    rel_class = getattr(query_object.first(), tokens[0]).__class__
                    query_object = query_object.join(getattr(
                        query_object_entity, tokens[0])).order_by(getattr(
                            rel_class, tokens[1]))
            else:
                if sort_by[0] == "-":
                    query_object = query_object.order_by(
                        getattr(query_object_entity, sort_by[1:]).desc())
                else:
                    query_object = query_object.order_by(
                        getattr(query_object_entity, sort_by))

        return query_object

    def get_context_object_name(self, object_list):
        if self.context_object_name:
            return self.context_object_name
        elif hasattr(object_list, "column_descriptions"):
            return str("%s_list" % camelcase_to_underscore(
                object_list.column_descriptions[0]["name"]))
        else:
            return None

    def get_context_data(self, **kwargs):
        query_object = kwargs.pop("object_list")
        page_size = self.get_paginate_by()
        context_object_name = self.get_context_object_name(query_object)

        if self.sort_by:
            query_object = self.sort_query_object(query_object)

        if page_size:
            paginator, query_object, is_paginated = self.paginate_query_object(query_object, page_size)
            context = {
                "paginator": paginator,
                "is_paginated": is_paginated,
                "object_list": query_object
{'fraction_non_alphanumeric': 0.08206388206388206, 'fraction_numerical': 0.004586404586404586, 'mean_word_length': 2.2444208289054197, 'pattern_counts': {'":': 9, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2329699', 'n_tokens_mistral': 1784, 'n_tokens_neox': 1708, 'n_words': 352}