search with additional (preset) search criteria

git-svn-id: svn://svn.cy55.de/Zope3/src/loops/trunk@1615 fd906abe-77d9-0310-91a1-e0d9ade77398
This commit is contained in:
helmutm 2007-03-06 11:01:48 +00:00
parent 3278e2abed
commit d44b721a89
7 changed files with 151 additions and 29 deletions

View file

@ -121,6 +121,9 @@ type manager.
>>> from loops.type import LoopsTypeManager, LoopsType
>>> component.provideAdapter(LoopsTypeManager, (ILoopsObject,), ITypeManager)
>>> from loops.type import TypeConcept
>>> component.provideAdapter(TypeConcept)
>>> from loops.concept import ConceptTypeSourceList
>>> types = ConceptTypeSourceList(cc1)
>>> sorted(t.title for t in types)

View file

@ -225,7 +225,7 @@ class BaseView(GenericView):
return util.KeywordVocabulary(general
+ self.listTypesForSearch(('resource',), ('system', 'hidden'),))
# controllling editing
# controlling editing
@Lazy
def editable(self):

View file

@ -1,4 +1,4 @@
4===================================================================
===================================================================
loops.search - Provide search functionality for the loops framework
===================================================================
@ -118,17 +118,21 @@ purposes fairly primitive) catalog and a resource we can search for:
>>> class DummyCat(object):
... implements(ICatalog)
... def searchResults(self, **criteria):
... result = []
... name = criteria.get('loops_title')
... if name.endswith('*'): name = name[:-1]
... type = criteria.get('loops_type', ('resource',))
... if name:
... if 'concept' in type[0]:
... result = concepts.get(name)
... else:
... result = resources.get(name)
... if result:
... return [result]
... return []
... if name and name.endswith('*'): name = name[:-1]
... typeToken = criteria.get('loops_type', ('resource',))
... if name or typeToken:
... if 'concept' in typeToken[0]:
... if name:
... result = concepts.get(name)
... else:
... tp = concepts[typeToken[0].split(':')[-1]]
... result = list(tp.getChildren())
... else:
... result = resources.get(name)
... if not result: return []
... return type(result) is list and result or [result]
>>> component.provideUtility(DummyCat())
>>> from loops.resource import Resource
@ -200,6 +204,59 @@ of the concepts' titles:
>>> view.listConcepts()
"[['Zope (Topic)', '11']]"
Preset Concept Types on Search Forms
------------------------------------
Often we want to include certain types in our search. We can instruct
the search form to include lines for these types by giving these types
a certain qualifier, via the option attribute of the type interface.
Let's start with a new type, the customer type.
>>> customer = concepts['customer'] = Concept('Customer')
>>> customer.conceptType = typeConcept
>>> custType = ITypeConcept(customer)
>>> custType.options
[]
>>> cust1 = concepts['cust1'] = Concept(u'Zope Corporation')
>>> cust2 = concepts['cust2'] = Concept(u'cyberconcepts')
>>> for c in (cust1, cust2): c.conceptType = customer
>>> from cybertools.typology.interfaces import IType
>>> IType(cust1).qualifiers
('concept',)
>>> searchView = Search(search, TestRequest())
>>> list(searchView.presetSearchTypes)
[]
We can now add a 'search' qualifier to the customer type's options
and thus include the customer type in the preset search types.
>>> custType.options = ('qualifier:search',)
>>> IType(cust1).qualifiers
('concept', 'search')
>>> searchView = Search(search, TestRequest())
>>> list(searchView.presetSearchTypes)
[{'token': 'loops:concept:customer', 'title': 'Customer'}]
>>> searchView.conceptsForType('loops:concept:customer')
[{'token': 'none', 'title': u'not selected'},
{'token': '17', 'title': u'Zope Corporation'},
{'token': '18', 'title': u'cyberconcepts'}]
Let's use this new search option for querying:
>>> form = {'search.4.text_selected': u'17'}
>>> resultsView = SearchResults(page, TestRequest(form=form))
>>> results = list(resultsView.results)
>>> results[0].title
u'Zope Corporation'
Automatic Filtering
-------------------
TODO - more to come...

View file

@ -64,6 +64,20 @@ class Search(BaseView):
self.maxRowNum = n
return n
@Lazy
def presetSearchTypes(self):
""" Return a list of concept type info dictionaries (see BaseView)
that should be displayed on a separate search parameter row.
"""
#return ITypeManager(self.context).listTypes(include=('search',))
return self.listTypesForSearch(include=('search',))
def conceptsForType(self, token):
noSelection = dict(token='none', title=u'not selected')
result = sorted(ConceptQuery(self).query(type=token), key=lambda x: x.title)
return [noSelection] + [dict(title=o.title, token=util.getUidForObject(o))
for o in result]
def initDojo(self):
self.registerDojo()
cm = self.controller.macros
@ -106,18 +120,33 @@ class SearchResults(BaseView):
@Lazy
def results(self):
request = self.request
type = request.get('search.1.text', 'loops:*')
text = request.get('search.2.text')
useTitle = request.get('search.2.title')
useFull = request.get('search.2.full')
conceptType = request.get('search.3.type', 'loops:concept:*')
conceptTitle = request.get('search.3.text')
conceptUid = request.get('search.3.text_selected')
form = self.request.form
type = form.get('search.1.text', 'loops:*')
text = form.get('search.2.text')
useTitle = form.get('search.2.title')
useFull = form.get('search.2.full')
conceptType = form.get('search.3.type', 'loops:concept:*')
conceptTitle = form.get('search.3.text')
conceptUid = form.get('search.3.text_selected')
result = FullQuery(self).query(text=text, type=type,
useTitle=useTitle, useFull=useFull,
conceptTitle=conceptTitle, conceptUid=conceptUid,
conceptType= conceptType)
conceptType=conceptType)
rowNum = 4
while rowNum < 10:
addCriteria = form.get('search.%i.text_selected' % rowNum)
rowNum += 1
if not addCriteria:
break
if addCriteria == 'none':
continue
addSelection = FullQuery(self).query(text=text, type=type,
useTitle=useTitle, useFull=useFull,
conceptUid=addCriteria)
if result:
result = [r for r in result if r in addSelection]
else:
result = addSelection
result = sorted(result, key=lambda x: x.title.lower())
return self.viewIterator(result)

View file

@ -84,6 +84,7 @@
<div metal:define-macro="search_row" id="1.1.row"
tal:define="rowNum item/rowNum;
basicIdPrefix idPrefix;
idPrefix string:$idPrefix.$rowNum;
namePrefix string:search.$rowNum;
param search_param | item/searchParam"
@ -164,8 +165,36 @@
<tr>
<td metal:use-macro="macros/minus"/>
<td colspan="3">
<h3>Search via related concepts</h3>
<h3 i18n:translate="">Search via related concepts</h3>
</td>
<tr tal:repeat="type item/presetSearchTypes">
<tal:preset define="rowNum item/rowNum;
idPrefix string:$basicIdPrefix.$rowNum;
namePrefix string:search.$rowNum;">
<td></td>
<td>
<span i18n:translate="">Type: </span>
<b tal:content="type/title" />
<input type="hidden" name="type" value=""
tal:attributes="name string:$namePrefix.type;
value type/token" />
</td>
<td>
<label for="text"
tal:attributes="for string:$idPrefix.text">Select value:</label>
</td>
<td>
<select name="text_selected"
tal:attributes="name string:$namePrefix.text_selected;
id string:$idPrefix.text;">
<tal:concepts repeat="concept python: item.conceptsForType(type['token'])">
<option tal:attributes="value concept/token"
tal:content="concept/title">Zope Corp</option>
</tal:concepts>
</select>
</td>
</tal:preset>
</tr>
<tr>
<td></td>
<td>

View file

@ -85,6 +85,9 @@ class LoopsType(BaseType):
# check typeProvider for additional qualifiers:
if self.typeProvider in (self.typeConcept, self.predicateType,):
qu.append('system')
addQualifiers = self.optionsDict.get('qualifier')
if addQualifiers:
qu.extend(addQualifiers.split(','))
# how to set a type to 'hidden'?
return tuple(qu)

13
util.py
View file

@ -64,6 +64,13 @@ def nl2br(text):
else: # gracefully handle Mac line endings
return '<br />\n'.join(text.split('\r'))
def toUnicode(text):
if type(text) is not unicode:
return text.decode('UTF-8')
else:
return text
def getObjectForUid(uid):
if uid == '*': # wild card
return '*'
@ -76,9 +83,3 @@ def getUidForObject(obj):
intIds = component.getUtility(IIntIds)
return str(intIds.queryId(obj))
def toUnicode(text):
if type(text) is not unicode:
return text.decode('UTF-8')
else:
return text