def test_q_serializer_03(self): "AND" self.login() self._create_contacts() q = Q(last_name=self.adrian.last_name) & Q(first_name__startswith='Ad') self._assertQIsOK(q, [self.adrian]) str_q = QSerializer().dumps(q) self._assertQEqual(FakeContact, q, QSerializer().loads(str_q))
def test_q_serializer_06(self): "Dates" self.login() self._create_contacts() q = Q(birthday__gt=date(year=2000, month=1, day=1)) self._assertQIsOK(q, [self.adrian]) str_q = QSerializer().dumps(q) self._assertQEqual(FakeContact, q, QSerializer().loads(str_q))
def test_q_serializer_04(self): "OR" self.login() self._create_contacts() q = Q(first_name=self.adrian.first_name) | Q( first_name__startswith='Ric') self._assertQIsOK(q, [self.richard, self.adrian]) str_q = QSerializer().dumps(q) self._assertQEqual(FakeContact, q, QSerializer().loads(str_q))
def test_q_serializer_05(self): "NOT" self.login() self._create_contacts() q = ~Q(first_name=self.adrian.first_name) & Q( last_name=self.adrian.last_name) self._assertQIsOK(q, [self.marianne]) str_q = QSerializer().dumps(q) self._assertQEqual(FakeContact, q, QSerializer().loads(str_q))
def test_q_serializer_10(self): "Value is a model instance" self.login() self._create_contacts() q = Q(position=self.baker) self._assertQIsOK(q, [self.marianne]) qsr = QSerializer() str_q = qsr.dumps(q) self._assertQEqual(FakeContact, q, qsr.loads(str_q))
def test_q_serializer_11(self): "__in=[...] + model instance" self.login() self._create_contacts() q = Q(position__in=[self.boxer, self.fighter]) self._assertQIsOK(q, [self.richard, self.adrian]) qsr = QSerializer() str_q = qsr.dumps(q) self._assertQEqual(FakeContact, q, qsr.loads(str_q))
def test_q_serializer_01(self): self.login() self._create_contacts() q1 = Q(last_name=self.adrian.last_name) self._assertQIsOK(q1, [self.adrian, self.marianne]) str_q = QSerializer().dumps(q1) self.assertIsInstance(str_q, str) q2 = QSerializer().loads(str_q) self.assertIsInstance(q2, Q) self._assertQEqual(FakeContact, q1, q2)
def test_q_serializer_08(self): "Range." user = self.create_user() create_orga = partial(FakeOrganisation.objects.create, user=user) create_orga(name='Vallée des rois', capital=15000) o2 = create_orga(name='Paxtown', capital=5000) create_orga(name='Zotis incorporation', capital=200) q = Q(capital__range=[1000, 10000]) self._assertQIsOK(q, [o2]) str_q = QSerializer().dumps(q) self._assertQEqual(FakeOrganisation, q, QSerializer().loads(str_q))
def register_in_session(self, request): serialized = {**self.__dict__} if self.extra_q is not None: serialized['extra_q'] = QSerializer().dumps(self.extra_q) request.session[self.url] = serialized
def test_q_serializer_07(self): "Datetimes" user = self.create_user() create_dt = partial(self.create_datetime, year=2015, month=2, minute=0) create_act = partial(FakeActivity.objects.create, user=user, type=self._create_activity_type()) acts = [ create_act(title='T#1', start=create_dt(day=19, hour=8)), create_act(title='T#2', start=create_dt(day=19, hour=12)), ] q = Q(start__lt=create_dt(day=19, hour=9)) self._assertQIsOK(q, [acts[0]]) str_q = QSerializer().dumps(q) self._assertQEqual(FakeActivity, q, QSerializer().loads(str_q))
def test_q_serializer_02(self): "2 conditions + operator" user = self.create_user() create_contact = partial(FakeContact.objects.create, user=user) adrian = create_contact(first_name='Adrian', last_name='Velbà') create_contact(first_name='Marianne', last_name='Velbà') create_contact(first_name='Richard', last_name='Aldana') q1 = Q(last_name=adrian.last_name, first_name__startswith='Ad') self._assertQIsOK(q1, [adrian]) str_q = QSerializer().dumps(q1) self.assertIsInstance(str_q, str) q2 = QSerializer().loads(str_q) self.assertIsInstance(q2, Q) self._assertQEqual(FakeContact, q1, q2)
def detailview_display(self, context): folder_id = context['object'].id q_dict = {'linked_folder': folder_id} return self._render( self.get_template_context( context, Document.objects.filter(**q_dict), # Document.objects.filter(is_deleted=False, **q_dict), TODO: problem deleted docs avoid folder deletion... q_filter=QSerializer().dumps(Q(**q_dict)), ))
def test_extra_filter(self): self.login() self._build_hf_n_contacts() response = self.assertGET200( self._build_contact_dl_url( extra_q=QSerializer().dumps(Q(last_name='Wong'))), ) result = [force_str(line) for line in response.content.splitlines()] self.assertEqual(2, len(result)) self.assertEqual('"","Wong","Edward","","is a girl"', result[1])
def __call__(self, q_filter: Optional[dict] = None) -> Optional[str]: fmt = self._fmt if not fmt: return None final_q = self._common_q & Q(**q_filter) if q_filter else self._common_q return fmt.format( QSerializer().dumps(final_q) if final_q else '' )
def get_state(cls, request, url=None) -> Optional['ListViewState']: lvs = None data = request.session.get(url or request.path) if data is not None: lvs = cls() for k, v in data.items(): setattr(lvs, k, v) if lvs.extra_q is not None: lvs.extra_q = QSerializer().loads(lvs.extra_q) return lvs
def test_q_serializer_12(self): "__in=QuerySet -> error" self.login() self._create_contacts() q = Q(position__in=FakePosition.objects.filter(title__startswith='B')) self._assertQIsOK(q, [self.richard, self.marianne]) qsr = QSerializer() self.assertRaises(SerializationError, qsr.dumps, q) q = Q(position__in=FakePosition.objects.filter( title__startswith='B').values_list('id', flat=True), ) self._assertQIsOK(q, [self.richard, self.marianne]) self.assertRaises(SerializationError, qsr.dumps, q)
def _build_extrafilter(arguments, extra_filter=None): json_q_filter = arguments.get('q_filter') q_filter = Q() serializer = QSerializer() # TODO: better validation of q_filter ? (corresponding EntityCell allowed + searchable ?) # - limit the max depth of sub-fields chain ? # - do no allow all fields ? if json_q_filter: try: q_filter = serializer.loads(json_q_filter) except: try: q_filter = get_q_from_dict( _clean_value(json_q_filter, json_load, {})) except: raise else: warnings.warn( 'Old format for "q_filter" is deprecated is used : {}'. format(json_q_filter), DeprecationWarning) return (serializer.dumps(q_filter), q_filter if extra_filter is None else q_filter & extra_filter)
def build_q_filter(self, q_filter): extra_filter = False basic_q = Q(mime_type__name__startswith=MIMETYPE_PREFIX_IMG) if q_filter is not None: if isinstance(q_filter, dict): q_filter = Q(**q_filter) # NB: Q has not method __equal__(), so we compare serialized Q objects. serialize = QSerializer().serialize extra_filter = (serialize(q_filter) != serialize(basic_q)) final_q = (basic_q & q_filter) if extra_filter else q_filter else: final_q = basic_q return final_q, extra_filter
def get_state(cls, request, url=None): lvs = None data = request.session.get(url or request.path) if data is not None: # # lvs = object.__new__(ListViewState) # NB: causes problem on attribute change (renaming...) # lvs = ListViewState() lvs = cls() for k, v in data.items(): setattr(lvs, k, v) if lvs.extra_q is not None: lvs.extra_q = QSerializer().loads(lvs.extra_q) return lvs
def get_requested_q(self): arg_name = self.requested_q_arg json_q_filter = self.arguments.get(arg_name) # TODO: better validation (eg: corresponding EntityCell allowed + searchable ?) ? # - limit the max depth of sub-fields chain ? # - do no allow all fields ? if json_q_filter: try: return QSerializer().loads(json_q_filter) except JSONDecodeError: logger.exception( 'Error when decoding the argument "%s": %s', arg_name, json_q_filter, ) return Q()
def __call__(self, q_filter=None): fmt = self._fmt return fmt.format(QSerializer().dumps(Q(**q_filter)) if q_filter is not None else '') if fmt else None
def test_report_graph_fetcher01(self): "Contact-user." user = self.login() report = Report.objects.create(user=user, name='Fetcher Test', ct=Organisation) graph = ReportGraph.objects.create( user=user, name='Field Test', linked_report=report, # abscissa_cell_value='creation_date', abscissa_type=RGT_YEAR, abscissa_cell_value='creation_date', abscissa_type=ReportGraph.Group.YEAR, # ordinate_type=RGA_COUNT, ordinate_type=ReportGraph.Aggregator.COUNT, ) url = reverse('reports__create_instance_brick', args=(graph.id, )) response = self.assertGET200(url) with self.assertNoException(): choices = [ *response.context['form'].fields['fetcher'].widget.choices ] vname = _('Belows to the Contact/User') self.assertInChoices( value=f'{RGF_OWNED}|', label=vname, choices=choices, ) self.assertNoFormError( self.client.post(url, data={'fetcher': RGF_OWNED})) ibci = self.get_object_or_fail(InstanceBrickConfigItem, entity=graph.id) self.assertEqual('instanceblock_reports-graph', ibci.brick_class_id) self.assertEqual(RGF_OWNED, ibci.get_extra_data('type')) self.assertIsNone(ibci.get_extra_data('value')) brick = ReportGraphBrick(ibci) self.assertEqual( f'{graph.name} - {vname}', brick.verbose_name, ) self.assertListEqual([Contact], brick.target_ctypes) # Display on detail-view create_orga = partial(Organisation.objects.create, user=user) create_orga(name='Orga#1', creation_date=date(year=2015, month=1, day=1)) create_orga(name='Orga#2', creation_date=date(year=2015, month=2, day=2)) create_orga( name='Orga#3', creation_date=date(year=2015, month=3, day=3), user=self.other_user, ) create_orga(name='Orga#4', creation_date=date(year=2016, month=4, day=4)) fetcher = brick.fetcher self.assertIsInstance(fetcher, OwnedGraphFetcher) self.assertIsNone(fetcher.error) self.assertEqual(vname, fetcher.verbose_name) x, y = fetcher.fetch_4_entity(entity=user.linked_contact, user=user) self.assertListEqual(['2015', '2016'], x) qfilter_serializer = QSerializer() lv_url = reverse('persons__list_organisations') def build_url(year): return '{}?q_filter={}'.format( lv_url, qfilter_serializer.dumps( Q(user=user.id) & Q(creation_date__year=year)), ) self.assertListEqual([[2, build_url(2015)], [1, build_url(2016)]], y) # --- ibci = fetcher.create_brick_config_item() BrickDetailviewLocation.objects.create_if_needed( brick=ibci.brick_id, order=1, zone=BrickDetailviewLocation.RIGHT, model=Contact, ) contact = user.linked_contact response = self.assertGET200(contact.get_absolute_url()) dom = self.get_html_tree(response.content) brick_node = self.get_brick_node(dom, brick_id=ibci.brick_id) self.assertBrickHasNotClass(brick_node, 'is-empty') volatile_span = brick_node.find( './/span[@class="graph-volatile-value"]') self.assertIsNotNone(volatile_span) self.assertEqual(vname, volatile_span.text) # -- self.assertGET200( reverse('reports__fetch_graph_from_brick', args=(ibci.id, contact.id)))
def list_view_content( request, model, hf_pk='', extra_dict=None, template='creme_core/generics/list_entities.html', show_actions=True, extra_q=None, mode=MODE_MULTIPLE_SELECTION, post_process=None, content_template='creme_core/frags/list_view_content.html', lv_state_id=None): """ Generic list_view wrapper / generator Accepts only CremeEntity model and subclasses. @param post_process: Function that takes the template context and the request as parameters (so you can modify the context). """ assert issubclass( model, CremeEntity), '{} is not a subclass of CremeEntity'.format(model) PAGE_SIZES = settings.PAGE_SIZES is_GET = request.method == 'GET' arguments = request.GET if is_GET else request.POST lv_state_id = lv_state_id or request.path current_lvs = ListViewState.get_or_create_state(request, url=lv_state_id) rows = _build_rowscount(arguments, current_lvs) transient = is_GET or (arguments.get('transient') in {'1', 'true'}) ct = ContentType.objects.get_for_model(model) user = request.user header_filters = HeaderFilterList(ct, user) hf = current_lvs.set_headerfilter(header_filters, arguments.get('hfilter', -1), hf_pk) cells = hf.cells if show_actions: # cells.insert(0, EntityCellActions(model=model)) cells.insert( 0, EntityCellActions(model=model, actions_registry=actions_registry)) if arguments.get('search', '') == 'clear': current_lvs.clear_research() else: current_lvs.handle_research(arguments, cells, merge=transient) entity_filters = EntityFilterList(ct, user) efilter = _select_entityfilter(arguments, entity_filters, current_lvs.entity_filter_id) current_lvs.entity_filter_id = efilter.id if efilter else None json_q_filter, extra_filter = _build_extrafilter(arguments, extra_q) entities, count = _build_entity_queryset(user, model, current_lvs, extra_filter, efilter, hf) fast_mode = (count >= settings.FAST_QUERY_MODE_THRESHOLD) ordering = current_lvs.set_sort( model, cells, cell_key=arguments.get('sort_field', current_lvs.sort_field), order=arguments.get('sort_order', current_lvs.sort_order), fast_mode=fast_mode, ) entities_page = _build_entities_page( arguments, current_lvs, entities.order_by(*ordering), size=rows, count=count, ordering=ordering, fast_mode=fast_mode, ) if not transient: current_lvs.register_in_session(request) template_dict = { 'model': model, 'list_title': _('List of {models}').format(models=model._meta.verbose_name_plural), 'sub_title': '', 'header_filters': header_filters, 'entity_filters': entity_filters, 'entities': entities_page, 'list_view_state': current_lvs, 'content_type': ct, 'content_type_id': ct.id, 'search': len(current_lvs.research) > 0, 'content_template': content_template, 'page_sizes': PAGE_SIZES, 'o2m': (mode == MODE_SINGLE_SELECTION), 'add_url': model.get_create_absolute_url(), 'extra_bt_templates': None, # TODO: () instead ???, 'show_actions': show_actions, 'extra_filter': QSerializer().dumps(extra_filter), 'q_filter': json_q_filter, 'research_cellkeys': {cell_key for cell_key, _value in current_lvs.research}, 'is_popup_view': False, } if extra_dict: template_dict.update(extra_dict) if request.is_ajax(): template = template_dict['content_template'] if post_process: post_process(template_dict, request) # Optimisation time !! hf.populate_entities(entities_page.object_list, user) return template, template_dict