def clean(self): self.qtable_list = None if filter(None, [not f.is_valid() for f in self.forms]): return qt_by_name = {} # Dictionary of name -> [ QTable list ] n_display = 0 for form in self.forms: if form.cleaned_data['display']: n_display += 1 # Gather a list of QTables (qtable_list) involved, and check for naming collision if form.cleaned_data['source'] != 'table': continue curr = form.qtable qt_list = qt_by_name.get(curr.name, []) for qt in qt_list: # Error if a table has alias but another doesn't. (Tables with the same name.) if bool(curr.alias) ^ bool(qt.alias): raise forms.ValidationError( 'Ambiguous table "%s" without alias' % (qt.name, )) if curr.alias == qt.alias: # Duplicate. Don't update. break else: qt_list.append(curr) qt_by_name[curr.name] = qt_list self.qtable_list = sum([tbl_list for tbl_list in qt_by_name.values()], []) if not self.qtable_list: raise forms.ValidationError('Not selecting from any table column') if n_display == 0: raise forms.ValidationError('Not displaying any selection')
def clean(self): self.qtable = None self.selection = None self._display_check() if self.cleaned_data.get('sort') and not self.cleaned_data['sort_hql']: raise KeyError() # Verify that the 'source' field is consistent with the other fields source = self.cleaned_data.get('source') if not source: return None # No point since we can't get source constant_val = self.cleaned_data.get('constant') _field_source_check(source, 'Constant', constant_val, is_from_table=False) table_val = self.cleaned_data.get('table') _field_source_check(source, 'From table', table_val, is_from_table=True) col_val = self.cleaned_data.get('col') _field_source_check(source, 'From column', col_val, is_from_table=True) if self.cleaned_data.get( 'sort', '') and not self.cleaned_data.get('sort_order', ''): raise forms.ValidationError('Sort order missing') if table_val: # Column must belong to the table self.qtable = report_gen.QTable( table_val, self.cleaned_data.get('table_alias')) if col_val == '*': if self.cleaned_data.get('col_alias'): raise forms.ValidationError( 'Alias not applicable for selecting "*"') elif col_val not in self.qtable.get_columns(): raise forms.ValidationError('Invalid column name "%s"' % (col_val, )) # ColumnSelection object self.selection = report_gen.ColumnSelection( self.qtable, col_val, self.cleaned_data.get('col_alias')) else: # ConstSelection object self.selection = report_gen.ConstSelection( constant_val, self.cleaned_data.get('col_alias')) self.selection.distinct = self.cleaned_data.get('distinct', False) self.selection.set_aggregation(self.cleaned_data.get('agg', '')) if self.errors: delattr(self, 'selection') return self.cleaned_data
def clean(self): if self.errors: return # Verify unary operators constraints check_right = True op = self.cleaned_data['op'] if op in common.RELATION_OPS_UNARY: if self.cleaned_data.get('r_source') or self.cleaned_data.get( 'r_cond'): raise forms.ValidationError( 'Operator %s does not take the right operand' % (op, )) check_right = False else: if not self.cleaned_data.get( 'l_source') or not self.cleaned_data.get('r_source'): raise forms.ValidationError('Operator %s takes both operands' % (op, )) # Verify the lhs values match the source l_source = self.cleaned_data['l_source'] l_constant = self.cleaned_data.get('l_constant') _field_source_check(l_source, 'Constant (Left)', l_constant, is_from_table=False) l_table = self.cleaned_data.get('l_table') _field_source_check(l_source, 'Table (Left)', l_table, is_from_table=True) l_col = self.cleaned_data.get('l_col') _field_source_check(l_source, 'Column (Left)', l_col, is_from_table=True) if check_right: # Verify the rhs values match the source r_source = self.cleaned_data['r_source'] r_constant = self.cleaned_data.get('r_constant') _field_source_check(r_source, 'Constant (Right)', r_constant, is_from_table=False) r_table = self.cleaned_data.get('r_table') _field_source_check(r_source, 'Table (Right)', r_table, is_from_table=True) r_col = self.cleaned_data.get('r_col') _field_source_check(r_source, 'Column (Right)', r_col, is_from_table=True) return self.cleaned_data
def _display_check(self): """Reconcile 'display' with 'source'""" src = self.cleaned_data.get('source') if not self.cleaned_data.get('display'): if src and src != 'table': raise forms.ValidationError( 'Source must be "table" when not displaying column') self.cleaned_data['source'] = 'table' if self.cleaned_data.get('col_alias'): raise forms.ValidationError( 'Column alias not applicable when not displaying column') else: if not src: raise forms.ValidationError('Source value missing')
def _field_source_check(true_source, field_name, field_value, is_from_table): """ Some fields come from a table (is_from_table). And they should be specified iff the true_source (what the user selected) says "table". The same holds for constant source. This function verifies that constraint and would raise ValidationError. Returns whether this field is required. """ if bool(true_source == 'table') ^ bool(is_from_table): if field_value: raise forms.ValidationError( '%s value not applicable with %s source' % (field_name, true_source)) return False elif not field_value: raise forms.ValidationError('%s value missing' % (field_name, )) return True
def fixup_union(parent_mform, subform_name, data, is_root=False): """ Create child union mforms dynamically. Note that the parent_mform may be invalid. The parent_mform is a MultiForm, in which the subform_name is a UnionMultiForm we need to fix. This method performs this dynamic construction of the child UnionMultiForm. Note that it applies to existing child forms (i.e. the child form exists and the user is submitting the query), as well as a newly added child (i.e. the user just clicked 'ADD' to add a sub-condition). We figure out the number of children from the mgmt form. Note that this is actually a count of the number of children we have ever had. It is a max of the number of children, some of which may have been deleted. For each child <i>, our strategy is to test if 'sub<i>' exists in the POST data. If so, we create a sub-UnionMultiForm for that child. And we do it recursively. """ global SUB_UNION_PREFIX union_mform = getattr(parent_mform, subform_name) mgmt_form = union_mform.mgmt if not mgmt_form.is_valid(): raise forms.ValidationError('Missing ManagementForm for conditions') n_children = mgmt_form.form_counts() # This removes our current subform (union_mform) and any children. if mgmt_form.cleaned_data['remove']: parent_mform.remove_subform(subform_name) LOG.debug('Removed subform: %s' % (union_mform, )) # If we just removed the root union, add back an empty one. if is_root: parent_mform.add_subform('union', UnionMultiForm, data=None) LOG.debug('Adding root union back') return # Note that some of the n_children could be non-existent (i.e. deleted) for i in range(0, n_children): child_name = '%s%d' % (SUB_UNION_PREFIX, i) if not union_mform.has_subform_data(child_name, data): LOG.debug('Skipping over non-existent subform: %s %s' % (union_mform, child_name)) continue union_mform.add_subform(child_name, UnionMultiForm, data) LOG.debug('Instantiating subform: %s %s' % (union_mform, child_name)) # The child may have grand-children fixup_union(union_mform, child_name, data) if mgmt_form.cleaned_data['add']: id = mgmt_form.new_form_id() child_name = '%s%d' % (SUB_UNION_PREFIX, id) union_mform.add_subform(child_name, UnionMultiForm) LOG.debug('Added subform: %s %s' % (union_mform, child_name))
def _make_selection(self, table_alias_dict, is_left): if is_left: prefix = 'l_' else: prefix = 'r_' source = self.cleaned_data[prefix + 'source'] if source == 'table': table = self.cleaned_data[prefix + 'table'] col = self.cleaned_data[prefix + 'col'] try: return report_gen.ColumnSelection(table_alias_dict[table], col) except KeyError: raise forms.ValidationError('Unknown table "%s" in condition' % (table, )) constant = self.cleaned_data[prefix + 'constant'] return report_gen.ConstSelection(constant)