from django import test from django.db.models.fields import related, CharField, Field, FieldDoesNotExist from django.contrib.contenttypes.fields import GenericRelation from .models import ( AbstractPerson, BasePerson, Person, Relating, Relation ) TEST_RESULTS = { 'fields': { Person: [ 'id', 'data_abstract', 'fk_abstract_id', 'data_not_concrete_abstract', 'content_type_abstract_id', 'object_id_abstract', 'data_base', 'fk_base_id', 'data_not_concrete_base', 'content_type_base_id', 'object_id_base', 'baseperson_ptr_id', 'data_inherited', 'fk_inherited_id', 'data_not_concrete_inherited', 'content_type_concrete_id', 'object_id_concrete', ], BasePerson: [ 'id', 'data_abstract', 'fk_abstract_id', 'data_not_concrete_abstract', 'content_type_abstract_id', 'object_id_abstract', 'data_base', 'fk_base_id', 'data_not_concrete_base', 'content_type_base_id', 'object_id_base', ], AbstractPerson: [ 'data_abstract', 'fk_abstract_id', 'data_not_concrete_abstract', 'content_type_abstract_id', 'object_id_abstract', ], Relating: [ 'id', 'baseperson_id', 'baseperson_hidden_id', 'person_id', 'person_hidden_id', 'proxyperson_id', 'proxyperson_hidden_id', ], }, 'local_fields': { Person: [ 'baseperson_ptr_id', 'data_inherited', 'fk_inherited_id', 'data_not_concrete_inherited', 'content_type_concrete_id', 'object_id_concrete', ], BasePerson: [ 'id', 'data_abstract', 'fk_abstract_id', 'data_not_concrete_abstract', 'content_type_abstract_id', 'object_id_abstract', 'data_base', 'fk_base_id', 'data_not_concrete_base', 'content_type_base_id', 'object_id_base', ], AbstractPerson: [ 'data_abstract', 'fk_abstract_id', 'data_not_concrete_abstract', 'content_type_abstract_id', 'object_id_abstract', ], Relating: [ 'id', 'baseperson_id', 'baseperson_hidden_id', 'person_id', 'person_hidden_id', 'proxyperson_id', 'proxyperson_hidden_id', ], }, 'local_concrete_fields': { Person: [ 'baseperson_ptr_id', 'data_inherited', 'fk_inherited_id', 'content_type_concrete_id', 'object_id_concrete', ], BasePerson: [ 'id', 'data_abstract', 'fk_abstract_id', 'content_type_abstract_id', 'object_id_abstract', 'data_base', 'fk_base_id', 'content_type_base_id', 'object_id_base', ], AbstractPerson: [ 'data_abstract', 'fk_abstract_id', 'content_type_abstract_id', 'object_id_abstract', ], Relating: [ 'id', 'baseperson_id', 'baseperson_hidden_id', 'person_id', 'person_hidden_id', 'proxyperson_id', 'proxyperson_hidden_id', ], }, 'many_to_many': { Person: [ 'm2m_abstract', 'friends_abstract', 'following_abstract', 'm2m_base', 'friends_base', 'following_base', 'm2m_inherited', 'friends_inherited', 'following_inherited', ], BasePerson: [ 'm2m_abstract', 'friends_abstract', 'following_abstract', 'm2m_base', 'friends_base', 'following_base', ], AbstractPerson: [ 'm2m_abstract', 'friends_abstract', 'following_abstract', ], Relating: [ 'basepeople', 'basepeople_hidden', 'people', 'people_hidden', ], }, 'many_to_many_with_model': { Person: [ BasePerson, BasePerson, BasePerson, BasePerson, BasePerson, BasePerson, None, None, None, ], BasePerson: [ None, None, None, None, None, None, ], AbstractPerson: [ None, None, None, ], Relating: [ None, None, None, None, ], }, 'get_all_related_objects_with_model': { Person: ( ('relating_baseperson', BasePerson), ('relating_person', None), ), BasePerson: ( ('person', None), ('relating_baseperson', None), ), Relation: ( ('fk_abstract_rel', None), ('fo_abstract_rel', None), ('fk_base_rel', None), ('fo_base_rel', None), ('fk_concrete_rel', None), ('fo_concrete_rel', None), ), }, 'get_all_related_objects_with_model_local': { Person: ( ('relating_person', None), ), BasePerson: ( ('person', None), ('relating_baseperson', None) ), Relation: ( ('fk_abstract_rel', None), ('fo_abstract_rel', None), ('fk_base_rel', None), ('fo_base_rel', None), ('fk_concrete_rel', None), ('fo_concrete_rel', None), ), }, 'get_all_related_objects_with_model_hidden': { BasePerson: ( ('model_meta:baseperson_friends_base', None), ('model_meta:baseperson_friends_base', None), ('model_meta:baseperson_m2m_base', None), ('model_meta:baseperson_following_base', None), ('model_meta:baseperson_following_base', None), ('model_meta:baseperson_m2m_abstract', None), ('model_meta:baseperson_friends_abstract', None), ('model_meta:baseperson_friends_abstract', None), ('model_meta:baseperson_following_abstract', None), ('model_meta:baseperson_following_abstract', None), ('model_meta:person', None), ('model_meta:relating_basepeople', None), ('model_meta:relating_basepeople_hidden', None), ('model_meta:relating', None), ('model_meta:relating', None), ), Person: ( ('model_meta:baseperson_friends_base', BasePerson), ('model_meta:baseperson_friends_base', BasePerson), ('model_meta:baseperson_m2m_base', BasePerson), ('model_meta:baseperson_following_base', BasePerson), ('model_meta:baseperson_following_base', BasePerson), ('model_meta:baseperson_m2m_abstract', BasePerson), ('model_meta:baseperson_friends_abstract', BasePerson), ('model_meta:baseperson_friends_abstract', BasePerson), ('model_meta:baseperson_following_abstract', BasePerson), ('model_meta:baseperson_following_abstract', BasePerson), ('model_meta:relating_basepeople', BasePerson), ('model_meta:relating_basepeople_hidden', BasePerson), ('model_meta:relating', BasePerson), ('model_meta:relating', BasePerson), ('model_meta:person_m2m_inherited', None), ('model_meta:person_friends_inherited', None), ('model_meta:person_friends_inherited', None), ('model_meta:person_following_inherited', None), ('model_meta:person_following_inherited', None), ('model_meta:relating_people', None), ('model_meta:relating_people_hidden', None), ('model_meta:relating', None), ('model_meta:relating', None), ), Relation: ( ('model_meta:baseperson_m2m_base', None), ('model_meta:baseperson_m2m_abstract', None), ('model_meta:baseperson', None), ('model_meta:baseperson', None), ('model_meta:baseperson', None), ('model_meta:baseperson', None), ('model_meta:baseperson', None), ('model_meta:baseperson', None), ('model_meta:person_m2m_inherited', None), ('model_meta:person', None), ('model_meta:person', None), ('model_meta:person', None), ('model_meta:person', None), ('model_meta:person', None), ('model_meta:proxyperson', None), ('model_meta:proxyperson', None), ('model_meta:proxyperson', None), ), }, 'get_all_related_objects_with_model_hidden_local': { BasePerson: ( ('model_meta:baseperson_friends_base', None), ('model_meta:baseperson_friends_base', None), ('model_meta:baseperson_m2m_base', None), ('model_meta:baseperson_following_base', None), ('model_meta:baseperson_following_base', None), ('model_meta:baseperson_m2m_abstract', None), ('model_meta:baseperson_friends_abstract', None), ('model_meta:baseperson_friends_abstract', None), ('model_meta:baseperson_following_abstract', None), ('model_meta:baseperson_following_abstract', None), ('model_meta:person', None), ('model_meta:relating_basepeople', None), ('model_meta:relating_basepeople_hidden', None), ('model_meta:relating', None), ('model_meta:relating', None), ), Person: ( ('model_meta:person_m2m_inherited', None), ('model_meta:person_friends_inherited', None), ('model_meta:person_friends_inherited', None), ('model_meta:person_following_inherited', None), ('model_meta:person_following_inherited', None), ('model_meta:relating_people', None), ('model_meta:relating_people_hidden', None), ('model_meta:relating', None), ('model_meta:relating', None), ), Relation: ( ('model_meta:baseperson_m2m_base', None), ('model_meta:baseperson_m2m_abstract', None), ('model_meta:baseperson', None), ('model_meta:baseperson', None), ('model_meta:baseperson', None), ('model_meta:baseperson', None), ('model_meta:baseperson', None), ('model_meta:baseperson', None), ('model_meta:person_m2m_inherited', None), ('model_meta:person', None), ('model_meta:person', None), ('model_meta:person', None), ('model_meta:person', None), ('model_meta:person', None), ('model_meta:proxyperson', None), ('model_meta:proxyperson', None), ('model_meta:proxyperson', None), ), }, 'get_all_related_objects_with_model_proxy': { BasePerson: ( ('person', None), ('relating_baseperson', None), ), Person: ( ('relating_baseperson', BasePerson), ('relating_person', None), ('relating_proxyperson', None), ), Relation: ( ('fk_abstract_rel', None), ('fo_abstract_rel', None), ('fk_base_rel', None), ('fo_base_rel', None), ('fk_concrete_rel', None), ('fo_concrete_rel', None), ), }, 'get_all_related_objects_with_model_proxy_hidden': { BasePerson: ( ('model_meta:baseperson_friends_base', None), ('model_meta:baseperson_friends_base', None), ('model_meta:baseperson_m2m_base', None), ('model_meta:baseperson_following_base', None), ('model_meta:baseperson_following_base', None), ('model_meta:baseperson_m2m_abstract', None), ('model_meta:baseperson_friends_abstract', None), ('model_meta:baseperson_friends_abstract', None), ('model_meta:baseperson_following_abstract', None), ('model_meta:baseperson_following_abstract', None), ('model_meta:person', None), ('model_meta:relating_basepeople', None), ('model_meta:relating_basepeople_hidden', None), ('model_meta:relating', None), ('model_meta:relating', None), ), Person: ( ('model_meta:baseperson_friends_base', BasePerson), ('model_meta:baseperson_friends_base', BasePerson), ('model_meta:baseperson_m2m_base', BasePerson), ('model_meta:baseperson_following_base', BasePerson), ('model_meta:baseperson_following_base', BasePerson), ('model_meta:baseperson_m2m_abstract', BasePerson), ('model_meta:baseperson_friends_abstract', BasePerson), ('model_meta:baseperson_friends_abstract', BasePerson), ('model_meta:baseperson_following_abstract', BasePerson), ('model_meta:baseperson_following_abstract', BasePerson), ('model_meta:relating_basepeople', BasePerson), ('model_meta:relating_basepeople_hidden', BasePerson), ('model_meta:relating', BasePerson), ('model_meta:relating', BasePerson), ('model_meta:person_m2m_inherited', None), ('model_meta:person_friends_inherited', None), ('model_meta:person_friends_inherited', None), ('model_meta:person_following_inherited', None), ('model_meta:person_following_inherited', None), ('model_meta:relating_people', None), ('model_meta:relating_people_hidden', None), ('model_meta:relating', None), ('model_meta:relating', None), ('model_meta:relating', None), ('model_meta:relating', None), ), Relation: ( ('model_meta:baseperson_m2m_base', None), ('model_meta:baseperson_m2m_abstract', None), ('model_meta:baseperson', None), ('model_meta:baseperson', None), ('model_meta:baseperson', None), ('model_meta:baseperson', None), ('model_meta:baseperson', None), ('model_meta:baseperson', None), ('model_meta:person_m2m_inherited', None), ('model_meta:person', None), ('model_meta:person', None), ('model_meta:person', None), ('model_meta:person', None), ('model_meta:person', None), ('model_meta:proxyperson', None), ('model_meta:proxyperson', None), ('model_meta:proxyperson', None), ), }, 'get_all_related_many_to_many_with_model': { BasePerson: ( ('friends_abstract_rel_+', None), ('followers_abstract', None), ('friends_base_rel_+', None), ('followers_base', None), ('relating_basepeople', None), ('+', None), ), Person: ( ('friends_abstract_rel_+', BasePerson), ('followers_abstract', BasePerson), ('friends_base_rel_+', BasePerson), ('followers_base', BasePerson), ('relating_basepeople', BasePerson), ('+', BasePerson), ('friends_inherited_rel_+', None), ('followers_concrete', None), ('relating_people', None), ('+', None), ), Relation: ( ('m2m_abstract_rel', None), ('m2m_base_rel', None), ('m2m_concrete_rel', None), ), }, 'get_all_related_many_to_many_local': { BasePerson: [ 'friends_abstract_rel_+', 'followers_abstract', 'friends_base_rel_+', 'followers_base', 'relating_basepeople', '+', ], Person: [ 'friends_inherited_rel_+', 'followers_concrete', 'relating_people', '+', ], Relation: [ 'm2m_abstract_rel', 'm2m_base_rel', 'm2m_concrete_rel', ], }, 'virtual_fields': { AbstractPerson: [ 'generic_relation_abstract', 'content_object_abstract', ], BasePerson: [ 'generic_relation_base', 'content_object_base', 'generic_relation_abstract', 'content_object_abstract', ], Person: [ 'content_object_concrete', 'generic_relation_concrete', 'generic_relation_base', 'content_object_base', 'generic_relation_abstract', 'content_object_abstract', ], }, } class OptionsBaseTests(test.TestCase): def _map_rq_names(self, res): return tuple([(o.field.related_query_name(), m) for o, m in res]) def _map_names(self, res): return tuple([(f.name, m) for f, m in res]) class DataTests(OptionsBaseTests): def test_fields(self): for model, expected_result in TEST_RESULTS['fields'].items(): fields = model._meta.fields self.assertEqual([f.attname for f in fields], expected_result) def test_local_fields(self): is_data_field = lambda f: isinstance(f, Field) and not isinstance(f, related.ManyToManyField) for model, expected_result in TEST_RESULTS['local_fields'].items(): fields = model._meta.local_fields self.assertEqual([f.attname for f in fields], expected_result) self.assertTrue(all([f.model is model for f in fields])) self.assertTrue(all([is_data_field(f) for f in fields])) def test_local_concrete_fields(self): for model, expected_result in TEST_RESULTS['local_concrete_fields'].items(): fields = model._meta.local_concrete_fields self.assertEqual([f.attname for f in fields], expected_result) self.assertTrue(all([f.column is not None for f in fields])) class M2MTests(OptionsBaseTests): def test_many_to_many(self): for model, expected_result in TEST_RESULTS['many_to_many'].items(): fields = model._meta.many_to_many self.assertEqual([f.attname for f in fields], expected_result) self.assertTrue(all([isinstance(f.rel, related.ManyToManyRel) for f in fields])) def test_many_to_many_with_model(self): for model, expected_result in TEST_RESULTS['many_to_many_with_model'].items(): models = [model for field, model in model._meta.get_m2m_with_model()] self.assertEqual(models, expected_result) class RelatedObjectsTests(OptionsBaseTests): def setUp(self): self.key_name = lambda r: r[0] def test_related_objects(self): result_key = 'get_all_related_objects_with_model' for model, expected in TEST_RESULTS[result_key].items(): objects = model._meta.get_all_related_objects_with_model() self.assertEqual(self._map_rq_names(objects), expected) def test_related_objects_local(self): result_key = 'get_all_related_objects_with_model_local' for model, expected in TEST_RESULTS[result_key].items(): objects = model._meta.get_all_related_objects_with_model(local_only=True) self.assertEqual(self._map_rq_names(objects), expected) def test_related_objects_include_hidden(self): result_key = 'get_all_related_objects_with_model_hidden' for model, expected in TEST_RESULTS[result_key].items(): objects = model._meta.get_all_related_objects_with_model(include_hidden=True) self.assertEqual( sorted(self._map_names(objects), key=self.key_name), sorted(expected, key=self.key_name) ) def test_related_objects_include_hidden_local_only(self): result_key = 'get_all_related_objects_with_model_hidden_local' for model, expected in TEST_RESULTS[result_key].items(): objects = model._meta.get_all_related_objects_with_model( include_hidden=True, local_only=True) self.assertEqual( sorted(self._map_names(objects), key=self.key_name), sorted(expected, key=self.key_name) ) def test_related_objects_proxy(self): result_key = 'get_all_related_objects_with_model_proxy' for model, expected in TEST_RESULTS[result_key].items(): objects = model._meta.get_all_related_objects_with_model( include_proxy_eq=True) self.assertEqual(self._map_rq_names(objects), expected) def test_related_objects_proxy_hidden(self): result_key = 'get_all_related_objects_with_model_proxy_hidden' for model, expected in TEST_RESULTS[result_key].items(): objects = model._meta.get_all_related_objects_with_model( include_proxy_eq=True, include_hidden=True) self.assertEqual( sorted(self._map_names(objects), key=self.key_name), sorted(expected, key=self.key_name) ) class RelatedM2MTests(OptionsBaseTests): def test_related_m2m_with_model(self): result_key = 'get_all_related_many_to_many_with_model' for model, expected in TEST_RESULTS[result_key].items(): objects = model._meta.get_all_related_m2m_objects_with_model() self.assertEqual(self._map_rq_names(objects), expected) def test_related_m2m_local_only(self): result_key = 'get_all_related_many_to_many_local' for model, expected in TEST_RESULTS[result_key].items(): objects = model._meta.get_all_related_many_to_many_objects(local_only=True) self.assertEqual([o.field.related_query_name() for o in objects], expected) def test_related_m2m_asymmetrical(self): m2m = Person._meta.many_to_many self.assertTrue('following_base' in [f.attname for f in m2m]) related_m2m = Person._meta.get_all_related_many_to_many_objects() self.assertTrue('followers_base' in [o.field.related_query_name() for o in related_m2m]) def test_related_m2m_symmetrical(self): m2m = Person._meta.many_to_many self.assertTrue('friends_base' in [f.attname for f in m2m]) related_m2m = Person._meta.get_all_related_many_to_many_objects() self.assertIn('friends_inherited_rel_+', [o.field.related_query_name() for o in related_m2m]) class VirtualFieldsTests(OptionsBaseTests): def test_virtual_fields(self): for model, expected_names in TEST_RESULTS['virtual_fields'].items(): objects = model._meta.virtual_fields self.assertEqual(sorted([f.name for f in objects]), sorted(expected_names)) class GetFieldByNameTests(OptionsBaseTests): def test_get_data_field(self): field_info = Person._meta.get_field_by_name('data_abstract') self.assertEqual(field_info[1:], (BasePerson, True, False)) self.assertIsInstance(field_info[0], CharField) def test_get_m2m_field(self): field_info = Person._meta.get_field_by_name('m2m_base') self.assertEqual(field_info[1:], (BasePerson, True, True)) self.assertIsInstance(field_info[0], related.ManyToManyField) def test_get_related_object(self): field_info = Person._meta.get_field_by_name('relating_baseperson') self.assertEqual(field_info[1:], (BasePerson, False, False)) self.assertIsInstance(field_info[0], related.RelatedObject) def test_get_related_m2m(self): field_info = Person._meta.get_field_by_name('relating_people') self.assertEqual(field_info[1:], (None, False, True)) self.assertIsInstance(field_info[0], related.RelatedObject) def test_get_generic_foreign_key(self): # For historic reasons generic foreign keys aren't available. with self.assertRaises(FieldDoesNotExist): Person._meta.get_field_by_name('content_object_base') def test_get_generic_relation(self): field_info = Person._meta.get_field_by_name('generic_relation_base') self.assertEqual(field_info[1:], (None, True, False)) self.assertIsInstance(field_info[0], GenericRelation)