def test_index_on_create_and_update(self): """ Test user index gets updated when a project is created or updated """ cause = Cause.objects.all().order_by('pk').first() skill = Skill.objects.all().order_by('pk').first() self.assertTrue(SearchQuerySet().models(User).all().count() == 0) user = User.objects.create_user(email="*****@*****.**", password="******") user.save() profile = get_profile_model()(user=user) profile.save() self.assertTrue(SearchQuerySet().models(User).filter( skills=skill.pk).count() == 0) profile.skills.add(skill) self.assertTrue(SearchQuerySet().models(User).filter( skills=skill.pk).count() == 1) self.assertTrue(SearchQuerySet().models(User).filter( causes=cause.pk).count() == 0) profile.causes.add(cause) self.assertTrue(SearchQuerySet().models(User).filter( causes=cause.pk).count() == 1) profile.skills.clear() profile.causes.clear() self.assertTrue(SearchQuerySet().models(User).filter( skills=skill.pk).count() == 0) self.assertTrue(SearchQuerySet().models(User).filter( causes=cause.pk).count() == 0)
def get_queryset(self): params = self.request.GET key = 'users-{}'.format(hash(frozenset(params.items()))) cache_ttl = 120 result = cache.get(key) if not result: cause = params.get('cause', None) skill = params.get('skill', None) name = params.get('name', None) queryset = SearchQuerySet().models(User) queryset = filters.by_skills(queryset, skill) queryset = filters.by_causes(queryset, cause) queryset = filters.by_name(queryset, name) result_keys = [q.pk for q in queryset] related_field_name = get_profile_model()._meta.get_field( 'user').related_query_name() result = User.objects.filter( pk__in=result_keys, public=True).prefetch_related( related_field_name + '__skills', related_field_name + '__causes').select_related(related_field_name) cache.set(key, result, cache_ttl) return result
def handle_profile_delete(self, sender, instance, **kwargs): """ Custom handler for user profile delete """ try: self.handle_save(instance.user.__class__, instance.user) # we call save just as well except (get_profile_model().DoesNotExist): pass # just returns, instance already deleted from database
def create_sample_users(): user1 = User(name="user one", email="*****@*****.**", password="******") user1.save() user2 = User(name="user two", email="*****@*****.**", password="******") user2.save() user3 = User(name="user three", email="*****@*****.**", password="******") user3.save() user4 = User(name="user four", email="*****@*****.**", password="******", public=False) user4.save() UserProfile = get_profile_model() profile1 = UserProfile(user=user1, full_name="user one", about="about one") profile1.save() profile1.causes.add(Cause.objects.get(pk=1)) profile1.causes.add(Cause.objects.get(pk=2)) profile1.skills.add(Skill.objects.get(pk=1)) profile1.skills.add(Skill.objects.get(pk=2)) profile2 = UserProfile(user=user2, full_name="user two", about="about two") profile2.save() profile2.causes.add(Cause.objects.get(pk=1)) profile2.causes.add(Cause.objects.get(pk=3)) profile2.skills.add(Skill.objects.get(pk=1)) profile2.skills.add(Skill.objects.get(pk=3)) profile3 = UserProfile(user=user3, full_name="user three", about="about three") profile3.save()
def test_index_on_delete(self): """ Test user index gets updated when a project is created or updated """ self.assertTrue(SearchQuerySet().models(User).all().count() == 0) user = User.objects.create_user(email="*****@*****.**", password="******") user.save() profile = get_profile_model()(user=user) profile.save() self.assertTrue(SearchQuerySet().models(User).all().count() == 1) profile.delete() self.assertTrue(SearchQuerySet().models(User).all().count() == 1) user.delete() self.assertTrue(SearchQuerySet().models(User).all().count() == 0)
def test_ordering_by_relevance(self): """ Assert it's possible to order projects by relevance """ UserProfile = get_profile_model() user = User(name="b", email="*****@*****.**", password="******") user.save() self.client.force_authenticate(user=user) response = self.client.get(reverse("search-projects-list") + "?ordering=-relevance,-created_date", format="json") self.assertEqual(response.status_code, 200) profile = UserProfile(user=user) profile.save() profile.causes.add(Cause.objects.get(pk=1)) profile.skills.add(Skill.objects.get(pk=1)) profile.skills.add(Skill.objects.get(pk=2)) profile.causes.add(Cause.objects.get(pk=3)) response = self.client.get(reverse("search-projects-list") + "?ordering=-relevance,-created_date", format="json") self.assertEqual(str(response.data["results"][0]["name"]), "test project3") self.assertEqual(str(response.data["results"][1]["name"]), "test project") self.assertEqual(str(response.data["results"][2]["name"]), "test project2")
class TiedModelRealtimeSignalProcessor(signals.BaseSignalProcessor): """ TiedModelRealTimeSignalProcessor handles updates to a index tied to a model We need to be able to detect changes to a model a rebuild another index, such as detecting changes to GoogleAddress and updating the index for projects and organizations. """ attach_to = [ (Project, 'handle_save', 'handle_delete'), (Organization, 'handle_save', 'handle_delete'), (User, 'handle_save', 'handle_delete'), (get_profile_model(), 'handle_profile_save', 'handle_profile_delete'), (GoogleAddress, 'handle_address_save', 'handle_address_delete'), (Job, 'handle_job_and_work_save', 'handle_job_and_work_delete'), (Work, 'handle_job_and_work_save', 'handle_job_and_work_delete'), ] m2m = [ Project.causes.through, Project.skills.through, Organization.causes.through ] m2m_user = [ get_profile_model().causes.through, get_profile_model().skills.through ] def setup(self): for item in self.attach_to: models.signals.post_save.connect(getattr(self, item[1]), sender=item[0]) models.signals.post_delete.connect(getattr(self, item[2]), sender=item[0]) for item in self.m2m: models.signals.m2m_changed.connect(self.handle_m2m, sender=item) for item in self.m2m_user: models.signals.m2m_changed.connect(self.handle_m2m_user, sender=item) # never really called def teardown(self): # pragma: no cover for item in self.attach_to: models.signals.post_save.disconnect(getattr(self, item[1]), sender=item[0]) models.signals.post_delete.disconnect(getattr(self, item[2]), sender=item[0]) for item in self.m2m: models.signals.m2m_changed.disconnect(self.handle_m2m, sender=item) for item in self.m2m_user: models.signals.m2m_changed.disconnect(self.handle_m2m_user, sender=item) def handle_address_save(self, sender, instance, **kwargs): """ Custom handler for address save """ objects = self.find_associated_with_address(instance) for obj in objects: self.handle_save(obj.__class__, obj) # this function is never really called on sqlite dbs def handle_address_delete(self, sender, instance, **kwargs): """ Custom handler for address delete """ objects = self.find_associated_with_address(instance) # this is not called as django will delete associated project/address # triggering handle_delete for obj in objects: # pragma: no cover self.handle_delete(obj.__class__, obj) def handle_job_and_work_save(self, sender, instance, **kwargs): """ Custom handler for job and work save """ self.handle_save(instance.project.__class__, instance.project) def handle_job_and_work_delete(self, sender, instance, **kwargs): """ Custom handler for job and work delete """ self.handle_delete(instance.project.__class__, instance.project) def handle_profile_save(self, sender, instance, **kwargs): """ Custom handler for user profile save """ self.handle_save(instance.user.__class__, instance.user) def handle_profile_delete(self, sender, instance, **kwargs): """ Custom handler for user profile delete """ try: self.handle_save(instance.user.__class__, instance.user) # we call save just as well except (get_profile_model().DoesNotExist): pass # just returns, instance already deleted from database def handle_m2m(self, sender, instance, **kwargs): """ Handle many to many relationships """ self.handle_save(instance.__class__, instance) def handle_m2m_user(self, sender, instance, **kwargs): """ Handle many to many relationships for user field """ self.handle_save(instance.user.__class__, instance.user) def find_associated_with_address(self, instance): """ Returns list with projects and organizations associated with given address """ objects = [] objects += list(Project.objects.filter(address=instance)) objects += list(Organization.objects.filter(address=instance)) return objects
def prepare_skills(self, obj): try: if obj.profile: return [skill.id for skill in obj.profile.skills.all()] except get_profile_model().DoesNotExist: # pragma: no cover return []
def prepare_causes(self, obj): try: if obj.profile: return [cause.id for cause in obj.profile.causes.all()] except get_profile_model().DoesNotExist: # pragma: no cover return []