Add "between" verb for numeric grid filters
This commit is contained in:
		
							parent
							
								
									3e8924e7cc
								
							
						
					
					
						commit
						deed2111fb
					
				
					 3 changed files with 134 additions and 3 deletions
				
			
		|  | @ -76,8 +76,7 @@ class NumericValueRenderer(FilterValueRenderer): | |||
|     """ | ||||
|     Input renderer for numeric values. | ||||
|     """ | ||||
|     # TODO | ||||
|     # data_type = 'number' | ||||
|     data_type = 'number' | ||||
| 
 | ||||
|     def render(self, value=None, **kwargs): | ||||
|         kwargs.setdefault('step', '0.001') | ||||
|  | @ -137,6 +136,7 @@ class GridFilter(object): | |||
|         'less_equal':           "less than or equal to", | ||||
|         'is_empty':             "is empty", | ||||
|         'is_not_empty':         "is not empty", | ||||
|         'between':              "between", | ||||
|         'is_null':              "is null", | ||||
|         'is_not_null':          "is not null", | ||||
|         'is_true':              "is true", | ||||
|  | @ -378,6 +378,47 @@ class AlchemyGridFilter(GridFilter): | |||
|             return query | ||||
|         return query.filter(self.column <= self.encode_value(value)) | ||||
| 
 | ||||
|     def filter_between(self, query, value): | ||||
|         """ | ||||
|         Filter data with a "between" query.  Really this uses ">=" and | ||||
|         "<=" (inclusive) logic instead of SQL "between" keyword. | ||||
|         """ | ||||
|         if value is None or value == '': | ||||
|             return query | ||||
| 
 | ||||
|         if '|' not in value: | ||||
|             return query | ||||
| 
 | ||||
|         values = value.split('|') | ||||
|         if len(values) != 2: | ||||
|             return query | ||||
| 
 | ||||
|         start_value, end_value = values | ||||
| 
 | ||||
|         # we'll only filter if we have start and/or end value | ||||
|         if not start_value and not end_value: | ||||
|             return query | ||||
| 
 | ||||
|         return self.filter_for_range(query, start_value, end_value) | ||||
| 
 | ||||
|     def filter_for_range(self, query, start_value, end_value): | ||||
|         """ | ||||
|         This method should actually apply filter(s) to the query, | ||||
|         according to the given value range.  Subclasses may override | ||||
|         this logic. | ||||
|         """ | ||||
|         if start_value: | ||||
|             if self.value_invalid(start_value): | ||||
|                 return query | ||||
|             query = query.filter(self.column >= start_value) | ||||
| 
 | ||||
|         if end_value: | ||||
|             if self.value_invalid(end_value): | ||||
|                 return query | ||||
|             query = query.filter(self.column <= end_value) | ||||
| 
 | ||||
|         return query | ||||
| 
 | ||||
| 
 | ||||
| class AlchemyStringFilter(AlchemyGridFilter): | ||||
|     """ | ||||
|  | @ -532,7 +573,8 @@ class AlchemyNumericFilter(AlchemyGridFilter): | |||
| 
 | ||||
|     # expose greater-than / less-than verbs in addition to core | ||||
|     default_verbs = ['equal', 'not_equal', 'greater_than', 'greater_equal', | ||||
|                      'less_than', 'less_equal', 'is_null', 'is_not_null', 'is_any'] | ||||
|                      'less_than', 'less_equal', 'between', | ||||
|                      'is_null', 'is_not_null', 'is_any'] | ||||
| 
 | ||||
|     # TODO: what follows "works" in that it prevents an error...but from the | ||||
|     # user's perspective it still fails silently...need to improve on front-end | ||||
|  | @ -541,6 +583,13 @@ class AlchemyNumericFilter(AlchemyGridFilter): | |||
|     # term for integer field... | ||||
| 
 | ||||
|     def value_invalid(self, value): | ||||
| 
 | ||||
|         # first just make sure it's somewhat numeric | ||||
|         try: | ||||
|             float(value) | ||||
|         except ValueError: | ||||
|             return True | ||||
| 
 | ||||
|         return bool(value and len(six.text_type(value)) > 8) | ||||
| 
 | ||||
|     def filter_equal(self, query, value): | ||||
|  | @ -726,6 +775,7 @@ class AlchemyDateFilter(AlchemyGridFilter): | |||
|             return query | ||||
|         return query.filter(self.column <= self.encode_value(date)) | ||||
| 
 | ||||
|     # TODO: this should be merged into parent class | ||||
|     def filter_between(self, query, value): | ||||
|         """ | ||||
|         Filter data with a "between" query.  Really this uses ">=" and "<=" | ||||
|  | @ -753,6 +803,7 @@ class AlchemyDateFilter(AlchemyGridFilter): | |||
| 
 | ||||
|         return self.filter_date_range(query, start_date, end_date) | ||||
| 
 | ||||
|     # TODO: this should be merged into parent class | ||||
|     def filter_date_range(self, query, start_date, end_date): | ||||
|         """ | ||||
|         This method should actually apply filter(s) to the query, according to | ||||
|  |  | |||
|  | @ -1,4 +1,53 @@ | |||
| 
 | ||||
| const GridFilterNumericValue = { | ||||
|     template: '#grid-filter-numeric-value-template', | ||||
|     props: { | ||||
|         value: String, | ||||
|         wantsRange: Boolean, | ||||
|     }, | ||||
|     data() { | ||||
|         return { | ||||
|             startValue: null, | ||||
|             endValue: null, | ||||
|         } | ||||
|     }, | ||||
|     mounted() { | ||||
|         if (this.wantsRange) { | ||||
|             if (this.value.includes('|')) { | ||||
|                 let values = this.value.split('|') | ||||
|                 if (values.length == 2) { | ||||
|                     this.startValue = values[0] | ||||
|                     this.endValue = values[1] | ||||
|                 } else { | ||||
|                     this.startValue = this.value | ||||
|                 } | ||||
|             } else { | ||||
|                 this.startValue = this.value | ||||
|             } | ||||
|         } else { | ||||
|             this.startValue = this.value | ||||
|         } | ||||
|     }, | ||||
|     methods: { | ||||
|         focus() { | ||||
|             this.$refs.startValue.focus() | ||||
|         }, | ||||
|         startValueChanged(value) { | ||||
|             if (this.wantsRange) { | ||||
|                 value += '|' + this.endValue | ||||
|             } | ||||
|             this.$emit('input', value) | ||||
|         }, | ||||
|         endValueChanged(value) { | ||||
|             value = this.startValue + '|' + value | ||||
|             this.$emit('input', value) | ||||
|         }, | ||||
|     }, | ||||
| } | ||||
| 
 | ||||
| Vue.component('grid-filter-numeric-value', GridFilterNumericValue) | ||||
| 
 | ||||
| 
 | ||||
| const GridFilterDateValue = { | ||||
|     template: '#grid-filter-date-value-template', | ||||
|     props: { | ||||
|  |  | |||
|  | @ -1,5 +1,29 @@ | |||
| ## -*- coding: utf-8; -*- | ||||
| 
 | ||||
| <script type="text/x-template" id="grid-filter-numeric-value-template"> | ||||
|   <div class="level"> | ||||
|     <div class="level-left"> | ||||
|       <div class="level-item"> | ||||
|         <b-input v-model="startValue" | ||||
|                  ref="startValue" | ||||
|                  @input="startValueChanged"> | ||||
|         </b-input> | ||||
|       </div> | ||||
|       <div v-show="wantsRange" | ||||
|            class="level-item"> | ||||
|         and | ||||
|       </div> | ||||
|       <div v-show="wantsRange" | ||||
|            class="level-item"> | ||||
|         <b-input v-model="endValue" | ||||
|                  ref="endValue" | ||||
|                  @input="endValueChanged"> | ||||
|         </b-input> | ||||
|       </div> | ||||
|     </div> | ||||
|   </div> | ||||
| </script> | ||||
| 
 | ||||
| <script type="text/x-template" id="grid-filter-date-value-template"> | ||||
|   <div class="level"> | ||||
|     <div class="level-left"> | ||||
|  | @ -75,6 +99,13 @@ | |||
|           </option> | ||||
|         </b-select> | ||||
| 
 | ||||
|         <grid-filter-numeric-value v-if="filter.data_type == 'number'" | ||||
|                                   v-model="filter.value" | ||||
|                                   v-show="valuedVerb()" | ||||
|                                   :wants-range="filter.verb == 'between'" | ||||
|                                   ref="valueInput"> | ||||
|         </grid-filter-numeric-value> | ||||
| 
 | ||||
|         <b-input v-if="filter.data_type == 'string' && !multiValuedVerb()" | ||||
|                  v-model="filter.value" | ||||
|                  v-show="valuedVerb()" | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Lance Edgar
						Lance Edgar