text: from django.db import models, transaction
  from django.urls import reverse
  
  from apps.group.caches import cache_bust, make_key, make_key_many
  from apps.group.exceptions import GroupError, GroupMembershipError
  from apps.group.signals import group_created
  
  # Create your managers here.
  
  class GroupManager(models.Manager):
      """
      Group model manager.
      """
  
      def create_new_group(self, user, name, access='PRIVATE'):
          """
          Create a new group defined by its name and access type.
          Group access is set as private ('PRIV') by default.
          When created send signal to set administrator permit to the group creator.
          """
          if not self.filter(name=name).exists():
              group, created = self.get_or_create(name=name, access=access)
              if created:
                  response = group_created.send(sender=self.model.__class__, user=user, group=group)
                  receiver, administrator = response[0]
                  cache_bust([('groups', user.pk)])
                  return group, administrator
              return False
          else:
              raise GroupError('Already exists a group with name \'{name}\''.format(name=name))
  
      def get_user_groups(self, user):
          """
          Return all group memberships for one user.
          """
          key = make_key('groups', user.pk)
          groups = cache.get(key)
          if groups is None:
              groups = self.filter(members=user).order_by('-date_joined')
              cache.set(key, groups)
          return groups
  
      def count_user_groups(self, user):
          """
          Count all groups the user belongs to.
          """
          count = self.get_user_groups(user).count()
          return count
  
  
  class GroupMembershipManager(models.Manager):
      """
      GroupMembership model manager.
      """
  
      def add_membership(self, user, group, permit='PART'):
          """
          New group membership.
          If the group is public the user joins it automatically, whereas
          if it is private the user must be admitted by the group administrator
          via requeset approval.
          """
          if self.is_member(user, group):
              raise GroupMembershipError('User is already member of this group.')
          if group.access == 'PUBLIC':
              membership, created = self.get_or_create(member=user, group=group, permit=permit)
              if created:
                  membership_created.send(sender=self.model)
                  cache_bust([('groups', user.pk), ('memberships', group.pk)])
                  return reverse('group:group_detail', kwargs={'group_id': group.pk})
              else:
                  raise GroupMembershipError('Error creating group membership.')
          elif group.access == 'PRIVATE':
              return reverse('group:membership_request', kwargs={'group_id': group.pk})
          else:
              raise GroupError('Group access has to be either PUBLIC or PRIVATE.')
  
      def set_group_admin(self, user, group, permit='ADMIN'):
          """
          Set the creator of a group as administrator.
          There can only be one administrator in each group.
          """
          if isinstance(group, self.model.__class__):
              if not self.filter(group=group, permit=permit).exists():
                  administrator = self.create(member=user, group=group, permit=permit)
                  return administrator
              else:
                  raise GroupError('The group already has one administrator.')
          return False
  
      def get_group_admin(self, group):
          """
          Return group administrator.
          """
          if isinstance(group, self.model.__class__):
              try:
                  membership = self.selected_related('member').get(group=group, permit='ADMIN')
                  administrator = membership.member
                  return administrator
              except self.model.DoesNotExist:
                  raise GroupError('Group has no administrator.')
          return False
  
      def memberships(self, group):
          """
          Return all group memberships and members.
          """
          keys = make_key_many([('memberships', group.pk), ('members', group.pk)])
          memberships = cache.get(keys.get('memberships'))
          members = cache.get(keys.get('members'))
          if memberships is None:
              memberships = self.selected_related('member').filter(group=group)
              cache.set(keys.get('memberships'), memberships)
          if members is None:
              members = [membership.member for membership in memberships]
              cache.set(keys.get('members'), members)
          return memberships, members
  
      def count_group_members(self, group):
          """
          Count all members belonging to one group.
          """
          memberships, members = self.memberships(group)
          count = memberships.count()
          return count
  
      def is_member(self, user, group):
          """
          Check if user is a group member.
          """
          if user.is_authenticated() and isinstance(group, self.model.__class__):
              key = make_key('members', group.pk)
              members = cache.get(key)
              if members is not None and user in members:
                  return True
              else:
                  try:
                      member = self.get(member=user, group=group)
                      return True
                  except self.model.DoesNotExist:
                      return False
          return False
  
  
  class GroupMembershipRequestManager(models.Manager):
      """
      GroupMembership model manager.
      """
  
      def send_membership_request(self, from_user, to_admin, group, message):
          """
          Send membership request to private group administrator to join.
          After trying to join a private group the user is redirected to
          membership request form if the group is private once checked the
          user is not already a group member.
          The membership request form saving executes this method.
          """
          if user.is_authenticated():
              request, created = self.get_or_create(from_user=from_user, to_administrator=to_admin, group=group, message=message)
              if not created:
                  raise SendRequestError('Membership request for this group has already been sent.')
              cache_bust([('requests', to_admin.pk), ('sent_requests', from_user.pk)])
              membership_request_sent.send(sender=self.model.__class__)
              return request
          return False
  
      def requests(self, user):
          """
          Return all membership requests.
          """
          key = make_key('requests', user.pk)
          requests = cache.get(key)
          if requests is None:
              requests = self.filter(from_user=user)
              cache.set(key, requests)
          return requests
  
      def request_count(self, user):
          """
          Return all membership requests count.
          """
          count = self.requests(user).count()
          return count
  
      def rejected_requests(self, user):
          """
          Return all rejected membership requests.
          """
          key = make_key('rejected_requests', user.pk)
          rejected_requests = cache.get(key)
          if rejected_requests is None:
              rejected_requests = self.filter(Q(rejected__isnull=False) | Q(rejected=True), from_user=user)
              cache.set(key, rejected_requests)
          return rejected_requests
  
      def rejected_requests_count(self, user):
          """
          Return all rejected membership requests count.
          """
          count = self.rejected_requests(user).count()
          return count
  
      def unrejected_requests(self, user):
          """
          Return all unrejected membership requests.
          """
          key = make_key('unrejected_requests', user.pk)
          unrejected_requests = cache.get(key)
          if unrejected_requests is None:
              unrejected_requests = self.filter(Q(rejected__isnull=True) | Q(rejected=False), from_user=user)
              cache.set(key, unrejected_requests)
          return unrejected_requests
  
      def unrejected_requests_count(self, user):
          """
          Return all unrejected membership requests count.
          """
          count = self.unrejected_requests(user).count()
          return count
  
      def viewed_requests(self, user):
          """
          Return all viewed membership requests.
          """
          key = make_key('viewed_requests', user.pk)
          viewed_requests = cache.get(key)
          if viewed_requests is None:
              viewed_requests = self.filter(Q(viewed__isnull=False) | Q(viewed=True), from_user=user)
              cache.set(key, viewed_requests)
          return viewed_requests
  
      def viewed_request_count(self, user):
          """
          Return all viewed membership requests count.
          """
          count = self.viewed_requests(user).count()
          return count
  
      def unviewed_requests(self, user):
          """
          Return all unviewed membership requests.
          """
          key = make_key('unviewed_requests', user.pk)
          unviewed_requests = cache.get(key)
          if unviewed_requests is None:
              unviewed_requests = self.filter(Q(viewed__isnull=True) | Q(viewed=False), from_user=user)
              cache.set(key, unviewed_requests)
          return unviewed_requests
  
      def unviewed_request_count(self, user):
          """
          Return all unviewed membership requests count.
          """
          count = self.unviewed_requests(user).count()
          return count
  