def use(object: TrackedModel, new_data: Callable[[TrackedModel], dict[str, Any]]): model = type(object) versions = set( model.objects.filter(**object.get_identifying_fields()).values_list( "pk", flat=True, ), ) # Visit the edit page and ensure it is a success edit_url = object.get_url("edit") assert edit_url, f"No edit page found for {object}" response = valid_user_api_client.get(edit_url) assert response.status_code == 200 # Get the data out of the edit page # and override it with any data that has been passed in data = get_form_data(response.context_data["form"]) # Submit the edited data and if we expect success ensure we are redirected realised_data = new_data(object) assert set(realised_data.keys()).issubset(data.keys()) data.update(realised_data) response = valid_user_api_client.post(edit_url, data) # Check that if we expect failure that the new data was not persisted if response.status_code not in (301, 302): assert ( set( model.objects.filter(**object.get_identifying_fields()).values_list( "pk", flat=True, ), ) == versions ) raise ValidationError( f"Update form contained errors: {response.context_data['form'].errors}", ) # Check that what we asked to be changed has been persisted response = valid_user_api_client.get(edit_url) assert response.status_code == 200 data = get_form_data(response.context_data["form"]) for key in realised_data: assert data[key] == realised_data[key] # Check that if success was expected that the new version was persisted new_version = model.objects.exclude(pk=object.pk).get( version_group=object.version_group, ) assert new_version != object # Check that the new version is an update and is not approved yet assert new_version.update_type == UpdateType.UPDATE assert new_version.transaction != object.transaction assert not new_version.transaction.workbasket.approved return new_version
def use(object: TrackedModel): model = type(object) versions = set( model.objects.filter(**object.get_identifying_fields()).values_list( "pk", flat=True, ), ) # Visit the delete page and ensure it is a success delete_url = object.get_url("delete") assert delete_url, f"No delete page found for {object}" response = valid_user_api_client.get(delete_url) assert response.status_code == 200 # Get the data out of the delete page data = get_form_data(response.context_data["form"]) response = valid_user_api_client.post(delete_url, data) # Check that if we expect failure that the new data was not persisted if response.status_code not in (301, 302): assert ( set( model.objects.filter(**object.get_identifying_fields()).values_list( "pk", flat=True, ), ) == versions ) raise ValidationError( f"Delete form contained errors: {response.context_data['form'].errors}", ) # Check that the delete persisted and we can't delete again response = valid_user_api_client.get(delete_url) assert response.status_code == 404 # Check that if success was expected that the new version was persisted new_version = model.objects.exclude(pk=object.pk).get( version_group=object.version_group, ) assert new_version != object # Check that the new version is a delete and is not approved yet assert new_version.update_type == UpdateType.DELETE assert new_version.transaction != object.transaction assert not new_version.transaction.workbasket.approved return new_version
def cache_object(self, obj: TrackedModel): """ Caches an objects primary key and model name in the cache. Key is generated based on the model name and the identifying fields used to find it. """ model = obj.__class__ link_fields = self.get_handler_link_fields(model) for identifying_fields in link_fields: cache_key = self.generate_cache_key( model, identifying_fields, obj.get_identifying_fields(identifying_fields), ) cache.set(cache_key, (obj.pk, model.__name__), timeout=None)
def remove_object_from_cache(self, obj: TrackedModel): """ Removes an object from the importer cache. If an object has to be deleted (generally done in dev only) then it is problematic to keep the ID in the cache as well. Key is generated based on the model name and the identifying fields used to find it. """ model = obj.__class__ link_fields = self.get_handler_link_fields(model) for identifying_fields in link_fields: cache_key = self.generate_cache_key( model, identifying_fields, obj.get_identifying_fields(identifying_fields), ) cache.delete(cache_key)
def check( model: Union[TrackedModel, Type[DjangoModelFactory]], serializer: Type[TrackedModelSerializer], parent_model: TrackedModel = None, dependencies: Dict[str, Union[TrackedModel, Type[DjangoModelFactory]]] = None, kwargs: Dict[str, Any] = None, validity=(date_ranges.normal, date_ranges.adjacent_no_end), ): update_type = request.param if isinstance(model, type) and issubclass(model, DjangoModelFactory): if parent_model: raise ValueError("Can't have parent_model and a factory defined") # Build kwargs and dependencies needed to make a complete model. # This can't rely on the factory itself as the dependencies need # to be in the database and .build does not save anything. kwargs = kwargs or {} for name, dependency_model in (dependencies or {}).items(): if isinstance(dependency_model, type) and issubclass( dependency_model, DjangoModelFactory, ): kwargs[name] = dependency_model.create() else: kwargs[name] = dependency_model if validity: kwargs["valid_between"] = validity[0] parent_model = model.create(**kwargs) kwargs.update(parent_model.get_identifying_fields()) if validity: kwargs["valid_between"] = validity[1] model = model.build( update_type=update_type, **kwargs, ) elif not parent_model: raise ValueError("parent_model must be defined if an instance is provided") try: updated_model = imported_fields_match( model, serializer, ) except model.__class__.DoesNotExist: if update_type == UpdateType.UPDATE: raise updated_model = model.__class__.objects.get( update_type=UpdateType.DELETE, **model.get_identifying_fields() ) version_group = parent_model.version_group version_group.refresh_from_db() assert version_group.versions.count() == 2 assert version_group == updated_model.version_group assert version_group.current_version == updated_model assert version_group.current_version.update_type == update_type return updated_model