예제 #1
0
 def search(self,
            klass,
            sortBy='',
            maxResults=None,
            noSecurity=False,
            **fields):
     '''Searches objects of p_klass. p_sortBy must be the name of an indexed
        field (declared with indexed=True); every param in p_fields must
        take the name of an indexed field and take a possible value of this
        field. You can optionally specify a maximum number of results in
        p_maxResults. If p_noSecurity is specified, you get all objects,
        even if the logged user does not have the permission to view it.'''
     # Find the content type corresponding to p_klass
     tool = self.tool.o
     contentType = tool.getPortalType(klass)
     # Create the Search object
     search = Search('customSearch', sortBy=sortBy, **fields)
     if not maxResults:
         maxResults = 'NO_LIMIT'
         # If I let maxResults=None, only a subset of the results will be
         # returned by method executeResult.
     res = tool.executeQuery(contentType,
                             search=search,
                             maxResults=maxResults,
                             noSecurity=noSecurity)
     return [o.appy() for o in res['objects']]
예제 #2
0
 def count(self, klass, noSecurity=False, **fields):
     '''Identical to m_search above, but returns the number of objects that
        match the search instead of returning the objects themselves. Use
        this method instead of writing len(self.search(...)).'''
     tool = self.tool.o
     contentType = tool.getPortalType(klass)
     search = Search('customSearch', **fields)
     res = tool.executeQuery(contentType, search=search, brainsOnly=True,
                             noSecurity=noSecurity)
     if res: return res._len # It is a LazyMap instance
     else: return 0
예제 #3
0
 def reindex(self, fields=None, unindex=False):
     """Asks a direct object reindexing. In most cases you don't have to
        reindex objects "manually" with this method. When an object is
        modified after some user action has been performed, Appy reindexes
        this object automatically. But if your code modifies other objects,
        Appy may not know that they must be reindexed, too. So use this
        method in those cases.
     """
     if fields:
         # Get names of indexes from field names.
         indexes = [Search.getIndexName(name) for name in fields]
     else:
         indexes = None
     self.o.reindex(indexes=indexes, unindex=unindex)
예제 #4
0
 def reindex(self, fields=None, unindex=False):
     '''Asks a direct object reindexing. In most cases you don't have to
        reindex objects "manually" with this method. When an object is
        modified after some user action has been performed, Appy reindexes
        this object automatically. But if your code modifies other objects,
        Appy may not know that they must be reindexed, too. So use this
        method in those cases.
     '''
     if fields:
         # Get names of indexes from field names.
         indexes = [Search.getIndexName(name) for name in fields]
     else:
         indexes = None
     self.o.reindex(indexes=indexes, unindex=unindex)
예제 #5
0
    def compute(self,
                klass,
                sortBy='',
                maxResults=None,
                context=None,
                expression=None,
                noSecurity=False,
                **fields):
        '''This method, like m_search and m_count above, performs a query on
           objects of p_klass. But in this case, instead of returning a list of
           matching objects (like m_search) or counting elements (like p_count),
           it evaluates, on every matching object, a Python p_expression (which
           may be an expression or a statement), and returns, if needed, a
           result. The result may be initialized through parameter p_context.
           p_expression is evaluated with 2 variables in its context: "obj"
           which is the currently walked object, instance of p_klass, and "ctx",
           which is the context as initialized (or not) by p_context. p_context
           may be used as
              (1) a variable or instance that is updated on every call to
                  produce a result;
              (2) an input variable or instance;
              (3) both.

           The method returns p_context, modified or not by evaluation of
           p_expression on every matching object.

           When you need to perform an action or computation on a lot of
           objects, use this method instead of doing things like
           
                    "for obj in self.search(MyClass,...)"
           '''
        tool = self.tool.o
        contentType = tool.getPortalType(klass)
        search = Search('customSearch', sortBy=sortBy, **fields)
        # Initialize the context variable "ctx"
        ctx = context
        for brain in tool.executeQuery(contentType, search=search, \
                 brainsOnly=True, maxResults=maxResults, noSecurity=noSecurity):
            # Get the Appy object from the brain
            if noSecurity: method = '_unrestrictedGetObject'
            else: method = 'getObject'
            exec 'obj = brain.%s().appy()' % method
            exec expression
        return ctx
예제 #6
0
파일: ToolMixin.py 프로젝트: ajmirsky/appy
    def executeQuery(self, contentType, searchName=None, startNumber=0,
                     search=None, remember=False, brainsOnly=False,
                     maxResults=None, noSecurity=False, sortBy=None,
                     sortOrder='asc', filterKey=None, filterValue=None,
                     refField=None):
        '''Executes a query on a given p_contentType (or several, separated
           with commas) in Plone's portal_catalog. If p_searchName is specified,
           it corresponds to:
             1) a search defined on p_contentType: additional search criteria
                will be added to the query, or;
             2) "_advanced": in this case, additional search criteria will also
                be added to the query, but those criteria come from the session
                (in key "searchCriteria") and were created from search.pt.

           We will retrieve objects from p_startNumber. If p_search is defined,
           it corresponds to a custom Search instance (instead of a predefined
           named search like in p_searchName). If both p_searchName and p_search
           are given, p_search is ignored.

           This method returns a list of objects in the form of the
           __dict__ attribute of an instance of SomeObjects (see in
           appy.gen.utils). We return the __dict__ attribute instead of real
           instance: that way, it can be used in ZPTs without security problems.
           If p_brainsOnly is True, it returns a list of brains instead (can be
           useful for some usages like knowing the number of objects without
           needing to get information about them). If no p_maxResults is
           specified, the method returns maximum
           self.numberOfResultsPerPage. The method returns all objects if
           p_maxResults equals string "NO_LIMIT".

           If p_noSecurity is True, it gets all the objects, even those that the
           currently logged user can't see.

           The result is sorted according to the potential sort key defined in
           the Search instance (Search.sortBy). But if parameter p_sortBy is
           given, it defines or overrides the sort. In this case, p_sortOrder
           gives the order (*asc*ending or *desc*ending).

           If p_filterKey is given, it represents an additional search parameter
           to take into account: the corresponding search value is in
           p_filterValue.

           If p_refField is given, the query is limited to the objects that are
           referenced through it.'''
        # Is there one or several content types ?
        if contentType.find(',') != -1:
            portalTypes = contentType.split(',')
        else:
            portalTypes = contentType
        params = {'portal_type': portalTypes}
        if not brainsOnly: params['batch'] = True
        # Manage additional criteria from a search when relevant
        if searchName:
            # In this case, contentType must contain a single content type.
            appyClass = self.getAppyClass(contentType)
            if searchName != '_advanced':
                search = ClassDescriptor.getSearch(appyClass, searchName)
            else:
                fields = self.REQUEST.SESSION['searchCriteria']
                search = Search('customSearch', **fields)
        if search:
            # Add additional search criteria
            for fieldName, fieldValue in search.fields.iteritems():
                # Management of searches restricted to objects linked through a
                # Ref field: not implemented yet.
                if fieldName == '_ref': continue
                # Make the correspondance between the name of the field and the
                # name of the corresponding index.
                attrName = Search.getIndexName(fieldName)
                # Express the field value in the way needed by the index
                params[attrName] = Search.getSearchValue(fieldName, fieldValue)
            # Add a sort order if specified
            sortKey = search.sortBy
            if sortKey:
                params['sort_on'] = Search.getIndexName(sortKey, usage='sort')
        # Determine or override sort if specified.
        if sortBy:
            params['sort_on'] = Search.getIndexName(sortBy, usage='sort')
            if sortOrder == 'desc': params['sort_order'] = 'reverse'
            else:                   params['sort_order'] = None
        # If defined, add the filter among search parameters.
        if filterKey:
            filterKey = Search.getIndexName(filterKey)
            filterValue = Search.getSearchValue(filterKey, filterValue)
            params[filterKey] = filterValue
            # TODO This value needs to be merged with an existing one if already
            # in params, or, in a first step, we should avoid to display the
            # corresponding filter widget on the screen.
        # Determine what method to call on the portal catalog
        if noSecurity: catalogMethod = 'unrestrictedSearchResults'
        else:          catalogMethod = 'searchResults'
        exec 'brains = self.portal_catalog.%s(**params)' % catalogMethod
        if brainsOnly:
            # Return brains only.
            if not maxResults: return brains
            else: return brains[:maxResults]
        if not maxResults:
            if refField: maxResults = refField.maxPerPage
            else:        maxResults = self.appy().numberOfResultsPerPage
        elif maxResults == 'NO_LIMIT': maxResults = None
        res = SomeObjects(brains, maxResults, startNumber,noSecurity=noSecurity)
        res.brainsToObjects()
        # In some cases (p_remember=True), we need to keep some information
        # about the query results in the current user's session, allowing him
        # to navigate within elements without re-triggering the query every
        # time a page for an element is consulted.
        if remember:
            if not searchName:
                # It is the global search for all objects pf p_contentType
                searchName = contentType
            uids = {}
            i = -1
            for obj in res.objects:
                i += 1
                uids[startNumber+i] = obj.UID()
            self.REQUEST.SESSION['search_%s' % searchName] = uids
        return res.__dict__
예제 #7
0
    def executeQuery(self,
                     className,
                     searchName=None,
                     startNumber=0,
                     search=None,
                     remember=False,
                     brainsOnly=False,
                     maxResults=None,
                     noSecurity=False,
                     sortBy=None,
                     sortOrder='asc',
                     filterKey=None,
                     filterValue=None,
                     refObject=None,
                     refField=None):
        '''Executes a query on instances of a given p_className (or several,
           separated with commas) in the catalog. If p_searchName is specified,
           it corresponds to:
             1) a search defined on p_className: additional search criteria
                will be added to the query, or;
             2) "_advanced": in this case, additional search criteria will also
                be added to the query, but those criteria come from the session
                (in key "searchCriteria") and were created from search.pt.

           We will retrieve objects from p_startNumber. If p_search is defined,
           it corresponds to a custom Search instance (instead of a predefined
           named search like in p_searchName). If both p_searchName and p_search
           are given, p_search is ignored.

           This method returns a list of objects in the form of the
           __dict__ attribute of an instance of SomeObjects (see in
           appy.gen.utils). We return the __dict__ attribute instead of real
           instance: that way, it can be used in ZPTs without security problems.
           If p_brainsOnly is True, it returns a list of brains instead (can be
           useful for some usages like knowing the number of objects without
           needing to get information about them). If no p_maxResults is
           specified, the method returns maximum
           self.numberOfResultsPerPage. The method returns all objects if
           p_maxResults equals string "NO_LIMIT".

           If p_noSecurity is True, it gets all the objects, even those that the
           currently logged user can't see.

           The result is sorted according to the potential sort key defined in
           the Search instance (Search.sortBy). But if parameter p_sortBy is
           given, it defines or overrides the sort. In this case, p_sortOrder
           gives the order (*asc*ending or *desc*ending).

           If p_filterKey is given, it represents an additional search parameter
           to take into account: the corresponding search value is in
           p_filterValue.

           If p_refObject and p_refField are given, the query is limited to the
           objects that are referenced from p_refObject through p_refField.'''
        # Is there one or several content types ?
        if className.find(',') != -1:
            classNames = className.split(',')
        else:
            classNames = className
        params = {'ClassName': classNames}
        if not brainsOnly: params['batch'] = True
        # Manage additional criteria from a search when relevant
        if searchName:
            # In this case, className must contain a single content type.
            appyClass = self.getAppyClass(className)
            if searchName != '_advanced':
                search = ClassDescriptor.getSearch(appyClass, searchName)
            else:
                fields = self.REQUEST.SESSION['searchCriteria']
                search = Search('customSearch', **fields)
        if search:
            # Add additional search criteria
            for fieldName, fieldValue in search.fields.iteritems():
                # Management of searches restricted to objects linked through a
                # Ref field: not implemented yet.
                if fieldName == '_ref': continue
                # Make the correspondance between the name of the field and the
                # name of the corresponding index.
                attrName = Search.getIndexName(fieldName)
                # Express the field value in the way needed by the index
                params[attrName] = Search.getSearchValue(fieldName, fieldValue)
            # Add a sort order if specified
            sortKey = search.sortBy
            if sortKey:
                params['sort_on'] = Search.getIndexName(sortKey, usage='sort')
        # Determine or override sort if specified.
        if sortBy:
            params['sort_on'] = Search.getIndexName(sortBy, usage='sort')
            if sortOrder == 'desc': params['sort_order'] = 'reverse'
            else: params['sort_order'] = None
        # If defined, add the filter among search parameters.
        if filterKey:
            filterKey = Search.getIndexName(filterKey)
            filterValue = Search.getSearchValue(filterKey, filterValue)
            params[filterKey] = filterValue
            # TODO This value needs to be merged with an existing one if already
            # in params, or, in a first step, we should avoid to display the
            # corresponding filter widget on the screen.
        if refObject:
            refField = refObject.getAppyType(refField)
            params['UID'] = getattr(refObject, refField.name).data
        # Use index "Allowed" if noSecurity is False
        if not noSecurity: params['Allowed'] = self.getAllowedValue()
        brains = self.getPath("/catalog")(**params)
        if brainsOnly:
            # Return brains only.
            if not maxResults: return brains
            else: return brains[:maxResults]
        if not maxResults:
            if refField: maxResults = refField.maxPerPage
            else: maxResults = self.appy().numberOfResultsPerPage
        elif maxResults == 'NO_LIMIT': maxResults = None
        res = SomeObjects(brains,
                          maxResults,
                          startNumber,
                          noSecurity=noSecurity)
        res.brainsToObjects()
        # In some cases (p_remember=True), we need to keep some information
        # about the query results in the current user's session, allowing him
        # to navigate within elements without re-triggering the query every
        # time a page for an element is consulted.
        if remember:
            if not searchName:
                # It is the global search for all objects pf p_className
                searchName = className
            uids = {}
            i = -1
            for obj in res.objects:
                i += 1
                uids[startNumber + i] = obj.UID()
            self.REQUEST.SESSION['search_%s' % searchName] = uids
        return res.__dict__