1 from django.db import models
2 from django.contrib.contenttypes.models import ContentType
3 from django.core.paginator import Paginator, EmptyPage
6 def fattr(*args, **kwargs):
8 Returns a wrapper which takes a function as its only argument and sets the key/value pairs passed in with kwargs as attributes on that function. This can be used as a decorator.
12 >>> from philo.utils import fattr
13 >>> @fattr(short_description="Hello World!")
17 >>> x.short_description
21 def wrapper(function):
23 setattr(function, key, kwargs[key])
28 ### ContentTypeLimiters
31 class ContentTypeLimiter(object):
33 return models.Q(pk__in=[])
35 def add_to_query(self, query, *args, **kwargs):
36 query.add_q(self.q_object(), *args, **kwargs)
39 class ContentTypeRegistryLimiter(ContentTypeLimiter):
40 """Can be used to limit the choices for a :class:`ForeignKey` or :class:`ManyToManyField` to the :class:`ContentType`\ s which have been registered with this limiter."""
44 def register_class(self, cls):
45 """Registers a model class with this limiter."""
46 self.classes.append(cls)
48 def unregister_class(self, cls):
49 """Unregisters a model class from this limiter."""
50 self.classes.remove(cls)
54 for cls in self.classes:
56 if issubclass(cls, models.Model):
57 if not cls._meta.abstract:
58 contenttype = ContentType.objects.get_for_model(cls)
59 contenttype_pks.append(contenttype.pk)
62 return models.Q(pk__in=contenttype_pks)
65 class ContentTypeSubclassLimiter(ContentTypeLimiter):
67 Can be used to limit the choices for a :class:`ForeignKey` or :class:`ManyToManyField` to the :class:`ContentType`\ s for all non-abstract models which subclass the class passed in on instantiation.
69 :param cls: The class whose non-abstract subclasses will be valid choices.
70 :param inclusive: Whether ``cls`` should also be considered a valid choice (if it is a non-abstract subclass of :class:`models.Model`)
73 def __init__(self, cls, inclusive=False):
75 self.inclusive = inclusive
79 def handle_subclasses(cls):
80 for subclass in cls.__subclasses__():
82 if issubclass(subclass, models.Model):
83 if not subclass._meta.abstract:
84 if not self.inclusive and subclass is self.cls:
86 contenttype = ContentType.objects.get_for_model(subclass)
87 contenttype_pks.append(contenttype.pk)
88 handle_subclasses(subclass)
91 handle_subclasses(self.cls)
92 return models.Q(pk__in=contenttype_pks)
98 def paginate(objects, per_page=None, page_number=1):
100 Given a list of objects, return a (``paginator``, ``page``, ``objects``) tuple.
102 :param objects: The list of objects to be paginated.
103 :param per_page: The number of objects per page.
104 :param page_number: The number of the current page.
105 :returns tuple: (``paginator``, ``page``, ``objects``) where ``paginator`` is a :class:`django.core.paginator.Paginator` instance, ``page`` is the result of calling :meth:`Paginator.page` with ``page_number``, and objects is ``page.objects``. Any of the return values which can't be calculated will be returned as ``None``.
109 per_page = int(per_page)
110 except (TypeError, ValueError):
111 # Then either it wasn't set or it was set to an invalid value
112 paginator = page = None
114 # There also shouldn't be pagination if the list is too short. Try count()
115 # first - good chance it's a queryset, where count is more efficient.
117 if objects.count() <= per_page:
118 paginator = page = None
119 except AttributeError:
120 if len(objects) <= per_page:
121 paginator = page = None
124 return paginator, page, objects
128 paginator = Paginator(objects, per_page)
130 page_number = int(page_number)
135 page = paginator.page(page_number)
139 objects = page.object_list
141 return paginator, page, objects