def assert_lookup_matches_db_execution(self, lookup_name, field_name, obj_value, filter_value, fail_fast=False, raise_invalid_usage=True): MiscModel.objects.all().delete() obj_value = create_test_value(obj_value) filter_value = create_test_value(filter_value) try: with transaction.atomic(): m = MiscModel(**{field_name: obj_value}) m.save() saved_m = MiscModel.objects.get(id=m.id) saved_value = getattr(saved_m, field_name) except (IntegrityError, ValueError, ValidationError, TypeError, ValueError, InvalidOperation, DataError) as e: # we aren't testing which field values are valid to save in the db, so we'll skip these cases transaction.rollback() raise InvalidDbState(str(e)) filter_statement = field_name + '__' + lookup_name q = Q(**{filter_statement: filter_value}) try: self.assert_q_executes_the_same_in_python_and_sql(MiscModel, q, raise_original_exceptions=fail_fast, raise_invalid_usage=raise_invalid_usage) except DoesNotMatchDbExecution as e: raise LookupDoesNotMatchDbExecution( lookup_name=lookup_name, field_name=field_name, obj_value=obj_value, filter_value=filter_value, db_result=e.db_result, py_result=e.py_result, saved_db_value=saved_value, sql=e.sql )
def test_q_negation(self): MiscModel(text='hello', integer=5).save() MiscModel().save() q = ~Q(text='hello') self.assert_q_executes_the_same_in_python_and_sql(MiscModel, q) q = ~Q(text='goodbye') self.assert_q_executes_the_same_in_python_and_sql(MiscModel, q)
def create_test_value(value): if isinstance(value, six.string_types) and value.startswith('TestValue: '): value_type = value.replace('TestValue: ', '') if value_type == 'object': return object() elif value_type == 'saved_model': saved_model = MiscModel() saved_model.save() return saved_model elif value_type == 'unsaved_model': return MiscModel() return value
def test_related_object(self): MiscModel().save() related = MiscModel(text='goodbye') related.save() main = MiscModel(text='hello', foreign=related) main.save() q = Q(foreign__text='goodbye') self.assert_q_executes_the_same_in_python_and_sql(MiscModel, q)
def test_nested_q_object_handling(self): m1 = MiscModel(text='hello', integer=5) m1.save() m2 = MiscModel(text='goodbye', integer=50) m2.save() q = Q(text='hola') | (Q(integer__gt=49) & Q(text='goodbye') & Q(integer__lt=500)) | Q(text='zzzzzzzzzzzzz') self.assert_q_executes_the_same_in_python_and_sql(MiscModel, q)
def test_related_object_reverse_relation(self): MiscModel().save() related = MiscModel(text="goodbye").save() hello_model = MiscModel(text="hello", foreign=related) hello_model.save() MiscModel(text="hola", foreign=related).save() q = Q(miscmodel__text="hello") self.assert_q_executes_the_same_in_python_and_sql(MiscModel, q) q = Q(miscmodel__text="adios") self.assert_q_executes_the_same_in_python_and_sql(MiscModel, q) q = Q(miscmodel__text="hola") self.assert_q_executes_the_same_in_python_and_sql(MiscModel, q) q = Q(miscmodel=hello_model) self.assert_q_executes_the_same_in_python_and_sql(MiscModel, q)
def test_in_with_queryset_as_arg(self): main = MiscModel() main.save() MiscModel(foreign=main, integer=1, text='a').save() MiscModel(foreign=main, integer=2, text='a').save() MiscModel(foreign=main, integer=3, text='b').save() MiscModel(foreign=main, integer=4, text='b').save() a_models = MiscModel.objects.filter(text='a') all_models = list(MiscModel.objects.all()) db_results = MiscModel.objects.filter(miscmodel__in=a_models) mem_results = filter_by_q(all_models, Q(miscmodel__in=a_models)) self.assertEqual(set(db_results), set(mem_results))
def assert_lookup_matches(self, lookup_name, field_name, obj_value, filter_value, lookup_adapter=None, expected=True): m = MiscModel(**{field_name: obj_value}) filter_statement = field_name + '__' + lookup_name try: result = obj_matches_filter_statement(m, filter_statement, filter_value, lookup_adapter=lookup_adapter) except Exception as e: if type(expected) != type or not isinstance(e, expected): raise # raise Exception('Unexpected result for (%s)%s==%s Expected: %s Actual: %s' % (repr(obj_value), filter_statement, repr(filter_value), repr(expected), repr(e))) else: if result != expected: raise Exception( 'Unexpected result for %s lookup (%s)%s==%s Expected: %s Actual: %s' % (repr(lookup_adapter), repr(obj_value), filter_statement, repr(filter_value), repr(expected), repr(result)))
def test_nested_q_object_handling(self): m1 = MiscModel(text="hello", integer=5) m1.save() m2 = MiscModel(text="goodbye", integer=50) m2.save() q = Q(text="hola") | (Q(integer__gt=49) & Q(text="goodbye") & Q(integer__lt=500)) | Q(text="zzzzzzzzzzzzz") self.assert_q_executes_the_same_in_python_and_sql(MiscModel, q)
def test_one_to_one_related_object(self): m1 = MiscModel(integer=1) m1.save() m2 = MiscModel(integer=2, main_info=m1) m2.save() q_to_test = [ Q(extra_info=m2), Q(extra_info=m1), Q(main_info=m1), Q(main_info=m2) ] all_models = list(MiscModel.objects.all()) for q in q_to_test: filter_by_q(all_models, q) self.assert_q_executes_the_same_in_python_and_sql(MiscModel, q)
def test_related_object(self): MiscModel().save() related = MiscModel(text="goodbye") related.save() main = MiscModel(text="hello", foreign=related) main.save() q = Q(foreign__text="goodbye") self.assert_q_executes_the_same_in_python_and_sql(MiscModel, q)
def test_one_to_one_related_object(self): m1 = MiscModel(integer=1) m1.save() m2 = MiscModel(integer=2, main_info=m1) m2.save() q_to_test = [Q(extra_info=m2), Q(extra_info=m1), Q(main_info=m1), Q(main_info=m2)] all_models = list(MiscModel.objects.all()) for q in q_to_test: filter_by_q(all_models, q) self.assert_q_executes_the_same_in_python_and_sql(MiscModel, q)
def test_related_object_reverse_relation(self): MiscModel().save() related = MiscModel(text='goodbye').save() hello_model = MiscModel(text='hello', foreign=related) hello_model.save() MiscModel(text='hola', foreign=related).save() q = Q(miscmodel__text='hello') self.assert_q_executes_the_same_in_python_and_sql(MiscModel, q) q = Q(miscmodel__text='adios') self.assert_q_executes_the_same_in_python_and_sql(MiscModel, q) q = Q(miscmodel__text='hola') self.assert_q_executes_the_same_in_python_and_sql(MiscModel, q) q = Q(miscmodel=hello_model) self.assert_q_executes_the_same_in_python_and_sql(MiscModel, q)
def test_everything_together(self): m1 = MiscModel(text='hello', integer=5) m1.save() m2 = MiscModel(text='goodbye', integer=50) m2.save() m3 = MiscModel(text='howdy', datetime=timezone.now()) m3.save() m1.foreign = m2 m2.foreign = m3 m3.foreign = m1 m1.save() m2.save() m3.save() q = Q(text='hola') | ( Q(integer__gt=49) & Q(text='goodbye') & Q(integer__lt=500) ) | Q( miscmodel__miscmodel__miscmodel__miscmodel__foreign__foreign__integer =5) self.assert_q_executes_the_same_in_python_and_sql(MiscModel, q)
def test_everything_together(self): m1 = MiscModel(text="hello", integer=5) m1.save() m2 = MiscModel(text="goodbye", integer=50) m2.save() m3 = MiscModel(text="howdy", datetime=timezone.now()) m3.save() m1.foreign = m2 m2.foreign = m3 m3.foreign = m1 m1.save() m2.save() m3.save() q = ( Q(text="hola") | (Q(integer__gt=49) & Q(text="goodbye") & Q(integer__lt=500)) | Q(miscmodel__miscmodel__miscmodel__miscmodel__foreign__foreign__integer=5) ) self.assert_q_executes_the_same_in_python_and_sql(MiscModel, q)
def test_text_iexact(self): m = MiscModel(text='a') assert obj_matches_q(m, Q(text__iexact='A'), lookup_adapter='python') assert not obj_matches_q(m, Q(text__exact='A'), lookup_adapter='python')
def test_several_degree_related_object(self): m1 = MiscModel(integer=1) m2 = MiscModel(integer=2) m3 = MiscModel(integer=3) m1.save() m2.save() m3.save() m1.foreign = m2 m2.foreign = m3 m3.foreign = m1 m1.save() m2.save() m3.save() q = Q(miscmodel__integer=2) self.assertEqual(1, MiscModel.objects.filter(q).count()) self.assert_q_executes_the_same_in_python_and_sql(MiscModel, q) q = Q(foreign__integer=2) self.assertEqual(1, MiscModel.objects.filter(q).count()) self.assert_q_executes_the_same_in_python_and_sql(MiscModel, q) q = Q(miscmodel__miscmodel__miscmodel__foreign__foreign__integer=2) self.assertEqual(1, MiscModel.objects.filter(q).count()) self.assert_q_executes_the_same_in_python_and_sql(MiscModel, q) q = Q(miscmodel__miscmodel__miscmodel__foreign__integer=9) self.assert_q_executes_the_same_in_python_and_sql(MiscModel, q)
def test_invalid_usage_regex(self): m = MiscModel() m.save() with self.assertRaisesRegexp(InvalidLookupUsage, 'string'): obj_matches_q(m, Q(text__regex=[1, 2, 3]), lookup_adapter='python')