def handle (self, *args, **options): session.bind.echo = options['debug'] filepath = options['filepath'] model_info = {} with open(filepath, 'r') as data_file: content = ''.join(line.split('//')[0] for line in data_file) full_data = json.loads(content, object_pairs_hook = OrderedDict) for data_block in full_data: Model = get_model(data_block['application'], data_block['Model']) unique_indexes = {} # Prepare indeces of unique-constraints. for table in Model.__mapper__.tables: for constraint in table.constraints: if isinstance(constraint, UniqueConstraint): unique_indexes[constraint] = set() for datum in data_block['data']: datum = prepare(session, Model, datum) update_target = None for constraint, index in unique_indexes.items(): # Look for item in index. key = key_from_constraint(constraint, datum) if key in index: self.stderr.write("ERROR: Second import of '{}' " + "record with unique constraint:".format(Model)) for column, value in zip(constraint.columns, key): self.stderr.write(" {} = {}".format( column, value)) return # Look for item in database. target = session.query(Model).filter( *filter_from_constraint(constraint, datum)).scalar() if update_target and update_target != target: self.stderr.write('ERROR: Second unique-index match does not yield the same model.') self.stderr.write(" Model: {}".format(Model)) self.stderr.write(" constraint: {}".format(constraint)) self.stderr.write(" data: {}".format(datum)) return update_target = target if update_target: updated = False for field, value in datum.items(): if getattr(update_target, field) != value: updated = True setattr(update_target, field, value) if updated: self.stdout.write("updating {}".format(update_target)) else: model = Model(**datum) session.add(model) self.stdout.write("adding {}".format(model)) session.flush() session.commit()
def update_character_summary (request, id): character = session.query(Character).get(int(id)) response = storyteller_or_editing_owner(request, character, 'edit') if response: return response chronicle_ids = [c.id for c in character.chronicle.all_chronicles] affected_traits = set() data = json.loads(request.body.decode('ascii')) for key, value in data.items(): column = Character.__table__.columns[key] if len(column.foreign_keys) == 0: old_value = getattr(character, key) new_value = value # TODO (Emery): Check rules for character_summary attributes. (Name, last_edited, ...) else: TraitType = get_referenced_model(column) key = key[:-3] # assumes key in format "<key>_id" old_value = getattr(character, key) new_value = None if value is None else session.query(TraitType).get(value) if old_value: changing_trait_ids = (old_value.id,) else: changing_trait_ids = tuple() if new_value: changing_trait_ids += (new_value.id,) # Rule: character-has-trait for rule in session.query(CharacterHasTrait).filter( CharacterHasTrait.chronicle_id.in_(chronicle_ids), CharacterHasTrait.other_trait_id.in_(changing_trait_ids) ): affected_traits.add(rule.trait) # Rule: character-does-not-have-trait for rule in session.query(CharacterDoesNotHaveTrait).filter( CharacterDoesNotHaveTrait.chronicle_id.in_(chronicle_ids), CharacterDoesNotHaveTrait.other_trait_id.in_(changing_trait_ids) ): affected_traits.add(rule.trait) # Set attribute on character. setattr(character, key, new_value) session.flush() # Recalculate availabilities for affected traits. availabilities = calculate_availabilities(character, affected_traits) return JsonResponse( { 'character': character, 'availabilities': availabilities, }, encoder = ModelEncoder )