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. |     Input renderer for numeric values. | ||||||
|     """ |     """ | ||||||
|     # TODO |     data_type = 'number' | ||||||
|     # data_type = 'number' |  | ||||||
| 
 | 
 | ||||||
|     def render(self, value=None, **kwargs): |     def render(self, value=None, **kwargs): | ||||||
|         kwargs.setdefault('step', '0.001') |         kwargs.setdefault('step', '0.001') | ||||||
|  | @ -137,6 +136,7 @@ class GridFilter(object): | ||||||
|         'less_equal':           "less than or equal to", |         'less_equal':           "less than or equal to", | ||||||
|         'is_empty':             "is empty", |         'is_empty':             "is empty", | ||||||
|         'is_not_empty':         "is not empty", |         'is_not_empty':         "is not empty", | ||||||
|  |         'between':              "between", | ||||||
|         'is_null':              "is null", |         'is_null':              "is null", | ||||||
|         'is_not_null':          "is not null", |         'is_not_null':          "is not null", | ||||||
|         'is_true':              "is true", |         'is_true':              "is true", | ||||||
|  | @ -378,6 +378,47 @@ class AlchemyGridFilter(GridFilter): | ||||||
|             return query |             return query | ||||||
|         return query.filter(self.column <= self.encode_value(value)) |         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): | class AlchemyStringFilter(AlchemyGridFilter): | ||||||
|     """ |     """ | ||||||
|  | @ -532,7 +573,8 @@ class AlchemyNumericFilter(AlchemyGridFilter): | ||||||
| 
 | 
 | ||||||
|     # expose greater-than / less-than verbs in addition to core |     # expose greater-than / less-than verbs in addition to core | ||||||
|     default_verbs = ['equal', 'not_equal', 'greater_than', 'greater_equal', |     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 |     # 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 |     # user's perspective it still fails silently...need to improve on front-end | ||||||
|  | @ -541,6 +583,13 @@ class AlchemyNumericFilter(AlchemyGridFilter): | ||||||
|     # term for integer field... |     # term for integer field... | ||||||
| 
 | 
 | ||||||
|     def value_invalid(self, value): |     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) |         return bool(value and len(six.text_type(value)) > 8) | ||||||
| 
 | 
 | ||||||
|     def filter_equal(self, query, value): |     def filter_equal(self, query, value): | ||||||
|  | @ -726,6 +775,7 @@ class AlchemyDateFilter(AlchemyGridFilter): | ||||||
|             return query |             return query | ||||||
|         return query.filter(self.column <= self.encode_value(date)) |         return query.filter(self.column <= self.encode_value(date)) | ||||||
| 
 | 
 | ||||||
|  |     # TODO: this should be merged into parent class | ||||||
|     def filter_between(self, query, value): |     def filter_between(self, query, value): | ||||||
|         """ |         """ | ||||||
|         Filter data with a "between" query.  Really this uses ">=" and "<=" |         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) |         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): |     def filter_date_range(self, query, start_date, end_date): | ||||||
|         """ |         """ | ||||||
|         This method should actually apply filter(s) to the query, according to |         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 = { | const GridFilterDateValue = { | ||||||
|     template: '#grid-filter-date-value-template', |     template: '#grid-filter-date-value-template', | ||||||
|     props: { |     props: { | ||||||
|  |  | ||||||
|  | @ -1,5 +1,29 @@ | ||||||
| ## -*- coding: utf-8; -*- | ## -*- 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"> | <script type="text/x-template" id="grid-filter-date-value-template"> | ||||||
|   <div class="level"> |   <div class="level"> | ||||||
|     <div class="level-left"> |     <div class="level-left"> | ||||||
|  | @ -75,6 +99,13 @@ | ||||||
|           </option> |           </option> | ||||||
|         </b-select> |         </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()" |         <b-input v-if="filter.data_type == 'string' && !multiValuedVerb()" | ||||||
|                  v-model="filter.value" |                  v-model="filter.value" | ||||||
|                  v-show="valuedVerb()" |                  v-show="valuedVerb()" | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Lance Edgar
						Lance Edgar