Commits

magicrebirth committed 5e739bc

Fixed bugs with the caching mechanims; other minor changes

  • Participants
  • Parent commits 0d3ee8e

Comments (0)

Files changed (22)

File demoproject/apps/djfacet/_readme.txt

 DJFACET: A faceted browser search engine built on top of Django. 
-VERSION: 0.9.5
 -----------------------------------------
 Source code available on BitBucket: https://bitbucket.org/magicrebirth/djfacet/
-Discussion and more info on gCode: http://code.google.com/p/djfacet/ 
 Author: michele pasin http://www.michelepasin.org/software/djfacet/
 -----------------------------------------
+VERSION: 0.9.9.5

File demoproject/apps/djfacet/cache_manager.py

 
 
 
-
-
-
-##################
-#  
-#  a couple of utils for caching html pages in the DB 
-#
-##################
-
-
-def cacheHTMLpage(text, pagename, extraargs="", ENFORCE=False):
-	""" Caches the contents of a page (eg splash page) in the DB
-
-	"""
-	c = CachedHtmlPage.objects.filter(page=pagename, args=extraargs)
-	if c and ENFORCE:
-		c[0].contents = text
-		c[0].save()
-		djfacetlog("CACHEHTMLPAGE: The page [%s, %s] has been re-cached." % (pagename, extraargs))
-	elif c and not ENFORCE:
-		djfacetlog("CACHEHTMLPAGE: The page [%s, %s] is already cached. Use ENFORCE to recache it." % (pagename, extraargs))
-	else:
-		c = CachedHtmlPage(page=pagename, args=extraargs, contents=text )
-		c.save()
-		djfacetlog("CACHEHTMLPAGE: The page [%s, %s] has been cached for the first time." % (pagename, extraargs), True)
-
-
-def get_cachedHTMLpage(pagename, extraargs=""):
-	""" REtrieves the cached contents of a page (eg splash page) from the DB
-
-	"""
-	c = CachedHtmlPage.objects.filter(page=pagename, args=extraargs)
-	if c:
-		djfacetlog("GET_CACHEDHTMLPAGE: The page [%s, %s] has been retrieved from DB" % (pagename, extraargs), True)
-		return c[0].contents
-	else:
-		djfacetlog("GET_CACHEDHTMLPAGE: The page [%s, %s] wasn't found in the cache." % (pagename, extraargs))
-		return None
-
-
-def delete_cachedHTMLpage(pagename, extraargs=""):
-	""" Deletes the cached contents of a page (eg splash page) from the DB
-
-	"""
-	c = CachedHtmlPage.objects.filter(page=pagename, args=extraargs)
-	if c:
-		c.delete()
-		djfacetlog("""DELETE_CACHEDHTMLPAGE: The page [%s, %s] has been deleted from DB\nIt will be automatically 
-		re-cached the next time you set DJF_SPLASHPAGE_CACHE = True""" % (pagename, extraargs), True)
-	else:
-		djfacetlog("DELETE_CACHEDHTMLPAGE: the page [%s, %s] was not found in the cache" % (pagename, extraargs), True)
-		return None
-
-
-
-
-
-
-
-
 ##################
 #  
 #  DbCache : abstracts the common operations needed for handling queries and storage of DB-cached facet-values
 class DbCache(object):
 	""" The manager contains information about .... 
 		=+=
-		...
+		For now, it is normally instantiated without queryargs, eg:
+		cacheDB = DbCache(FM_INSTANCE)
+		
 		=+=
 	
 	"""
 			obj.save()
 
 
-	def transformQueryargs(self, queryargs):
-		"""
-		Creates a deterministic representation of queryArgs, so that they can be stored in the DB as field of  
-		the CachedFacetQuery object
-		==> returns: '123_12345_562719192'
-		QueryArgs: list of facetvalues 
 
-		This is useful for caching second-level queries.
-
-		"""
-
-		queryargs_Ids = [x.id for x in queryargs]
-		return "_".join([str(x) for x in sorted(queryargs_Ids)])  # we sort them always by number
-
-
-
-
-	def _cacheOneFacetValue(self, facet, resulttype,  ENFORCE = False, values_to_cache = None):
+	def _cacheOneFacet(self, facet, resulttype,  ENFORCE = False, values_to_cache = None):
 		"""
 		FACET:	the facet within which we need to find the facet-values to cache
 		RESULTTYPE: the result the facet-values to cache (and facet) are related to
 		VALUES_TO_CACHE:  if we already pass the values to be cached, these are just saved..
 		"""
 	
-		obj_old, obj_new = None, None
-		queryargs = self.queryargs	# which is a list of lists
+		cached_fquery_old, cached_fquery_new = None, None
+		queryargs = self.queryargs	
 
 		# calculate queryargs transformation, get the CachedQueryArgs instance and pass it
 		if queryargs: 
-			exploded_queryargs = self.transformQueryargs(queryargs)
+			exploded_queryargs = self.explodeQueryargs(queryargs)
 			djfacetlog("cacheDB>> QUERYARGS found and transformed: **%s**"	% str(temp))
 		else:
 			exploded_queryargs = None
 
 		# get the CachedFacetQuery instance
 		try:
-			obj_old = CachedFacetQuery.objects.get(facet=facet.uniquename, resulttype=resulttype['uniquename'], queryargs=exploded_queryargs)
+			cached_fquery_old = CachedFacetQuery.objects.get(facet=facet.uniquename, resulttype=resulttype['uniquename'], queryargs=exploded_queryargs)
 		except:
-			obj_new = CachedFacetQuery(facet=facet.uniquename, resulttype=resulttype['uniquename'], queryargs=exploded_queryargs)
+			cached_fquery_new = CachedFacetQuery(facet=facet.uniquename, resulttype=resulttype['uniquename'], queryargs=exploded_queryargs)
 		
 		# ___________
 		# DELETE previously cached stuff, if necessary
 		# ___________
-		if obj_old and ENFORCE:
+		if cached_fquery_old and ENFORCE:
 			djfacetlog("cacheDB>>\n------\nENFORCE = true ===> emptying previously saved values......\n------")
 			self._emptyCacheForFacetQuery(facet, resulttype, exploded_queryargs)
 			# delete the previous contents first
 		# ___________
 		if values_to_cache or values_to_cache == []:  # also if it's an empty list	 
 			djfacetlog("cacheDB>>\n****\nCACHING ON THE FLY == Facet= *%s*	 Result= *%s*	Queryargs= *%s*\n****"	% (facet.uniquename, resulttype['uniquename'], str(exploded_queryargs)))		
-			obj = obj_new or obj_old	
-			obj.tot_ids = len(self.activeIDs)
-			obj.save()
-			self._inner_cache(obj, values_to_cache, facet, resulttype)
+			cached_fquery = cached_fquery_new or cached_fquery_old	
+			cached_fquery.tot_ids = len(self.activeIDs)
+			cached_fquery.save()
+			self._inner_cache(cached_fquery, values_to_cache, facet, resulttype)
 			return True
 
 		# ___________
 		# CASE 2: caching programmatically from console 
-		# in this case we found a new obj to cache, or an old one with either ENFORCE_UPDATE or DELETE set to True.. 
+		# in this case we found a new cached_fquery to cache, or an old one with either ENFORCE_UPDATE or DELETE set to True.. 
 		# ___________
-		if obj_new or (obj_old and ENFORCE):
+		if cached_fquery_new or (cached_fquery_old and ENFORCE):
 			# update the activeIDs as needed, instantiate the QueryHelper obj and save the instance
 			djfacetlog("cacheDB>>\n****\nCACHING	 == Facet= *%s*	 Result= *%s*	Queryargs= *%s*\n****"	% (facet.uniquename, resulttype['uniquename'], str(exploded_queryargs)))		
-			obj = obj_new or obj_old	
+			cached_fquery = cached_fquery_new or cached_fquery_old	
 
 			# ___________ for the moment we're handling only queries with NO queryargs (= top level)
 			
 			djfacetlog("cacheDB>> Applying algorithm for top-level items (no QUERYARGS)")
-			obj.tot_ids = self.fm.get_resulttype_count(resulttype['uniquename'])
+			cached_fquery.tot_ids = self.fm.get_resulttype_count(resulttype['uniquename'])
 			queryHelper= QueryHelper(resulttype['uniquename'], facet, resulttype['all_IDs'])
-			obj.save()
+			cached_fquery.save()
 
 			values_to_cache = queryHelper.calculate_facetvalues()
-			self._inner_cache(obj, values_to_cache, facet, resulttype)
+			self._inner_cache(cached_fquery, values_to_cache, facet, resulttype)
 			return True
 			
 					
 
 
 
-	def _inner_cache(self, obj, values_to_cache, facet, resulttype):
-		""" method used in iteration, or only once, for adding facetValues obj with updated
-		counts to the  cachedFacetQueryObj
+	def _inner_cache(self, cached_fquery, values_to_cache, facet, resulttype):
+		"""
+		Does the caching of a list of facetvalues in the context of a specific cached_fquery
+		Each facetvalue contains specific information eg updated counts or mptt-related stuff..
 		"""
 		counter = 0 
 		counterTot = len(values_to_cache)
 			except:
 				cacheValue = CachedFacetValue(facetvalue=fv.name)	# add facet=....
 			cacheValue.count=fv.howmany
+			if facet.mptt:
+				# 2012-05-23: extra data for mptt subs preview
+				# cacheValue.subspreview is just a list of facetvalues
+				subs_serialization = "**$**".join([x.id for x in fv.subspreview]) 
+				cacheValue.mpttsubs = subs_serialization
 			cacheValue.save()
-			obj.facetvalues.add(cacheValue)
+			cached_fquery.facetvalues.add(cacheValue)
 
 
+	def explodeQueryargs(self, queryargs):
+		"""
+		Creates a deterministic representation of queryArgs, so that they can be stored in the DB as field of  
+		the CachedFacetQuery object
+		==> returns: '123_12345_562719192'
+		QueryArgs: list of facetvalues 
+
+		This is useful for caching second-level queries.
+
+		"""
+
+		queryargs_Ids = [x.id for x in queryargs]
+		return "_".join([str(x) for x in sorted(queryargs_Ids)])  # we sort them always by number
+
 
 
 
 			return False
 
 
-	def getCachedFacetValues(self, resulttype_name, facet, limit=1000000000000):
+	def getCachedFacetValues(self, resulttype_name, facet, limit=1000000000000, showonly_subs=False):
 		# if existing in DB-cache
 		# return a list of facetValues, with counts
 		# otherwise return None
 
 		facet_uniquename = facet.uniquename
 		if self.queryargs:
-			queryargs = self.transformQueryargs(self.queryargs)
+			queryargs = self.explodeQueryargs(self.queryargs)
 		else:
 			queryargs = None  # because it's an empty list otherwise...
 
 					fv = facet.get_facetvalue_from_name(int(val_obj.facetvalue))
 				else:
 					fv = facet.get_facetvalue_from_name(val_obj.facetvalue)						
-				if fv:
+				if fv and facet.mptt:
+					if showonly_subs:
+						# djfacetlog("noise")
+						test_fv = facet.get_facetvalue_from_id(showonly_subs)
+						if test_fv.id == fv.father:
+							continue
+						else:
+							break							
+					fv_copy = copy.copy(fv)	 #make a copy, so we NEVER update the static FM object (and it's thread-safe!)
+					fv_copy.howmany = val_obj.count
+					fv_copy.subspreview = [facet.get_facetvalue_from_id(x) for x in val_obj.mpttsubs.split("**$**") if val_obj.mpttsubs]
+					fv_copy.tot_left = remaining_values
+					fv_copy.tot_inbatch = tot_limitvalues
+					fv_copy.tot_all = tot_allvalues
+					output.append(fv_copy)
+
+				elif fv:
 					fv_copy = copy.copy(fv)	 #make a copy, so we NEVER update the static FM object (and it's thread-safe!)
 					fv_copy.howmany = val_obj.count
 					fv_copy.tot_left = remaining_values
 					fv_copy.tot_inbatch = tot_limitvalues
 					fv_copy.tot_all = tot_allvalues
 					output.append(fv_copy)
+								
 			return output
 		else:
 			return None
 
 		# case in which we have a list of queryargs to be transformed	
 		elif type(queryargs) == type(["a list"]):  
-			queryargs = self.transformQueryargs(queryargs)
+			queryargs = self.explodeQueryargs(queryargs)
 
 
 		elif type(queryargs) == type("a string") or type(queryargs) == type(u"a unicode string"):	 
 
 		# finally: 
 		try:
-			obj_old = CachedFacetQuery.objects.get(facet=facet.uniquename, resulttype=resulttype['uniquename'], queryargs=queryargs)
+			cached_fquery_old = CachedFacetQuery.objects.get(facet=facet.uniquename, resulttype=resulttype['uniquename'], queryargs=queryargs)
 		except:
 			return "there is not such facet to delete in the cached DB table"
 		djfacetlog("\n!!!!!!!!!!!!!!... removing all cached objects .........\n facet[%s] resType[%s] queryargs=[%s]" % (facet.uniquename, resulttype['uniquename'], str(queryargs)))
-		for v in obj_old.facetvalues.all():
+		for v in cached_fquery_old.facetvalues.all():
 			v.delete()
 
-		obj_old.delete()
+		cached_fquery_old.delete()
 		return True
 
 
 
 
 
+##################
+#  
+# EXTRA UTILS FOR CACHING HTML PAGES IN THE DB 
+#
+##################
 
 
+def cacheHTMLpage(text, pagename, extraargs="", ENFORCE=False):
+	""" Caches the contents of a page (eg splash page) in the DB
+
+	"""
+	c = CachedHtmlPage.objects.filter(page=pagename, args=extraargs)
+	if c and ENFORCE:
+		c[0].contents = text
+		c[0].save()
+		djfacetlog("CACHEHTMLPAGE: The page [%s, %s] has been re-cached." % (pagename, extraargs))
+	elif c and not ENFORCE:
+		djfacetlog("CACHEHTMLPAGE: The page [%s, %s] is already cached. Use ENFORCE to recache it." % (pagename, extraargs))
+	else:
+		c = CachedHtmlPage(page=pagename, args=extraargs, contents=text )
+		c.save()
+		djfacetlog("CACHEHTMLPAGE: The page [%s, %s] has been cached for the first time." % (pagename, extraargs), True)
+
+
+def get_cachedHTMLpage(pagename, extraargs=""):
+	""" REtrieves the cached contents of a page (eg splash page) from the DB
+
+	"""
+	c = CachedHtmlPage.objects.filter(page=pagename, args=extraargs)
+	if c:
+		djfacetlog("GET_CACHEDHTMLPAGE: The page [%s, %s] has been retrieved from DB" % (pagename, extraargs), True)
+		return c[0].contents
+	else:
+		djfacetlog("GET_CACHEDHTMLPAGE: The page [%s, %s] wasn't found in the cache." % (pagename, extraargs))
+		return None
+
+
+def delete_cachedHTMLpage(pagename, extraargs=""):
+	""" Deletes the cached contents of a page (eg splash page) from the DB
+
+	"""
+	c = CachedHtmlPage.objects.filter(page=pagename, args=extraargs)
+	if c:
+		c.delete()
+		djfacetlog("""DELETE_CACHEDHTMLPAGE: The page [%s, %s] has been deleted from DB\nIt will be automatically 
+		re-cached the next time you set DJF_SPLASHPAGE_CACHE = True""" % (pagename, extraargs), True)
+	else:
+		djfacetlog("DELETE_CACHEDHTMLPAGE: the page [%s, %s] was not found in the cache" % (pagename, extraargs), True)
+		return None
+
+
+
+
+
+
+
+
+
+
+

File demoproject/apps/djfacet/constants.py

 
 # 2011-09-05: eliminated	
 # if hasattr(settings, 'DJFACET_COUNT'):
-# 	DJFACET_COUNT = settings.DJFACET_COUNT
+#	DJFACET_COUNT = settings.DJFACET_COUNT
 # else:
-# 	DJFACET_COUNT = True	
+#	DJFACET_COUNT = True	
 	
 # 2011-11-07: eliminated	
 # if hasattr(settings, 'DJFACET_TEST'):
-# 	DJFACET_TEST = settings.DJFACET_TEST
+#	DJFACET_TEST = settings.DJFACET_TEST
 # else:
-# 	DJFACET_TEST = False
+#	DJFACET_TEST = False
 # 
-# 	
+#	
 
 if hasattr(settings, 'DJF_AJAX'):
 	DJF_AJAX = settings.DJF_AJAX
 	
 # 
 # if hasattr(settings, 'DJF_SPLASHPAGE'):
-# 	DJF_SPLASHPAGE = settings.DJF_SPLASHPAGE
+#	DJF_SPLASHPAGE = settings.DJF_SPLASHPAGE
 # else:
-# 	DJF_SPLASHPAGE = True
+#	DJF_SPLASHPAGE = True
 # 
 # 
 # 
 # if hasattr(settings, 'DJF_SPLASHPAGE_ORIENTATION'):
-# 	if settings.DJF_SPLASHPAGE_ORIENTATION in ['horizontal', 'vertical']:
-# 		DJF_SPLASHPAGE_ORIENTATION = settings.DJF_SPLASHPAGE_ORIENTATION
+#	if settings.DJF_SPLASHPAGE_ORIENTATION in ['horizontal', 'vertical']:
+#		DJF_SPLASHPAGE_ORIENTATION = settings.DJF_SPLASHPAGE_ORIENTATION
 # else:
-# 	DJF_SPLASHPAGE_ORIENTATION = 'vertical'
+#	DJF_SPLASHPAGE_ORIENTATION = 'vertical'
 # 
 
 
 	raise
 try:
 	DJF_SPECS = __import__(specs_location, globals(), locals(), [''])
-except:
-	raise Exception("\n************* DJ_FACET: can't find the <facetspecs.py> file.. It must be at the root level of your django project *********** MORE INFO AVAILABLE AT: http://www.michelepasin.org/support/djfacet/docs/configuration.html *****")
+except SyntaxError, e:
+	import traceback
+	top = traceback.extract_stack()[-1]
+	t = ", ".join([type(e).__name__, os.path.basename(top[0]), str(top[1])])
+	raise Exception("\n\n***** DJ_FACET: syntax error in <%s> file.. \n===>%s\n\n" % (specs_location, t))	
+except Exception, e:
+	import traceback
+	top = traceback.extract_stack()[-1]
+	t = ", ".join([type(e).__name__, os.path.basename(top[0]), str(top[1])])
+	raise Exception("\n\n***** DJ_FACET: error with <%s> file.. Is it available at rhe root level of your django project? \n===> http://www.michelepasin.org/support/djfacet/docs/configuration.html\nPython error: %s\n" % (specs_location, t))
 
 
 
 
 # http://www.myhtmltutorials.com/softcolor.html
 
-SOFT_HTML_COLORS = ( "EEFFFF", "FFEEFF" , "FFFFEE", "EEEEEE" ,"EEFFEE" , "FFEEEE" , "DDEEEE" ,	"EEDDEE",	"EEEEDD", "DDDDEE", "DDEEDD","EEDDDD", 	"DDFFFF",	"FFDDFF",	"FFFFDD", "DDDDFF", "DDFFDD",	"FFDDDD", "CCDDDD", "DDCCDD", "DDDDDD" ,  "EEEEFF", "DDDDCC", "CCCCDD", "CCDDCC",	"DDCCCC", "CCEEEE", "EECCEE",	"EEEECC", "CCCCEE", "CCEECC",	"EECCCC" ,"CCFFFF", "FFCCFF",	"FFFFCC" ,"CCCCFF", "CCFFCC",	"FFCCCC")
+SOFT_HTML_COLORS = ( "EEFFFF", "FFEEFF" , "FFFFEE", "EEEEEE" ,"EEFFEE" , "FFEEEE" , "DDEEEE" ,	"EEDDEE",	"EEEEDD", "DDDDEE", "DDEEDD","EEDDDD",	"DDFFFF",	"FFDDFF",	"FFFFDD", "DDDDFF", "DDFFDD",	"FFDDDD", "CCDDDD", "DDCCDD", "DDDDDD" ,  "EEEEFF", "DDDDCC", "CCCCDD", "CCDDCC",	"DDCCCC", "CCEEEE", "EECCEE",	"EEEECC", "CCCCEE", "CCEECC",	"EECCCC" ,"CCFFFF", "FFCCFF",	"FFFFCC" ,"CCCCFF", "CCFFCC",	"FFCCCC")
 
 
 # SOFT_HTML_COLORS = ( "red", "green" )

File demoproject/apps/djfacet/docs/configuration.rst

 Now we can put together the two parameters definitions above, so to obtain the entire facet definition for the 'Region name' facet. Check out the following sections in order to find out more about the available parameters for describing facets::
 
 	facetslist = [  
-			{'appearance' : {	
+			{	'active' : True,
+				'appearance' : {	
 					'label' : 'Region name' , 
 					'uniquename' : 'regionname',
 					'model' : Region , 
 					'grouping'	: ['countrygroup'],
 					'ordering' : 'extended_name',
 						} ,
-			'behaviour' :  [{
+				'behaviour' :  [{
 					'resulttype' : 'religions',
 					'querypath' : 'country__inregion__name', 
 					'inversepath' : None,
 				]
 
 
+.. _genericoptions:
+
+Generic options
+=======================================	
+
+``active``
+++++++++++++++
+Required: No / Default: True
+
+Specifies if a facet needs to be loaded. Can be used as a quick on/off switch for adding/removing facets. Defaults to True, so it can be omitted safely. 
+
+
 .. _facetappearanceoptions:
 
 Facet Appearance options

File demoproject/apps/djfacet/facet.py

 	
 	
 
-	# NOTE: it's not recursive anymore!!!! but it uses the function above..
+	# NOTE: depends the function above..
+	# 2012-05-22: STILL NEEDED? 
+	
 	def recursive_tree_forfacetvalue_list(self, facetvalue_list):
 		""" MPTT ONLY: given a list of instances, we're outputting the minimal tree that contains all of them
 		

File demoproject/apps/djfacet/facetedmanager.py

 		if DJF_CACHE:
 			djfacetlog("+++> DB-CACHE: .. trying to get values from DB for __%s__ ..." % facet.name)
 			cacheDB = DbCache(self, queryargs, activeIDs)
-			cache_test = cacheDB.getCachedFacetValues(resulttype_name, facet, LIMIT)
+			cache_test = cacheDB.getCachedFacetValues(resulttype_name, facet, LIMIT, showonly_subs)
 			if cache_test:
-				djfacetlog("	   -----> Retrieved values.....")
+				djfacetlog("	   -----> SUCCESS: Retrieved values.....")
 				return cache_test
 			else:
 				cache_test = None
-				djfacetlog("	   -----> Could not retrieve any value from DB cache...")
+				djfacetlog("	   -----> FAILED: Could not retrieve any value from DB cache...")
 
 		# 2. calculate the fv counts ==> cause the DBcache is switched off, or there's no cached data available
 		if cache_test == None:			
 			valueslist = q.calculate_facetvalues()
 			
 			# CACHE ON THE FLY, IF IT'S A FULL QUERY ONLY
-			if DJF_CACHE and not LIMIT:
+			if DJF_CACHE and not LIMIT and not showonly_subs:
 				if not queryargs:
 					result_type = self.get_resulttype_from_name(resulttype_name)		
-					if cacheDB._cacheOneFacetValue(facet, result_type, values_to_cache=valueslist):
+					if cacheDB._cacheOneFacet(facet, result_type, values_to_cache=valueslist):
 						djfacetlog("		  ...... on-the-fly DB-Cache operation successfull...!")
 				else:
 					pass # we're DB-caching on the fly only when there are no queryargs !!!!!!!! 

File demoproject/apps/djfacet/facetsgroup.py

 				
 			REMOVE_EMPTY_VALUES: defaults to true, makes sure we move all empty values from facets!	
 			If we set it to False, the FB works but there's a bug with the cache... TODO
+			
+			2012-05-22: added 'active' to facetspecs definition - quick way to deactive a facet - defaults to True. 
+			
+			
 		"""				
 		for i in facetspecs:
-			if self.uniquename in i['appearance']['grouping']:
+			if self.uniquename in i['appearance']['grouping'] and i.get("active", True):
+				mptt = i.get('mptt', False)
 				appearance_specs = i['appearance']
 				mask = appearance_specs.get('mask', None)
 				customvalues = appearance_specs.get('customvalues', None)
 				dbfield = appearance_specs.get('dbfield', None)
 				displayfield = appearance_specs.get('displayfield', None)
 				hierarchyoptions = appearance_specs.get('hierarchy', None) # ... or the hierarchy opts
-				ordering = appearance_specs.get('ordering', None) 
-				mptt = appearance_specs.get('mptt', False)
+				ordering = appearance_specs.get('ordering', None) 				
 				exclude = appearance_specs.get('exclude', False)
 				
 				behaviour = i.get('behaviour', None) # behavior of each facet//result_type
 				group = self
 				# Facet(name, originalModel, originalAttribute, displayAttribute = None, behaviour = None, hierarchyoptions= None,  mask=None, customvalues = None, mptt = False, exclude=False, group=[])
+				djfacetlog("..adding facet: %s" % appearance_specs['uniquename'], True)
 				x = Facet(appearance_specs['uniquename'], appearance_specs['label'], appearance_specs['model'], 
 								dbfield, displayfield, ordering, behaviour, hierarchyoptions, mask, customvalues, mptt, group=group)
 							

File demoproject/apps/djfacet/facetspecs_example.py

 
 
 
+#	label = interface name / uniquename = internal name / infospace: a Model or a QuerySet instance
 result_types	 = [{	'label' : 'Religions', 
 						'uniquename' : 'religions', 
 						'infospace' : Religion	,
 					]
 			 
 
-facet_groups   =	[{	'label':	'Place facets', 
+facet_groups =		[{	'label':	'Place facets', 
 						'position': 1,
 						'uniquename' :	'countrygroup', 
 						'default' : True  , 
-						'bkcolor' : '#' } ,
+						'bkcolor' : 'FFEEFF' } ,
 						
 					{	'label':	'Religion facets', 
 						'position': 2,
 						'uniquename' :	'religiongroup', 
-						'default' : True   } ,
+						'default' : True   ,
+						'bkcolor' : "EEFFFF"} ,
 					]
 
 
 								'displayfield' : "name", 
 								'explanation': "no explanation yet", # TODO: add explanations to all of them!
 								'grouping'	: ['countrygroup'],
-								# 'ordering' : 'helper_bigsurname',
-								# 'hierarchy' : {'alpha': True, }, 
+								'ordering' : 'name',
 								} ,
 				'behaviour' :  [{'resulttype' : 'religions',
 								 'querypath' : 'country__inregion__name', 
 								'displayfield' : "idbname", 
 								'explanation': "no explanation yet", # TODO: add explanations to all of them!
 								'grouping'	: ['countrygroup'],
-								# 'ordering' : 'helper_bigsurname',
-								# 'hierarchy' : {'alpha': True, }, 
+								'ordering' : 'idbname',
 								} ,
 				'behaviour' :  [{'resulttype' : 'religions',
 								 'querypath' : 'country__inregion__idbname', 
 								'displayfield' : "name", 
 								'explanation': "no explanation yet", # TODO: add explanations to all of them!
 								'grouping'	: ['countrygroup'],
-								# 'ordering' : 'helper_bigsurname',
-								# 'hierarchy' : {'alpha': True, }, 
+								'ordering' : 'name',
 								} ,
 				'behaviour' :  [{'resulttype' : 'religions',
 								 'querypath' : 'country__name', 
 								 'inversepath' : None,
 								 'explanation' : "showing all...." },
+								
+								# NOTE THAT THIS FACET WILL NOT WORK WITH COUNTRIES!
+								# ...if it did.. it could look like this:
+								
 								# {'resulttype' : 'country',
 								#  'querypath' : 'name', 
 								#  'inversepath' : None,
 						 },
 						
 						
+				# THIS IS AN MPTT/HIERARCHICAL FACET		
 
-
-				{	'appearance' : {'label' : 'Religion name' , 
+				{	'mptt' : True,
+					'appearance' : {'label' : 'Religion name' , 
 									'uniquename' : 'religionname',
 									'model' : Religion , 
 									'dbfield' : "name", 
 									'displayfield' : "name", 
 									'explanation': "no explanation yet", # TODO: add explanations to all of them!
 									'grouping'	: ['religiongroup'],
-									# 'ordering' : 'helper_bigsurname',
-									# 'hierarchy' : {'alpha': True, }, 
+									'ordering' : 'name',
 									} ,
 					'behaviour' :  [{'resulttype' : 'religions',
 									 'querypath' : 'name', 
 									]
 							 },
 
+		
 						
 						#	end of facet_list
 								]
 
 
 
+

File demoproject/apps/djfacet/facetvalue.py

 		self.mpttoriginalID = mpttoriginalID  # needed for getting bck to the MPTT instance and speeding up searches
 		self.mptt_treeID = mptt_treeID  # for faster searches on trees
 		self.id = self.__constructID(name, facet.uniquename)	# the unique ID python gives to every obj
+		# set up the mask
 		if self.mask:
 			if self.mask.get(self.name):
 				self.displayname = self.mask.get(self.name)
 
 
 
-
-# ===============
-# AN ATTEMPT TO ADD MPTT AT THIS LEVEL.....
-# ===============
-
-# 
-# try:
-# 	from mptt.models import MPTTModel
-# except:
-# 	raise "FACETVALUE.PY : WHere is MPTT?"
-# 
-# 
-# 
-# class FacetValueMPTT(MPTTModel):
-# 	"""A FacetValue is an element within a facet. ==== MPTT
-# 
-# 
-# 	"""
-# 	def __init__(self, name, facet, father=0, hierarchytype="", hierarchyextra=None, displayname="", 
-# 					mask=None, customvalues=None, howmany=0):
-# 		MPTTModel.__init__(self)
-# 		self.name = name
-# 		self.facet = facet
-# 		self.hierarchytype = hierarchytype	# a string
-# 		self.hierarchyextra = hierarchyextra  
-# 		self.displayname = displayname or name
-# 		self.father = father
-# 		self.mask = mask
-# 		self.customvalues = customvalues
-# 		self.howmany = howmany
-# 		self.id = id(self)	# the unique ID python gives to every obj
-# 		if self.mask:
-# 			if self.mask.get(self.name):
-# 				self.displayname = self.mask.get(self.name)
-# 
-

File demoproject/apps/djfacet/management/commands/djfacet_cleanfacetcache.py

-from django.core.management.base import BaseCommand, CommandError
-from optparse import make_option
-
-from django.conf import settings
-from django.db import connection, models
-from time import strftime
-import time
-
-
-from djfacet.load_all import *
-
-
-
-##################
-#  2010-09-17 
-#  TEST 
-#
-##################
-
-
-
-# EG:
-# bash-3.2$ python manage.py djfacet_cleanfacetcache surname
-
-
-
-class Command(BaseCommand):
-	args = '<facet_uniquename1, facet_uniquename2, facet_uniquename3 etc. >'
-	help = 'Delete cachedObject according to parameters'
-
-	# make_option requires options in optparse format
-	option_list = BaseCommand.option_list  + (
-						make_option('--resulttypes', action='store', dest='resulttypes', default='all',
-									help='The _resulttypes_ option determines what resulttypes-facet couple will be cached'),
-						make_option('--emptyunused', action='store', dest='emptyunused', default='no',
-									help='The _emptyunused_ option empties the unused elements from CachedFacetValue and CachedQueryArgs tables'),
-						make_option('--firstlevel', action='store', dest='firstlevel', default='no',
-									help='The _firstlevel_ option determines whether we delete only objects at the firstlevel (= with no QueryArgs)'),
-						make_option('--secondlevel', action='store', dest='secondlevel', default='no',
-									help='The _secondlevel_ option determines whether to delete only objects at the firstlevel (= with QueryArgs)'),
-				  )
-
-
-	# :an init method that does the repetitive stuff....
-	def __init__(self, *args, **kwargs):
-
-		
-		#  MIND THAT IF <DJF_CACHE> IS SET TO TRUE AND THERE IS A CACHED VERSION OF THE FM, THAT'S WHAT'S BEEN USED!
-		#  IF YOU PASS FORCE_CREATION=True then the FM IS RECONSTRUCTED
-		self.fm = access_fmglobal()
-		
-		super(Command, self).__init__(*args, **kwargs)
-	
-
-
-	def handle(self, *args, **options): 
-		"""
-		args - args (eg. myapp in "manage.py reset myapp") = the facet names [result types are all by default]
-		options - configurable command line options
-		"""
-
-		all_facets = self.fm.get_all_facets()
-		all_resulttypes = self.fm.result_types
-		if not all_facets:
-			raise "No facets available!" 
-			
-	
-		if args:
-			temp = []
-			for a in args:
-				djfacetlog("Argument provided: ==%s==" % str(a))
-				temp += [x for x in all_facets if x.uniquename == str(a)]
-			all_facets = temp
-
-		if options['resulttypes'] != 'all':
-			test = self.fm.get_resulttype_from_name(options['resulttypes'])
-			if test:
-				all_resulttypes = [test]
-
-		# feedback:
-		print "++ = ++ = ++ = ++ = ++ = ++ = ++ = ++\nSTARTED DELETING CACHED FACET VALUES WITH PARAMS:"	
-		print "facets: " + str([facet.uniquename for facet in all_facets])
-		print "resulttypes:  "  + str([resulttype['uniquename'] for resulttype in all_resulttypes])
-		print "firstlevel:  "  + str(options['firstlevel'])
-		print "secondlevel:  "  + str(options['secondlevel'])
-		print "emptyunused:  "  + str(options['emptyunused'])
-		print "++ = ++ = ++ = ++ = ++ = ++ = ++ = ++\n"
-
-
-		
-		#  now do the actions: 
-
-		cacheDBinstance = DbCache(self.fm)
-
-		if options['emptyunused'] == 'yes':
-			print '.... now deleting all the unused elements...'
-			tot = cacheDBinstance._emptyUnusedElements()
-			print '............. successfully deleted [%d] unused elements' % tot
-
-		if options['firstlevel'] == 'yes':
-			for facet in all_facets:
-				for r in all_resulttypes:
-					cacheDBinstance._emptyCacheForFacetQuery(facet, r, None)
-			print '\nSuccessfully deleted firstlevel facets\n'
-			print '.... now deleting other unused elements...'
-			tot = cacheDBinstance._emptyUnusedElements()
-			print '............. successfully deleted [%d] unused elements' % tot
-
-		if options['secondlevel'] == 'yes':
-			for facet in all_facets:
-				for r in all_resulttypes:
-					cacheDBinstance._emptyCacheForFacetQuery(facet, r, 'only_with_queryargs')
-			print '\nSuccessfully deleted secondlevel facets\n'
-			print '.... now deleting other unused elements...'
-			tot = cacheDBinstance._emptyUnusedElements()
-			print '............. successfully deleted [%d] unused elements' % tot
-							
-		if options['firstlevel'] == 'no' and options['secondlevel'] == 'no':
-			for facet in all_facets:
-				for r in all_resulttypes:
-					cacheDBinstance._emptyCacheForFacetQuery(facet, r, 'all')
-			print '\nSuccessfully deleted ALL cached facets (WITH or WITHOUT QUERYARGS)\n'
-			print '.... now deleting other unused elements...'
-			tot = cacheDBinstance._emptyUnusedElements()
-			print '............. successfully deleted [%d] unused elements' % tot
-			
-	

File demoproject/apps/djfacet/management/commands/djfacet_facetcache.py

 # bash-3.2$ python manage.py djfacet_facetcache gender --secondlevel=yes  --lowerlimit=9905
 # bash-3.2$ python manage.py djfacet_facetcache possoffice possunfreepersons posslands possrevkind possrevsilver privileges
 
+
+# bash-3.2$ python manage.py djfacet_facetcache --reset=yes  # clears everything
+# bash-3.2$ python manage.py djfacet_facetcache --emptyunused=yes  # removes only unusued values
+
+
 class Command(BaseCommand):
 	args = '<facet_uniquename1, facet_uniquename2, facet_uniquename3 etc. >'
 	help = 'Cached all facet values within the facets available'
 
 	# make_option requires options in optparse format
 	option_list = BaseCommand.option_list  + (
-						make_option('--resulttypes', action='store', dest='resulttypes', default='all',
-									help='The _resulttypes_ option determines what resulttypes-facet couple will be cached'),
-						make_option('--enforce', action='store', dest='enforce', default='yes',
-									help='The _enforce_ option determines whether we delete previously cached object (default= TRUE!)'),
-						make_option('--onlyrescounts', action='store', dest='onlyrescounts', default='no',
-									help='The _onlyrescounts_ option determines whether to update only the res tot-counts (no facet values)'),
-						make_option('--fmcache', action='store', dest='fmcache', default='no',
-									help='The _fmcache_ option determines whether to recache the faceted manager instance too'),
+						make_option('--resulttypes', action='store', dest='resulttypes', 
+									default='all', help='The _resulttypes_ option determines what resulttypes-facet couple will be cached'),
+						make_option('--enforce', action='store', dest='enforce', 
+									default='yes', help='The _enforce_ option determines whether we delete previously cached object (default= TRUE!)'),
+						make_option('--onlyrescounts', action='store', dest='onlyrescounts', 
+									default='no', help='The _onlyrescounts_ option determines whether to update only the res tot-counts (no facet values)'),
+						make_option('--fmcache', action='store', dest='fmcache', 
+									default='no', help='The _fmcache_ option determines whether to recache the faceted manager instance too'),
+						# DELETING STUFF			
+						make_option('--emptyunused', action='store', dest='emptyunused', default='no',
+									help='The _emptyunused_ option empties the unused elements from CachedFacetValue and CachedQueryArgs tables'),
+						make_option('--reset', action='store', dest='reset', default='no',
+									help='The _reset_ option removes all previously cached values in the DB (also the FM)'),
 
 				  )
 
 		options - configurable command line options
 		"""
 
-		if options['fmcache'] == 'no':
-			#  MIND THAT IF <DJF_CACHE> IS SET TO TRUE AND THERE IS A CACHED VERSION OF THE FM, THAT'S WHAT'S BEEN USED!
-			FM_INSTANCE = access_fmglobal()
-			FM_INSTANCE.init_resulttypes_activeIDs()	 #cache this in memory first.
 
-		else:			
-			#  IF YOU PASS FORCE_CREATION=True then the FM IS RECONSTRUCTED		
-			FM_INSTANCE = access_fmglobal(FORCE_CREATION=True)
+		# delete section
+		if options['emptyunused'] == 'yes' or options['reset'] == 'yes':
+			if options['emptyunused'] == 'yes':
+				self.fm = access_fmglobal()
+				cacheDBinstance = DbCache(self.fm)
+				print '.... now deleting all the unused elements...'
+				tot = cacheDBinstance._emptyUnusedElements()
+				print '............. successfully deleted [%d] unused elements' % tot
+			elif options['reset'] == 'yes':
+				print "++ = ++ = ++ = ++ Cleaning all previously cached contents database...."
+				CachedFacetedManager.objects.all().delete()  # empty it first: there must be one line only
+				CachedFacetQuery.objects.all().delete()
+				CachedFacetValue.objects.all().delete()
+				print '.........successfully erased all previously cached contents!\n'
+				
+			
+		else:
 
-			print "++ = ++ = ++ = ++ Cleaning the database...."
-			CachedFacetedManager.objects.all().delete()  # empty it first: there must be one line only
-			c = CachedFacetedManager(manager=FM_INSTANCE)
-			c.save()
-			print '.........successfully cached the Faceted Manager object!\n'
+			if options['enforce'] == 'yes':
+				ENFORCE = True
+			else:
+				ENFORCE = True	# to be implemented..
 			
-		all_facets = FM_INSTANCE.get_all_facets()
-		all_resulttypes = FM_INSTANCE.result_types
+			if options['fmcache'] == 'yes':
+			
+				# CLEAN UP AND RECONSTRUCT THE CACHED FM INSTANCE  
+			
+				print "++ = ++ = ++ = ++ Cleaning all previously cached contents database...."
+				CachedFacetedManager.objects.all().delete()  # empty it first: there must be one line only
+				CachedFacetQuery.objects.all().delete()
+				CachedFacetValue.objects.all().delete()
+				FM_INSTANCE = access_fmglobal(FORCE_CREATION=True)
+				c = CachedFacetedManager(manager=FM_INSTANCE)
+				c.save()
+				print '.........successfully cached the Faceted Manager object!\n'
+				FM_INSTANCE.init_resulttypes_activeIDs()
+			
+			else:						
+			
+				#  USED WHATEVER CACHED VERSION OF THE FM IS AVAILABLE (PS: <DJF_CACHE> MUST BE SET TO TRUE )
+				#  ALTERNATIVELY, access_fmglobal() WILL RE-CREATE THE FM BUT WILL NOT CACHE IT 
+			
+				FM_INSTANCE = access_fmglobal()
+				FM_INSTANCE.init_resulttypes_activeIDs()	 #cache this in memory first.
+
+
+			
+			all_facets = FM_INSTANCE.get_all_facets()
+			all_resulttypes = FM_INSTANCE.result_types
+
+			
+			if args:
+				temp = []
+				for a in args:
+					djfacetlog("Argument provided: ==%s==" % str(a), True)
+					temp += [x for x in all_facets if x.uniquename == str(a)]
+				all_facets = temp
+
+			if options['resulttypes'] != 'all':
+				test = FM_INSTANCE.get_resulttype_from_name(options['resulttypes'])
+				if test:
+					all_resulttypes = [test]
+				else:
+					raise Exception, "ERROR: THE RESULTTYPE PASSED IS NOT VALID!" 
 				
 
 
-		if options['enforce'] == 'yes':
-			ENFORCE = True
-		else:
-			ENFORCE = True	# to be implemented..
-			
-		if args:
-			temp = []
-			for a in args:
-				djfacetlog("Argument provided: ==%s==" % str(a), True)
-				temp += [x for x in all_facets if x.uniquename == str(a)]
-			all_facets = temp
+			# feedback:
+			print "\n\n++ = ++ = ++ = ++ = ++ = ++ = ++\n%s\nSTARTING CACHING FACET VALUES WITH PARAMS:"  % strftime("%Y-%m-%d %H:%M:%S")	
+			print "facets: " + str([facet.uniquename for facet in all_facets])
+			print "resulttypes:	 "	+ str([resulttype['uniquename'] for resulttype in all_resulttypes])
+			print "enforce:	 "	+ str(options['enforce'])
+			print "fmcache:	 "	+ str(options['fmcache'])
+			print "reset:  "  + str(options['reset'])
+			print "emptyunused:  "  + str(options['emptyunused'])
+			print "++ = ++ = ++ = ++ = ++ = ++ = ++ = ++\n"
 
 
-		if options['resulttypes'] != 'all':
-			test = FM_INSTANCE.get_resulttype_from_name(options['resulttypes'])
-			if test:
-				all_resulttypes = [test]
-			else:
-				raise Exception, "ERROR: THE RESULTTYPE PASSED IS NOT VALID!" 
-				
 
 
-		# feedback:
-		print "\n\n++ = ++ = ++ = ++ = ++ = ++ = ++ = ++\n%s\nSTARTING CACHING FACET VALUES WITH PARAMS:"  % strftime("%Y-%m-%d %H:%M:%S")	
-		print "facets: " + str([facet.uniquename for facet in all_facets])
-		print "resulttypes:	 "	+ str([resulttype['uniquename'] for resulttype in all_resulttypes])
-		print "enforce:	 "	+ str(options['enforce'])
-		print "fmcache:	 "	+ str(options['fmcache'])
-		print "++ = ++ = ++ = ++ = ++ = ++ = ++ = ++\n"
+			#  now do the actions: 
 
 
+			cacheDB = DbCache(FM_INSTANCE)
 
 
-		#  now do the actions: 
 
-
-		cacheDB = DbCache(FM_INSTANCE)
-
-
-
-		# 1) cache the result types count  (later we'll have to make this an option for the command...)
-		if True:
-			cacheDB.cacheResultTypes()
+			# 1) cache the result types count  (later we'll have to make this an option for the command...)
+			if True:
+				cacheDB.cacheResultTypes()
 					
-		# 2) cache all the values
-		if options['onlyrescounts'] == 'no':  # option for caching only the tot resultTypes counts
-			for facet in all_facets:
-				for r in all_resulttypes:
-					if not facet.get_behaviour(r['uniquename']): 
-						print "\n WARNING ==> There is no behaviour defined for	 ...  [facet=%s, resType=%s]" % (str(facet.uniquename), r['uniquename'])
-					else:					
-						print "\n starting caching at [%s] ...... [facet=%s, resType=%s]"	 %	(strftime("%Y-%m-%d %H:%M:%S"), str(facet.uniquename), r['uniquename'])
-						v = cacheDB._cacheOneFacetValue(facet, resulttype=r, ENFORCE=ENFORCE) 
-						if v:
-							print "\n[%s]\nzzzzzzzzzzzzzzzzzz sleeping 1 second zzzzzzzzzzzzzzzzzzzzzzzz\n\n"	% strftime("%Y-%m-%d %H:%M:%S")
-							time.sleep(1)
+			# 2) cache all the values
+			if options['onlyrescounts'] == 'no':  # option for caching only the tot resultTypes counts
+				for facet in all_facets:
+					for r in all_resulttypes:
+						if not facet.get_behaviour(r['uniquename']): 
+							print "\n WARNING ==> There is no behaviour defined for	 ...  [facet=%s, resType=%s]" % (str(facet.uniquename), r['uniquename'])
+						else:					
+							print "\n...started caching at [%s] ...... [facet=%s, resType=%s]"	 %	(strftime("%Y-%m-%d %H:%M:%S"), str(facet.uniquename), r['uniquename'])
+							v = cacheDB._cacheOneFacet(facet, resulttype=r, ENFORCE=ENFORCE) 
+							if v:
+								print "\n[%s]\nzzzzzzzzzzzzzzzzzz sleeping 1 second zzzzzzzzzzzzzzzzzzzzzzzz\n\n"	% strftime("%Y-%m-%d %H:%M:%S")
+								time.sleep(1)
 					
 
 						
-			print '\nSuccessfully cached facets [%s]' % (str([facet.uniquename for facet in all_facets]))
-			#  let's clean the cache for unused elements...
-			print "\nNow emptying unused elements....."
-			print "....DONE: tot emptied elements= %d"	% cacheDB._emptyUnusedElements()
+				print '\nSuccessfully cached facets [%s]' % (str([facet.uniquename for facet in all_facets]))
+				#  let's clean the cache for unused elements...
+				print "\nNow emptying unused elements....."
+				print "....DONE: tot emptied elements= %d"	% cacheDB._emptyUnusedElements()
 
 

File demoproject/apps/djfacet/management/commands/djfacet_fmcache.py

 
 ##################
 #  
-#  Command that creates the cached version of the faceted manager 
+#  Command that creates the cached version of the faceted manager.
+# 
+# 	By default it also erases all previously cached values.
 #
 ##################
 
 		print "\n++ = ++ = ++ = ++ ++\n%s\nSTARTING CACHING the Faceted Manager using pickle"	 % strftime("%Y-%m-%d %H:%M:%S")	
 		print "++ = ++ = ++ = ++ \n"
 		
+		print "++ = ++ = ++ = ++ Cleaning all previously cached contents database...."
+		CachedFacetedManager.objects.all().delete()  # empty it first: there must be one line only
+		CachedFacetQuery.objects.all().delete()
+		CachedFacetValue.objects.all().delete()
+		
 		#  IF YOU PASS FORCE_CREATION=True then the FM IS RECONSTRUCTED		
 		FM_INSTANCE = access_fmglobal(FORCE_CREATION=True)
 
-		print "++ = ++ = ++ = ++ Cleaning the database...."
-		CachedFacetedManager.objects.all().delete()  # empty it first: there must be one line only
-
 		c = CachedFacetedManager(manager=FM_INSTANCE)
 		c.save()
 		

File demoproject/apps/djfacet/models.py

 
 
 
-#  ====================================
+##################
+#  
+#  MODELS USED TO CACHE QUERIES, FACET VALUES AND COUNTS
+#
+##################
 
-################ MODELS USED TO CACHE FACET VALUES AND COUNTS
 
-#  ====================================
+class CachedFacetedManager(TimeStampedHiddenModel):
+	"""	
+	Simple one-field table that contains the pickled backup of the faceted manager instance.
+	"""
+	manager = PickledObjectField()	# the fields that contains tyhe pickled fm instance value
+	
+
 
 
 
 class CachedFacetQuery(TimeStampedHiddenModel):
-	"""	 an abstraction of a FB query run to get the count of available facetValues	 """
+	"""	 
+	an abstraction representing a Django Facet query, run to get the count of available facetValues. 
+	
+	"""
 	facet = models.CharField(max_length=50, verbose_name="the uniquename of the facet")
 	resulttype = models.CharField(max_length=50, verbose_name="the uniquename of the result type")
 	tot_ids = models.IntegerField(null=True, blank=True, verbose_name="we store the tot number of resulttype objects") 
 	# queryargs = models.ForeignKey('CachedQueryArgs', null=True, blank=True,)
 	queryargs = models.TextField(null=True, blank=True, verbose_name="Contains a collation of the queryargs IDs - can become pretty big.. so we couldn't use a BIGINT or similar!")
-	
 	facetvalues = models.ManyToManyField('CachedFacetValue', null=True, blank=True,)
 	
 	class Meta:
 		pass
 
-# 
-# 
-# class CachedQueryArgs(TimeStampedHiddenModel):
-#	""" an abstraction of the filters used in a FB query (constructed succintly through a deterministic function) """
-#	facets = models.CharField(max_length=100, verbose_name="a deterministic collation of the uniquename of the facets involved in the query")
-#	values = models.CharField(max_length=100, verbose_name="a deterministic collation of the uniquename of the names of the facetValues involved in the query")
+
 
 
 
 class CachedFacetValue(TimeStampedHiddenModel):
-	"""	 abstraction of facet values, together with their count """
+	"""	
+	Abstraction of facet values, together with their count and all the info necessary for updating the interface in relation to a specific 
+		CachedFacetQuery instance
+		
+	2012-05-23: added extra subs field: "alter table djfacet_cachedfacetvalue add column mpttsubs longtext;"
+	"""
 	facetvalue = models.CharField(max_length=200, null=True, verbose_name="the name of the value")
-	facet = models.CharField(max_length=20, null=True, blank=True, verbose_name="NOT USED ? ? the uniquename of the facet")
+	facet = models.CharField(max_length=20, null=True, blank=True, verbose_name="The uniquename of the facet - NOT USED")
 	count = models.IntegerField(verbose_name="the count", null=True)
+	mpttsubs = models.TextField(null=True, blank=True, verbose_name="If it is an MPTT values, it contains a collation of the sub-values IDs - serialized as a list of strings separate by the '**$**' string. It can become pretty big.. so we couldn't use a BIGINT or similar!")
 
 
 
 
-class CachedFacetedManager(TimeStampedHiddenModel):
-	"""	 contains the pickled backup of the faceted manager	 """
-	manager = PickledObjectField()	# the fields that contains tyhe pickled fm instance value
-	
-	
+##################
+#  
+#  other helper models 
+#
+##################
 
 
 
 
 class CachedHtmlPage(TimeStampedHiddenModel):
-	"""	 contains the pickled backup of an html page
-	Currently used only for the splash page when it's to large to recalculate each time...	 """
+	"""
+	Helper table that contains the pickled backup of an html page
+	Currently used only for the splash page when it's to large to recalculate each time...	 
+	"""
 	page = models.CharField(max_length=100, verbose_name="page")
 	args = models.CharField(blank=True, max_length=100, verbose_name="auxiliary args - sometimes needed")
 	contents = PickledObjectField()

File demoproject/apps/djfacet/queryhelper.py

 		self.resulttypeModel = self.get_resulttype_from_name(resulttypeName)['infospace'] # so that it's called only once..
 		self.limit = limit or 1000000000000000	# if None or 0 is passed, default to unlimited
 		self.showonly_subs = showonly_subs
-		self.TOTCURRENT_RESULTS = len(activeIDs) # 2012-04-26: used to remove searchvalues that have no filtering potential
+		self.TOTCURRENT_RESULTS = 0
+		if activeIDs:
+			self.TOTCURRENT_RESULTS = len(activeIDs) # 2012-04-26: used to remove searchvalues that have no filtering potential
 
 	def should_we_use_distinct(self, facetModel, resultModel):
 		""" Returns false is the two models are different (proxy models don't count)
 				
 		for value in valid_values:
 				
-			if facet.mptt and DJF_MPTT_INHERITANCE:  # => flags that mptt inheritance values have to be calc on the fly
+			if facet.mptt and DJF_MPTT_INHERITANCE:	 # => flags that mptt inheritance values have to be calc on the fly
 			
 				fv = facet.get_facetvalue_from_MPTTid(value['id'])
 				
 					counter += 1				
 						
 					if tot_limitvalues <= LIMIT: 
-						subs, howmany = self._calcMPTT_inheritance(facet, fv, all_values, dbfield)
-						if howmany != self.TOTCURRENT_RESULTS:
-							# print all_values					
+						subs, howmany = self._calcMPTT_inheritance(facet, fv, all_values, dbfield, DJF_MPTT_INHERITANCE)
+						if howmany > 0 and howmany != self.TOTCURRENT_RESULTS:				
 							fv_copy = copy.copy(fv)	 #make a copy, so we don't update the static FM object
 							fv_copy.howmany = howmany
+							fv_copy.subspreview = subs
+							tot_limitvalues += 1
+							output.append(fv_copy)							
 							try:  #sometimes this fails due to ascii encoding errors, so we're catching it
 								djfacetlog("===>> updating FV count (with inference) for value: *%s=%s* (validated as %s) ==> +%d+	[%d of %d]" %
 								 (str(value), facet.get_facetvalue_from_MPTTid(value['id']).name, fv.name, howmany, counter,  len(valid_values)))
 							except:
-								pass
-						
-							fv_copy.subspreview = subs
-							tot_limitvalues += 1
-							output.append(fv_copy)		
+								pass						
+	
 				else:
+					tot_allvalues -= 1
 					try:
-						pass
-						djfacetlog("===>> NOT VALIDATED: *%s=%s*	[%d of %d]" % (str(value), facet.get_facetvalue_from_MPTTid(value['id']).name,  counter,  len(valid_values)))  # if you want to debug this
+						pass # if you want to debug this comment this line
+						djfacetlog("===>> NOT VALIDATED: *%s=%s*	[%d of %d]" % (str(value), facet.get_facetvalue_from_MPTTid(value['id']).name,	counter,  len(valid_values)))  
 					except:
 						pass
 		
+		
+			# IF normal value - or MPTT but NOT DJF_MPTT_INHERITANCE
+			
 			else:
 				
 				fv = facet.get_facetvalue_from_name(value[dbfield])
-				if fv:
+				if fv and value['count']:
 					counter += 1
 					try:  
 						djfacetlog("===>> updating FV count for value: *%s* ==> +%d+	[%d of %d]" % (str(value[dbfield]), 
 																				value['count'], counter,  len(valid_values)))
 					except:
 						pass
-					fv_copy = copy.copy(fv)	
+					fv_copy = copy.copy(fv) 
 					fv_copy.howmany = value['count']
 					if facet.mptt:
-						fv_copy.subspreview = self._calcMPTT_subsPreview(facet, fv, all_values, dbfield)
+						# fv_copy.subspreview = self._calcMPTT_subsPreview(facet, fv, all_values, dbfield)
+						fv_copy.subspreview = self._calcMPTT_inheritance(facet, fv, all_values, dbfield, DJF_MPTT_INHERITANCE)
 					tot_limitvalues += 1
 					output.append(fv_copy)
-								
+				else:
+					# update the count of tot available values
+					tot_allvalues -= 1
+					try:
+						pass # if you want to debug this comment this line
+						djfacetlog("===>> NOT VALIDATED: *%s* ==> +%d+	[%d of %d]" % (str(value[dbfield]), 
+												value['count'], counter,  len(valid_values)))  
+					except:
+						pass								
 			
 		
 		remaining_values = tot_allvalues - tot_limitvalues
 
 
 	def modify_countarg_forMPTT(self, facet, count_argument):
-		# print "\n******\n", count_argument, "\n******"
+		# print "\n******\ncount_argument= ", count_argument, " facet.originalAttribute=", facet.originalAttribute, "\n******"
 		if facet.originalAttribute:
-			count_argument = count_argument.rstrip(facet.originalAttribute)
-		# print "\n******\n", count_argument, "\n******"
+			if count_argument.endswith(facet.originalAttribute):
+				count_argument = count_argument.rstrip(facet.originalAttribute)
+		# print "\n******\ncount_argument= ", count_argument, "\n******"
 		if count_argument:
 			count_argument_and_id = count_argument + "__id"
 		else:
 			count_argument_and_id = "id"
-		# print "\n******", count_argument_and_id, "\n******"
+		# print "\n******count_argument_and_id= ", count_argument_and_id, "\n******"
 		return count_argument_and_id
 
 
 
 	def _validateMPTTvalue(self, mpttfacet, mpttfacetvalue, queryargs, current_output):
 		"""
-		Method that checks if a MPTT facetvalue should be returned, based on current query query parameters.
+		Method that checks if a MPTT facetvalue should be returned, based on current query parameters.
 		<self.showonly_subs> Fvalue_ID indicating that we're digging into a specific tree, so non-tree values are discarded.
 		<current_output> List of already validate MPTT values, used for checking against duplicates.
 		
 			
 
 	
-	def _calcMPTT_inheritance(self, facet, facetvalue, all_values, dbfield):
+	def _calcMPTT_inheritance(self, facet, facetvalue, all_values, dbfield, DJF_MPTT_INHERITANCE):
 		""" 
-		In this case all_values is like this:
+		Returns a tuple of lists or a single list depending on whether the MPTT_INHERITANCE is calculated.   
 		
-		{31L: [104L, 155L, 216L, 45L, 117L, 97L, 126L, 196L, 96L, 69L, 156L, 2L, 4L, 61L, 198L, 206L, 75L, 191L, 110L, 223L, 64L, 187L, 120L], 
-			32L: [212L, 110L, 155L, 96L, 156L, 198L, 73L, 2L, 97L], 33L: [2L, 197L, 186L, 147L, 14L, 221L, 14.... etc.....}
+		If DJF_MPTT_INHERITANCE = False:
+			Get descendants from MPTT, and choose the ones already available in all_values.
+			All_values is  
+			[{'count': 0, 'name': u'Muslim'}, {'count': 62, 'name': u'Muslim -Shia and Sunni-'}, etc.....]
+		
+		If DJF_MPTT_INHERITANCE = True:
+		
+			In this case all_values is like this:
+		
+			{31L: [104L, 155L, 216L, 45L,], 32L: [212L, 110L,], 33L: [2L, 197L, 186L, 147L, 14L, 221L, 14.... etc.....}
 				
-		A consolidated dict of mptt-IDs with [list of IDs] of valid results. This would let us do some ad hoc counting.
+			A consolidated dict of mptt-IDs with [list of IDs] of valid results. This would let us do some ad hoc counting.
 		
-		Approach:
-		From current facetvalue, extract corresponding MPTT instance, and get its descendants via DB. 
-		If descendants exist in all_values, append relevant [list of IDs] to an output list, and eventually remove duplicates from it. 
+			Approach:
+			From current facetvalue, extract corresponding MPTT instance, and get its descendants via DB. 
+			If descendants exist in all_values, append relevant [list of IDs] to an output list, and eventually remove duplicates from it. 
 		
-		That is returned together with a preview-list of the (valid) children of the fvalue, so to be used in a tooltip ...
+			That is returned together with a preview-list of the (valid) children of the fvalue, so to be used in a tooltip ...
 
 		"""
-		mpttinstance = facet.originalModel.objects.get(pk=facetvalue.mpttoriginalID)
-		descendants = mpttinstance.get_descendants(True) # includes this element too
-		count_list = []
-		subsPreview_list = []
-		for mpttval in descendants:
-			if all_values.get(mpttval.id):
-				count_list += all_values.get(mpttval.id)
-				if len(subsPreview_list) < 10 and mpttinstance.id != mpttval.id: #do not include the top level father
-					subsPreview_list.append(facet.get_facetvalue_from_MPTTid(mpttval.id))
-		return (subsPreview_list, len(set(count_list)))
+		if DJF_MPTT_INHERITANCE:
+			mpttinstance = facet.originalModel.objects.get(pk=facetvalue.mpttoriginalID)
+			descendants = mpttinstance.get_descendants(True) # includes this element too (MPTT method)
+			count_list = []
+			subsPreview_list = []
+			for mpttval in descendants:
+				if all_values.get(mpttval.id):
+					count_list += all_values.get(mpttval.id)
+					if len(subsPreview_list) < 10 and mpttinstance.id != mpttval.id: #do not include the top level father
+						subsPreview_list.append(facet.get_facetvalue_from_MPTTid(mpttval.id))
+			return (subsPreview_list, len(set(count_list)))
 
+		else:
+			# TODO : to be tested!!!
+			subsPreview_list = []
+			tree = facet.recursive_tree_forfacetvalue(facetvalue)
+			for eachtree in tree:
+				for v in all_values:
+					if eachtree.name == v[dbfield]:
+						subsPreview_list.append(eachtree)
+			return subsPreview_list		
 
 
 
 					count_argument_and_id = self.modify_countarg_forMPTT(facet, count_argument)
 					unique_identifier = 'id'					
 					# no need to find counts, just names for now:
-					if self.showonly_subs:  # in this case we want to retrieve all results, as they will be filtered later in <_calcMPTT_inheritance>
+					if self.showonly_subs:	# in this case we want to retrieve all results, as they will be filtered later in <_calcMPTT_inheritance>
 						valid_values = facetModel.objects.values(unique_identifier,).distinct()
 					else:
 						valid_values = facetModel.objects.filter(level=0).values(unique_identifier,).distinct()
 					# Create all_values with all IDs of valid results, so that we can do the counting later, eg:
 					# >>> Religion.objects.values('id', 'country__id')
 					# [{'country__id': None, 'id': 360L}, {'country__id': 225L, 'id': 58L}, {'country__id': 193L, 'id': 58L}, 
-					# 	{'country__id': 137L, 'id': 58L}, {'country__id': 14L, 'id': 58L}, '...(remaining elements truncated)...']					
+					#	{'country__id': 137L, 'id': 58L}, {'country__id': 14L, 'id': 58L}, '...(remaining elements truncated)...']					
 					all_values = facetModel.objects.values(unique_identifier, count_argument_and_id)
 
 					# here we consolidate the list of dicts above into a simple dict where IDs are grouped
 
 				else:
 					# if DJF_MPTT_INHERITANCE is False	(= counts are final, no need to check inheritance info)
-
+		 				# values have this form:
+		 					# [{'count': 0, 'name': u'Muslim'}, {'count': 62, 'name': u'Muslim -Shia and Sunni-'}, {'count': 9, 'name': u'Shia Muslim'}, {'count': 23, 'name': u'Sunni Muslim'},etc.....]
 						# TODO: when checking with POMS - maybe we need to force DISTINCT = True here?
 
 					all_values = facetModel.objects.values(dbfield).annotate(count=Count(count_argument, distinct=DISTINCT)).filter(count__lt=self.TOTCURRENT_RESULTS)			
 							valid_values = facetModel.objects.filter(level=0).values(dbfield).annotate(count=Count(count_argument, distinct=DISTINCT)).filter(count__lt=self.TOTCURRENT_RESULTS)[:LIMIT]
 
 
+
+			#
+			# no Args, no MPTT				
+			#
+			
 			else:	
 
-				# no Args, no MPTT
-
 				all_values = facetModel.objects.values(dbfield).annotate(count=Count(count_argument, distinct=DISTINCT)).filter(count__lt=self.TOTCURRENT_RESULTS)			
 
 				if facet.ordering:
 					valid_values = facetModel.objects.values(dbfield).annotate(count=Count(count_argument, distinct=DISTINCT)).filter(count__lt=self.TOTCURRENT_RESULTS)[:LIMIT]
 
 
+
 		# ===
 		# 2) IF HAVE ARGS, OR THE ARGS ARE HIDDEN VIA A PROXY MODEL
 		# ===
 
 
 				else:		
-				# TO CHECK in poms:	2012-05-11
+				# TO CHECK in poms: 2012-05-11
 					all_values = facetModel.objects.filter(**temp).values(dbfield).annotate(count=Count(count_argument, distinct=DISTINCT))			
 
 					if facet.ordering:
 		return [all_values, valid_values]	
 
 
+
+
+
+
+
 	def _calcvaluesForORQueries(self, reversed_paths_list, facetModel):
 		"""
 			2012-04-25: this method haven't been updated with new MPTT stuff. TO bE REVISED

File demoproject/apps/djfacet/static/djfacet/js/djfacet.js

 	
 	if (!(span_openclosefacet.hasClass("values_are_updated"))) {		
 
+		disable_UI("Updating available filters...");
+		
 		span_openclosefacet.addClass("values_are_updated");	 // so that it doesn't get reloaded unless necessary
 		var facet_title = span_openclosefacet.parent();
 		span_openclosefacet.parent().next().remove();
 		
 		var ajax_url = "update_facet?activefacet=" + activefacetid + "&resulttype=" + resulttype + newurl_stub
 
-		$.get(ajax_url,
-			 { },
-				  function(data){
+		$.get(ajax_url, function(data){
 						$(facet_title).after(data); 
-			
-				  }
-	   );					
+						enable_UI();			
+				  		});		
 	}	
 	else {
 		//alert("here");

File demoproject/apps/djfacet/templates/djfacet/single_facet.html

 			{# CLICKABLE HEADER  #}
 		
 			{% if tree %}
-				<h2>{{facet.group.label}} >> {{facet.name}} >> <a href="?resulttype={{result_typeObj.uniquename}}&amp;ordering={{ordering}}{{newurl_stub}}">All</a> >>
+				<h2>{{facet.group.labe|title}} >> {{facet.name|title}} >> <a href="?resulttype={{result_typeObj.uniquename}}&amp;ordering={{ordering}}{{newurl_stub}}">All</a> >>
 					{% for v in tree %}
 						{% if not forloop.last %}
 							 <a href="?resulttype={{result_typeObj.uniquename}}&amp;ordering={{ordering}}&amp;showsubs={{v.id}}{{newurl_stub}}">{{v.name}}</a> >>  
 					{% endfor %}
 				</h2>
 			{% else %}
-				<h2>{{facet.group.label}} >> {{facet.name}} >> All </h2>
+				<h2>{{facet.group.label|title}} >> {{facet.name|title}} >> All </h2>
 			{% endif %}
 
 

File demoproject/apps/djfacet/templatetags/djf_tags.py

 					mydict[val.displayname[0]] += [val]
 	else:
 		for val in facetvalues:
+			# print "v=%s, father=%s" % (val.name, str(val.father))
+			# print "subs=%s" % (str(val.subspreview))
 			if val.displayname:
 				if val.displayname[0].upper() not in mydict.keys():
 					mydict[val.displayname[0].upper()]= [val]

File demoproject/db/djfacet_demo-23-05-2012-14-46.sql

+# ************************************************************
+# Sequel Pro SQL dump
+# Version 3408
+#
+# http://www.sequelpro.com/
+# http://code.google.com/p/sequel-pro/
+#
+# Host: 127.0.0.1 (MySQL 5.1.56)
+# Database: djfacet_demo
+# Generation Time: 2012-05-23 13:46:02 +0000
+# ************************************************************
+
+
+/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
+/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
+/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
+/*!40101 SET NAMES utf8 */;
+/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
+/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
+/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
+
+
+# Dump of table auth_group
+# ------------------------------------------------------------
+
+DROP TABLE IF EXISTS `auth_group`;
+
+CREATE TABLE `auth_group` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `name` varchar(80) NOT NULL,
+  PRIMARY KEY (`id`),
+  UNIQUE KEY `name` (`name`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+
+
+# Dump of table auth_group_permissions
+# ------------------------------------------------------------
+
+DROP TABLE IF EXISTS `auth_group_permissions`;
+
+CREATE TABLE `auth_group_permissions` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `group_id` int(11) NOT NULL,
+  `permission_id` int(11) NOT NULL,
+  PRIMARY KEY (`id`),
+  UNIQUE KEY `group_id` (`group_id`,`permission_id`),
+  KEY `auth_group_permissions_425ae3c4` (`group_id`),
+  KEY `auth_group_permissions_1e014c8f` (`permission_id`),
+  CONSTRAINT `group_id_refs_id_3cea63fe` FOREIGN KEY (`group_id`) REFERENCES `auth_group` (`id`),
+  CONSTRAINT `permission_id_refs_id_5886d21f` FOREIGN KEY (`permission_id`) REFERENCES `auth_permission` (`id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+
+
+# Dump of table auth_message
+# ------------------------------------------------------------
+
+DROP TABLE IF EXISTS `auth_message`;
+
+CREATE TABLE `auth_message` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `user_id` int(11) NOT NULL,
+  `message` longtext NOT NULL,
+  PRIMARY KEY (`id`),
+  KEY `auth_message_403f60f` (`user_id`),
+  CONSTRAINT `user_id_refs_id_650f49a6` FOREIGN KEY (`user_id`) REFERENCES `auth_user` (`id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+
+
+# Dump of table auth_permission
+# ------------------------------------------------------------
+
+DROP TABLE IF EXISTS `auth_permission`;
+
+CREATE TABLE `auth_permission` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `name` varchar(50) NOT NULL,
+  `content_type_id` int(11) NOT NULL,
+  `codename` varchar(100) NOT NULL,
+  PRIMARY KEY (`id`),
+  UNIQUE KEY `content_type_id` (`content_type_id`,`codename`),
+  KEY `auth_permission_1bb8f392` (`content_type_id`),
+  CONSTRAINT `content_type_id_refs_id_728de91f` FOREIGN KEY (`content_type_id`) REFERENCES `django_content_type` (`id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+LOCK TABLES `auth_permission` WRITE;
+/*!40000 ALTER TABLE `auth_permission` DISABLE KEYS */;
+
+INSERT INTO `auth_permission` (`id`, `name`, `content_type_id`, `codename`)
+VALUES
+	(1,'Can add permission',1,'add_permission'),
+	(2,'Can change permission',1,'change_permission'),
+	(3,'Can delete permission',1,'delete_permission'),
+	(4,'Can add group',2,'add_group'),
+	(5,'Can change group',2,'change_group'),
+	(6,'Can delete group',2,'delete_group'),
+	(7,'Can add user',3,'add_user'),
+	(8,'Can change user',3,'change_user'),
+	(9,'Can delete user',3,'delete_user'),
+	(10,'Can add message',4,'add_message'),
+	(11,'Can change message',4,'change_message'),
+	(12,'Can delete message',4,'delete_message'),
+	(13,'Can add content type',5,'add_contenttype'),
+	(14,'Can change content type',5,'change_contenttype'),
+	(15,'Can delete content type',5,'delete_contenttype'),
+	(16,'Can add session',6,'add_session'),
+	(17,'Can change session',6,'change_session'),
+	(18,'Can delete session',6,'delete_session'),
+	(19,'Can add site',7,'add_site'),
+	(20,'Can change site',7,'change_site'),
+	(21,'Can delete site',7,'delete_site'),
+	(22,'Can add log entry',8,'add_logentry'),
+	(23,'Can change log entry',8,'change_logentry'),
+	(24,'Can delete log entry',8,'delete_logentry'),
+	(25,'Can add cached facet query',9,'add_cachedfacetquery'),
+	(26,'Can change cached facet query',9,'change_cachedfacetquery'),
+	(27,'Can delete cached facet query',9,'delete_cachedfacetquery'),
+	(28,'Can add cached facet value',10,'add_cachedfacetvalue'),
+	(29,'Can change cached facet value',10,'change_cachedfacetvalue'),
+	(30,'Can delete cached facet value',10,'delete_cachedfacetvalue'),
+	(31,'Can add cached faceted manager',11,'add_cachedfacetedmanager'),
+	(32,'Can change cached faceted manager',11,'change_cachedfacetedmanager'),
+	(33,'Can delete cached faceted manager',11,'delete_cachedfacetedmanager'),
+	(34,'Can add cached html page',12,'add_cachedhtmlpage'),
+	(35,'Can change cached html page',12,'change_cachedhtmlpage'),
+	(36,'Can delete cached html page',12,'delete_cachedhtmlpage'),
+	(37,'Can add region',13,'add_region'),
+	(38,'Can change region',13,'change_region'),
+	(39,'Can delete region',13,'delete_region'),
+	(40,'Can add religion in country',14,'add_religionincountry'),
+	(41,'Can change religion in country',14,'change_religionincountry'),
+	(42,'Can delete religion in country',14,'delete_religionincountry'),
+	(43,'Can add country',15,'add_country'),
+	(44,'Can change country',15,'change_country'),
+	(45,'Can delete country',15,'delete_country'),
+	(46,'Can add religion',16,'add_religion'),
+	(47,'Can change religion',16,'change_religion'),
+	(48,'Can delete religion',16,'delete_religion');
+
+/*!40000 ALTER TABLE `auth_permission` ENABLE KEYS */;
+UNLOCK TABLES;
+
+
+# Dump of table auth_user
+# ------------------------------------------------------------
+
+DROP TABLE IF EXISTS `auth_user`;
+
+CREATE TABLE `auth_user` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `username` varchar(30) NOT NULL,
+  `first_name` varchar(30) NOT NULL,
+  `last_name` varchar(30) NOT NULL,
+  `email` varchar(75) NOT NULL,
+  `password` varchar(128) NOT NULL,
+  `is_staff` tinyint(1) NOT NULL,
+  `is_active` tinyint(1) NOT NULL,
+  `is_superuser` tinyint(1) NOT NULL,
+  `last_login` datetime NOT NULL,
+  `date_joined` datetime NOT NULL,
+  PRIMARY KEY (`id`),
+  UNIQUE KEY `username` (`username`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+LOCK TABLES `auth_user` WRITE;
+/*!40000 ALTER TABLE `auth_user` DISABLE KEYS */;
+
+INSERT INTO `auth_user` (`id`, `username`, `first_name`, `last_name`, `email`, `password`, `is_staff`, `is_active`, `is_superuser`, `last_login`, `date_joined`)
+VALUES
+	(1,'mpasin','','','mik@mac.com','sha1$33bbf$715bf51dc2d4768115132e413f6acadec1a83da2',1,1,1,'2012-05-23 11:57:48','2012-01-09 15:47:03'),
+	(2,'test','','','','sha1$c7967$d90c09d9cd81a305d3eb7d65b88ba443b94caa13',1,1,1,'2012-05-23 11:58:16','2012-05-23 11:58:16');
+
+/*!40000 ALTER TABLE `auth_user` ENABLE KEYS */;
+UNLOCK TABLES;
+
+
+# Dump of table auth_user_groups
+# ------------------------------------------------------------
+
+DROP TABLE IF EXISTS `auth_user_groups`;
+
+CREATE TABLE `auth_user_groups` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `user_id` int(11) NOT NULL,
+  `group_id` int(11) NOT NULL,
+  PRIMARY KEY (`id`),
+  UNIQUE KEY `user_id` (`user_id`,`group_id`),
+  KEY `auth_user_groups_403f60f` (`user_id`),
+  KEY `auth_user_groups_425ae3c4` (`group_id`),
+  CONSTRAINT `group_id_refs_id_f116770` FOREIGN KEY (`group_id`) REFERENCES `auth_group` (`id`),
+  CONSTRAINT `user_id_refs_id_7ceef80f` FOREIGN KEY (`user_id`) REFERENCES `auth_user` (`id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+
+
+# Dump of table auth_user_user_permissions
+# ------------------------------------------------------------
+
+DROP TABLE IF EXISTS `auth_user_user_permissions`;
+
+CREATE TABLE `auth_user_user_permissions` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `user_id` int(11) NOT NULL,
+  `permission_id` int(11) NOT NULL,
+  PRIMARY KEY (`id`),
+  UNIQUE KEY `user_id` (`user_id`,`permission_id`),
+  KEY `auth_user_user_permissions_403f60f` (`user_id`),
+  KEY `auth_user_user_permissions_1e014c8f` (`permission_id`),
+  CONSTRAINT `permission_id_refs_id_67e79cb` FOREIGN KEY (`permission_id`) REFERENCES `auth_permission` (`id`),
+  CONSTRAINT `user_id_refs_id_dfbab7d` FOREIGN KEY (`user_id`) REFERENCES `auth_user` (`id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+
+
+# Dump of table django_admin_log
+# ------------------------------------------------------------
+
+DROP TABLE IF EXISTS `django_admin_log`;
+
+CREATE TABLE `django_admin_log` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `action_time` datetime NOT NULL,
+  `user_id` int(11) NOT NULL,
+  `content_type_id` int(11) DEFAULT NULL,
+  `object_id` longtext,
+  `object_repr` varchar(200) NOT NULL,
+  `action_flag` smallint(5) unsigned NOT NULL,
+  `change_message` longtext NOT NULL,
+  PRIMARY KEY (`id`),
+  KEY `django_admin_log_403f60f` (`user_id`),
+  KEY `django_admin_log_1bb8f392` (`content_type_id`),
+  CONSTRAINT `content_type_id_refs_id_288599e6` FOREIGN KEY (`content_type_id`) REFERENCES `django_content_type` (`id`),
+  CONSTRAINT `user_id_refs_id_c8665aa` FOREIGN KEY (`user_id`) REFERENCES `auth_user` (`id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+LOCK TABLES `django_admin_log` WRITE;
+/*!40000 ALTER TABLE `django_admin_log` DISABLE KEYS */;
+
+INSERT INTO `django_admin_log` (`id`, `action_time`, `user_id`, `content_type_id`, `object_id`, `object_repr`, `action_flag`, `change_message`)
+VALUES
+	(1,'2012-01-12 14:56:29',1,13,'43','Region ID: 43',3,''),
+	(2,'2012-01-12 14:58:27',1,13,'50','Region: Arctic Region',3,''),
+	(3,'2012-01-12 15:03:15',1,13,'51','Region: Asia, Europe',3,''),
+	(4,'2012-01-12 15:03:21',1,13,'35','Region: Asia, Europe',2,'Changed name.'),
+	(5,'2012-01-12 15:05:48',1,13,'47','Region: Oceania',3,''),
+	(6,'2012-01-12 15:06:22',1,13,'49','Region: World',3,''),
+	(7,'2012-01-12 15:07:38',1,13,'40','Region: Sub-saharan africa',2,'Changed name.'),
+	(8,'2012-01-12 15:09:02',1,13,'42','Region: South America',3,''),
+	(9,'2012-01-12 15:38:49',1,16,'152','Religion: (Orthodox',3,''),
+	(10,'2012-01-12 15:41:24',1,16,'164','Religion: Orthodox Church',3,''),
+	(11,'2012-01-12 15:46:04',1,16,'234','Religion: Maronite Catholic',2,'Changed name.'),
+	(12,'2012-01-12 15:47:03',1,16,'52','Religion: Roman Catholic (less than practicing)',2,'Changed name.'),
+	(13,'2012-01-12 15:49:11',1,16,'58','Religion: Muslim (Shia and Sunni)',2,'Changed name.'),
+	(14,'2012-01-12 15:50:48',1,16,'39','Religion: Protestant (various denominations including Reformate and Pentecostal)',2,'Changed name.'),
+	(15,'2012-01-12 15:51:33',1,16,'203','Religion: Protestant (Seventh-Day Adventist and Protestant denominations)',2,'Changed name.'),
+	(16,'2012-01-12 15:54:17',1,16,'172','Religion: Pentecostal/Charismatic',2,'Changed name.'),
+	(17,'2012-01-12 15:59:06',1,16,'231','Religion: other (2005 census)',2,'Changed name.'),
+	(18,'2012-01-12 16:01:17',1,16,'46','Religion: none or unspecified',2,'Changed name.'),
+	(19,'2012-04-25 00:56:23',1,16,'359','aaa (Sunni Muslim)',1,''),
+	(20,'2012-04-25 00:56:33',1,16,'359','aaa (Sunni Muslim)',3,''),
+	(21,'2012-04-25 01:04:02',1,16,'360','Muslim',1,''),
+	(22,'2012-04-25 01:05:51',1,16,'233','Muslim (Shia, Sunni, Druze, Isma\'ilite, Alawite, or Nusayri) (Muslim)',2,'Changed parent.'),
+	(23,'2012-04-25 01:06:28',1,16,'358','Muslim and other (Muslim)',2,'Changed parent.'),
+	(24,'2012-04-25 01:06:38',1,16,'356','Muslim and Hindu (Muslim)',2,'Changed parent.'),
+	(25,'2012-04-25 01:06:45',1,16,'314','other Muslim (includes Alawite (Muslim)',2,'Changed parent.'),
+	(26,'2012-04-25 01:06:56',1,16,'277','other (includes Sunni Muslim (Muslim)',2,'Changed parent.'),
+	(27,'2012-04-25 01:07:04',1,16,'276','Muslim, Ibadhi  (Muslim)',2,'Changed parent.'),
+	(28,'2012-04-25 01:15:06',1,16,'361','Catholic',1,''),
+	(29,'2012-04-25 01:21:15',1,16,'362','Protestant',1,''),
+	(30,'2012-04-25 01:25:01',1,16,'320','Mixture of Buddhist and Taoist',2,'Changed name.'),
+	(31,'2012-04-25 01:28:01',1,16,'363','Ukranian Orthodox (Orthodox)',1,''),
+	(32,'2012-04-25 01:35:29',1,16,'105','Christian Baptist (Christian)',2,'Changed name.'),
+	(33,'2012-04-25 01:36:34',1,16,'230','Parsi',2,'Changed name.'),
+	(34,'2012-04-25 01:41:18',1,16,'194','Baha\'i',2,'Changed name.'),
+	(35,'2012-04-25 01:42:15',1,16,'120','atheist or agnostic',2,'Changed name.'),
+	(36,'2012-05-03 10:56:11',1,16,'319','Aleppo',2,'Changed name.'),
+	(37,'2012-05-03 11:16:24',1,16,'106','Animist',2,'Changed name.'),
+	(38,'2012-05-03 11:16:32',1,16,'46','None or unspecified',2,'Changed name.'),
+	(39,'2012-05-03 11:34:58',1,16,'56','Yezidi',2,'Changed name.'),
+	(40,'2012-05-03 11:37:22',1,16,'86','Celestial Church of Christ',2,'Changed name.'),
+	(41,'2012-05-03 11:38:04',1,16,'87','Voudou',2,'Changed name.'),
+	(42,'2012-05-03 11:41:56',1,16,'133','Santeria',2,'Changed name.'),
+	(43,'2012-05-03 11:48:39',1,16,'116','non-denominational (Christian)',2,'Changed parent.'),
+	(44,'2012-05-03 11:49:17',1,16,'124','Kimbanguist (Christian)',2,'Changed parent.'),
+	(45,'2012-05-03 11:49:51',1,16,'128','Church of Latter Day Saints (Christian)',2,'Changed parent.'),
+	(46,'2012-05-03 12:05:32',1,16,'144','Mormon (Church of Latter Day Saints, Christian)',2,'Changed parent.'),
+	(47,'2012-05-03 12:06:41',1,16,'158','Assembly of God (Pentecostal)',2,'Changed parent.'),
+	(48,'2012-05-03 12:07:06',1,16,'160','Arya Samaj (Hindu)',2,'Changed parent.'),
+	(49,'2012-05-03 12:07:47',1,16,'170','Armenian-Gregorian (Armenian Apostolic, Orthodox)',2,'Changed parent.'),
+	(50,'2012-05-03 12:08:09',1,16,'176','Presbyterian (Protestant)',2,'Changed parent.'),
+	(51,'2012-05-03 12:08:40',1,16,'177','Congregational (Protestant)',2,'Changed parent.'),
+	(52,'2012-05-03 12:09:04',1,16,'180','Seventh-day Adventist Church (Protestant)',2,'Changed name and parent.'),
+	(53,'2012-05-03 12:09:24',1,16,'181','Calvinist (Protestant)',2,'Changed parent.'),
+	(54,'2012-05-03 12:10:36',1,16,'300','New Apostolic (Protestant)',2,'Changed parent.'),
+	(55,'2012-05-03 12:11:29',1,16,'289','Aglipayan (Catholic)',2,'Changed parent.'),
+	(56,'2012-05-03 12:12:18',1,16,'288','Iglesia ni Kristo (indigenous beliefs)',2,'Changed parent.'),
+	(57,'2012-05-03 12:12:39',1,16,'240','Copt (Christian)',2,'Changed parent.'),
+	(58,'2012-05-03 12:13:45',1,16,'238','Chaldean (pagan practices)',2,'Changed parent.'),
+	(59,'2012-05-03 12:14:50',1,16,'228','Shia (Muslim)',2,'Changed parent.'),
+	(60,'2012-05-03 12:15:06',1,16,'220','Latter-day Saints (Church of Latter Day Saints, Christian)',2,'Changed parent.'),
+	(61,'2012-05-03 12:15:37',1,16,'219','Bahá\'í Faith',2,'Changed name.'),
+	(62,'2012-05-03 12:16:02',1,16,'210','Congregational New Church (Protestant -Congregational-, Protestant)',2,'Changed parent.'),
+	(63,'2012-05-03 12:16:53',1,16,'194','Bahá\'í Faith',2,'Changed name.'),
+	(64,'2012-05-03 12:17:48',1,16,'192','Sunni (Muslim)',2,'Changed parent.'),
+	(65,'2012-05-03 12:18:16',1,16,'188','Sikhism',2,'Changed name.'),
+	(66,'2012-05-03 14:51:05',1,16,'314','Alawite (Muslim)',2,'Changed name.'),
+	(67,'2012-05-03 14:51:46',1,16,'276','Ibadhi  (Muslim)',2,'Changed name.'),
+	(68,'2012-05-03 14:52:30',1,16,'222','Buddhist and Confucianist (Buddhist)',2,'Changed name.'),