test.py 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661
  1. from django import test
  2. from django.contrib.contenttypes.fields import GenericRelation
  3. from django.core.exceptions import FieldDoesNotExist
  4. from django.db.models.fields import related, CharField, Field
  5. from .models import (
  6. AbstractPerson, BasePerson, Person, Relating, Relation
  7. )
  8. TEST_RESULTS = {
  9. 'fields': {
  10. Person: [
  11. 'id',
  12. 'data_abstract',
  13. 'fk_abstract_id',
  14. 'data_not_concrete_abstract',
  15. 'content_type_abstract_id',
  16. 'object_id_abstract',
  17. 'data_base',
  18. 'fk_base_id',
  19. 'data_not_concrete_base',
  20. 'content_type_base_id',
  21. 'object_id_base',
  22. 'baseperson_ptr_id',
  23. 'data_inherited',
  24. 'fk_inherited_id',
  25. 'data_not_concrete_inherited',
  26. 'content_type_concrete_id',
  27. 'object_id_concrete',
  28. ],
  29. BasePerson: [
  30. 'id',
  31. 'data_abstract',
  32. 'fk_abstract_id',
  33. 'data_not_concrete_abstract',
  34. 'content_type_abstract_id',
  35. 'object_id_abstract',
  36. 'data_base',
  37. 'fk_base_id',
  38. 'data_not_concrete_base',
  39. 'content_type_base_id',
  40. 'object_id_base',
  41. ],
  42. AbstractPerson: [
  43. 'data_abstract',
  44. 'fk_abstract_id',
  45. 'data_not_concrete_abstract',
  46. 'content_type_abstract_id',
  47. 'object_id_abstract',
  48. ],
  49. Relating: [
  50. 'id',
  51. 'baseperson_id',
  52. 'baseperson_hidden_id',
  53. 'person_id',
  54. 'person_hidden_id',
  55. 'proxyperson_id',
  56. 'proxyperson_hidden_id',
  57. ],
  58. },
  59. 'local_fields': {
  60. Person: [
  61. 'baseperson_ptr_id',
  62. 'data_inherited',
  63. 'fk_inherited_id',
  64. 'data_not_concrete_inherited',
  65. 'content_type_concrete_id',
  66. 'object_id_concrete',
  67. ],
  68. BasePerson: [
  69. 'id',
  70. 'data_abstract',
  71. 'fk_abstract_id',
  72. 'data_not_concrete_abstract',
  73. 'content_type_abstract_id',
  74. 'object_id_abstract',
  75. 'data_base',
  76. 'fk_base_id',
  77. 'data_not_concrete_base',
  78. 'content_type_base_id',
  79. 'object_id_base',
  80. ],
  81. AbstractPerson: [
  82. 'data_abstract',
  83. 'fk_abstract_id',
  84. 'data_not_concrete_abstract',
  85. 'content_type_abstract_id',
  86. 'object_id_abstract',
  87. ],
  88. Relating: [
  89. 'id',
  90. 'baseperson_id',
  91. 'baseperson_hidden_id',
  92. 'person_id',
  93. 'person_hidden_id',
  94. 'proxyperson_id',
  95. 'proxyperson_hidden_id',
  96. ],
  97. },
  98. 'local_concrete_fields': {
  99. Person: [
  100. 'baseperson_ptr_id',
  101. 'data_inherited',
  102. 'fk_inherited_id',
  103. 'content_type_concrete_id',
  104. 'object_id_concrete',
  105. ],
  106. BasePerson: [
  107. 'id',
  108. 'data_abstract',
  109. 'fk_abstract_id',
  110. 'content_type_abstract_id',
  111. 'object_id_abstract',
  112. 'data_base',
  113. 'fk_base_id',
  114. 'content_type_base_id',
  115. 'object_id_base',
  116. ],
  117. AbstractPerson: [
  118. 'data_abstract',
  119. 'fk_abstract_id',
  120. 'content_type_abstract_id',
  121. 'object_id_abstract',
  122. ],
  123. Relating: [
  124. 'id',
  125. 'baseperson_id',
  126. 'baseperson_hidden_id',
  127. 'person_id',
  128. 'person_hidden_id',
  129. 'proxyperson_id',
  130. 'proxyperson_hidden_id',
  131. ],
  132. },
  133. 'many_to_many': {
  134. Person: [
  135. 'm2m_abstract',
  136. 'friends_abstract',
  137. 'following_abstract',
  138. 'm2m_base',
  139. 'friends_base',
  140. 'following_base',
  141. 'm2m_inherited',
  142. 'friends_inherited',
  143. 'following_inherited',
  144. ],
  145. BasePerson: [
  146. 'm2m_abstract',
  147. 'friends_abstract',
  148. 'following_abstract',
  149. 'm2m_base',
  150. 'friends_base',
  151. 'following_base',
  152. ],
  153. AbstractPerson: [
  154. 'm2m_abstract',
  155. 'friends_abstract',
  156. 'following_abstract',
  157. ],
  158. Relating: [
  159. 'basepeople',
  160. 'basepeople_hidden',
  161. 'people',
  162. 'people_hidden',
  163. ],
  164. },
  165. 'many_to_many_with_model': {
  166. Person: [
  167. BasePerson,
  168. BasePerson,
  169. BasePerson,
  170. BasePerson,
  171. BasePerson,
  172. BasePerson,
  173. None,
  174. None,
  175. None,
  176. ],
  177. BasePerson: [
  178. None,
  179. None,
  180. None,
  181. None,
  182. None,
  183. None,
  184. ],
  185. AbstractPerson: [
  186. None,
  187. None,
  188. None,
  189. ],
  190. Relating: [
  191. None,
  192. None,
  193. None,
  194. None,
  195. ],
  196. },
  197. 'get_all_related_objects_with_model': {
  198. Person: (
  199. ('relating_baseperson', BasePerson),
  200. ('relating_person', None),
  201. ),
  202. BasePerson: (
  203. ('person', None),
  204. ('relating_baseperson', None),
  205. ),
  206. Relation: (
  207. ('fk_abstract_rel', None),
  208. ('fo_abstract_rel', None),
  209. ('fk_base_rel', None),
  210. ('fo_base_rel', None),
  211. ('fk_concrete_rel', None),
  212. ('fo_concrete_rel', None),
  213. ),
  214. },
  215. 'get_all_related_objects_with_model_local': {
  216. Person: (
  217. ('relating_person', None),
  218. ),
  219. BasePerson: (
  220. ('person', None),
  221. ('relating_baseperson', None)
  222. ),
  223. Relation: (
  224. ('fk_abstract_rel', None),
  225. ('fo_abstract_rel', None),
  226. ('fk_base_rel', None),
  227. ('fo_base_rel', None),
  228. ('fk_concrete_rel', None),
  229. ('fo_concrete_rel', None),
  230. ),
  231. },
  232. 'get_all_related_objects_with_model_hidden': {
  233. BasePerson: (
  234. ('model_meta.baseperson_friends_base', None),
  235. ('model_meta.baseperson_friends_base', None),
  236. ('model_meta.baseperson_m2m_base', None),
  237. ('model_meta.baseperson_following_base', None),
  238. ('model_meta.baseperson_following_base', None),
  239. ('model_meta.baseperson_m2m_abstract', None),
  240. ('model_meta.baseperson_friends_abstract', None),
  241. ('model_meta.baseperson_friends_abstract', None),
  242. ('model_meta.baseperson_following_abstract', None),
  243. ('model_meta.baseperson_following_abstract', None),
  244. ('model_meta.person', None),
  245. ('model_meta.relating_basepeople', None),
  246. ('model_meta.relating_basepeople_hidden', None),
  247. ('model_meta.relating', None),
  248. ('model_meta.relating', None),
  249. ),
  250. Person: (
  251. ('model_meta.baseperson_friends_base', BasePerson),
  252. ('model_meta.baseperson_friends_base', BasePerson),
  253. ('model_meta.baseperson_m2m_base', BasePerson),
  254. ('model_meta.baseperson_following_base', BasePerson),
  255. ('model_meta.baseperson_following_base', BasePerson),
  256. ('model_meta.baseperson_m2m_abstract', BasePerson),
  257. ('model_meta.baseperson_friends_abstract', BasePerson),
  258. ('model_meta.baseperson_friends_abstract', BasePerson),
  259. ('model_meta.baseperson_following_abstract', BasePerson),
  260. ('model_meta.baseperson_following_abstract', BasePerson),
  261. ('model_meta.relating_basepeople', BasePerson),
  262. ('model_meta.relating_basepeople_hidden', BasePerson),
  263. ('model_meta.relating', BasePerson),
  264. ('model_meta.relating', BasePerson),
  265. ('model_meta.person_m2m_inherited', None),
  266. ('model_meta.person_friends_inherited', None),
  267. ('model_meta.person_friends_inherited', None),
  268. ('model_meta.person_following_inherited', None),
  269. ('model_meta.person_following_inherited', None),
  270. ('model_meta.relating_people', None),
  271. ('model_meta.relating_people_hidden', None),
  272. ('model_meta.relating', None),
  273. ('model_meta.relating', None),
  274. ),
  275. Relation: (
  276. ('model_meta.baseperson_m2m_base', None),
  277. ('model_meta.baseperson_m2m_abstract', None),
  278. ('model_meta.baseperson', None),
  279. ('model_meta.baseperson', None),
  280. ('model_meta.baseperson', None),
  281. ('model_meta.baseperson', None),
  282. ('model_meta.baseperson', None),
  283. ('model_meta.baseperson', None),
  284. ('model_meta.person_m2m_inherited', None),
  285. ('model_meta.person', None),
  286. ('model_meta.person', None),
  287. ('model_meta.person', None),
  288. ('model_meta.person', None),
  289. ('model_meta.person', None),
  290. ('model_meta.proxyperson', None),
  291. ('model_meta.proxyperson', None),
  292. ('model_meta.proxyperson', None),
  293. ),
  294. },
  295. 'get_all_related_objects_with_model_hidden_local': {
  296. BasePerson: (
  297. ('model_meta.baseperson_friends_base', None),
  298. ('model_meta.baseperson_friends_base', None),
  299. ('model_meta.baseperson_m2m_base', None),
  300. ('model_meta.baseperson_following_base', None),
  301. ('model_meta.baseperson_following_base', None),
  302. ('model_meta.baseperson_m2m_abstract', None),
  303. ('model_meta.baseperson_friends_abstract', None),
  304. ('model_meta.baseperson_friends_abstract', None),
  305. ('model_meta.baseperson_following_abstract', None),
  306. ('model_meta.baseperson_following_abstract', None),
  307. ('model_meta.person', None),
  308. ('model_meta.relating_basepeople', None),
  309. ('model_meta.relating_basepeople_hidden', None),
  310. ('model_meta.relating', None),
  311. ('model_meta.relating', None),
  312. ),
  313. Person: (
  314. ('model_meta.person_m2m_inherited', None),
  315. ('model_meta.person_friends_inherited', None),
  316. ('model_meta.person_friends_inherited', None),
  317. ('model_meta.person_following_inherited', None),
  318. ('model_meta.person_following_inherited', None),
  319. ('model_meta.relating_people', None),
  320. ('model_meta.relating_people_hidden', None),
  321. ('model_meta.relating', None),
  322. ('model_meta.relating', None),
  323. ),
  324. Relation: (
  325. ('model_meta.baseperson_m2m_base', None),
  326. ('model_meta.baseperson_m2m_abstract', None),
  327. ('model_meta.baseperson', None),
  328. ('model_meta.baseperson', None),
  329. ('model_meta.baseperson', None),
  330. ('model_meta.baseperson', None),
  331. ('model_meta.baseperson', None),
  332. ('model_meta.baseperson', None),
  333. ('model_meta.person_m2m_inherited', None),
  334. ('model_meta.person', None),
  335. ('model_meta.person', None),
  336. ('model_meta.person', None),
  337. ('model_meta.person', None),
  338. ('model_meta.person', None),
  339. ('model_meta.proxyperson', None),
  340. ('model_meta.proxyperson', None),
  341. ('model_meta.proxyperson', None),
  342. ),
  343. },
  344. 'get_all_related_objects_with_model_proxy': {
  345. BasePerson: (
  346. ('person', None),
  347. ('relating_baseperson', None),
  348. ),
  349. Person: (
  350. ('relating_baseperson', BasePerson),
  351. ('relating_person', None), ('relating_proxyperson', None),
  352. ),
  353. Relation: (
  354. ('fk_abstract_rel', None), ('fo_abstract_rel', None),
  355. ('fk_base_rel', None), ('fo_base_rel', None),
  356. ('fk_concrete_rel', None), ('fo_concrete_rel', None),
  357. ),
  358. },
  359. 'get_all_related_objects_with_model_proxy_hidden': {
  360. BasePerson: (
  361. ('model_meta.baseperson_friends_base', None),
  362. ('model_meta.baseperson_friends_base', None),
  363. ('model_meta.baseperson_m2m_base', None),
  364. ('model_meta.baseperson_following_base', None),
  365. ('model_meta.baseperson_following_base', None),
  366. ('model_meta.baseperson_m2m_abstract', None),
  367. ('model_meta.baseperson_friends_abstract', None),
  368. ('model_meta.baseperson_friends_abstract', None),
  369. ('model_meta.baseperson_following_abstract', None),
  370. ('model_meta.baseperson_following_abstract', None),
  371. ('model_meta.person', None),
  372. ('model_meta.relating_basepeople', None),
  373. ('model_meta.relating_basepeople_hidden', None),
  374. ('model_meta.relating', None),
  375. ('model_meta.relating', None),
  376. ),
  377. Person: (
  378. ('model_meta.baseperson_friends_base', BasePerson),
  379. ('model_meta.baseperson_friends_base', BasePerson),
  380. ('model_meta.baseperson_m2m_base', BasePerson),
  381. ('model_meta.baseperson_following_base', BasePerson),
  382. ('model_meta.baseperson_following_base', BasePerson),
  383. ('model_meta.baseperson_m2m_abstract', BasePerson),
  384. ('model_meta.baseperson_friends_abstract', BasePerson),
  385. ('model_meta.baseperson_friends_abstract', BasePerson),
  386. ('model_meta.baseperson_following_abstract', BasePerson),
  387. ('model_meta.baseperson_following_abstract', BasePerson),
  388. ('model_meta.relating_basepeople', BasePerson),
  389. ('model_meta.relating_basepeople_hidden', BasePerson),
  390. ('model_meta.relating', BasePerson),
  391. ('model_meta.relating', BasePerson),
  392. ('model_meta.person_m2m_inherited', None),
  393. ('model_meta.person_friends_inherited', None),
  394. ('model_meta.person_friends_inherited', None),
  395. ('model_meta.person_following_inherited', None),
  396. ('model_meta.person_following_inherited', None),
  397. ('model_meta.relating_people', None),
  398. ('model_meta.relating_people_hidden', None),
  399. ('model_meta.relating', None),
  400. ('model_meta.relating', None),
  401. ('model_meta.relating', None),
  402. ('model_meta.relating', None),
  403. ),
  404. Relation: (
  405. ('model_meta.baseperson_m2m_base', None),
  406. ('model_meta.baseperson_m2m_abstract', None),
  407. ('model_meta.baseperson', None),
  408. ('model_meta.baseperson', None),
  409. ('model_meta.baseperson', None),
  410. ('model_meta.baseperson', None),
  411. ('model_meta.baseperson', None),
  412. ('model_meta.baseperson', None),
  413. ('model_meta.person_m2m_inherited', None),
  414. ('model_meta.person', None),
  415. ('model_meta.person', None),
  416. ('model_meta.person', None),
  417. ('model_meta.person', None),
  418. ('model_meta.person', None),
  419. ('model_meta.proxyperson', None),
  420. ('model_meta.proxyperson', None),
  421. ('model_meta.proxyperson', None),
  422. ),
  423. },
  424. 'get_all_related_many_to_many_with_model': {
  425. BasePerson: (
  426. ('friends_abstract_rel_+', None),
  427. ('followers_abstract', None),
  428. ('friends_base_rel_+', None),
  429. ('followers_base', None),
  430. ('relating_basepeople', None),
  431. ('+', None),
  432. ),
  433. Person: (
  434. ('friends_abstract_rel_+', BasePerson),
  435. ('followers_abstract', BasePerson),
  436. ('friends_base_rel_+', BasePerson),
  437. ('followers_base', BasePerson),
  438. ('relating_basepeople', BasePerson),
  439. ('+', BasePerson),
  440. ('friends_inherited_rel_+', None),
  441. ('followers_concrete', None),
  442. ('relating_people', None),
  443. ('+', None),
  444. ),
  445. Relation: (
  446. ('m2m_abstract_rel', None),
  447. ('m2m_base_rel', None),
  448. ('m2m_concrete_rel', None),
  449. ),
  450. },
  451. 'get_all_related_many_to_many_local': {
  452. BasePerson: [
  453. 'friends_abstract_rel_+',
  454. 'followers_abstract',
  455. 'friends_base_rel_+',
  456. 'followers_base',
  457. 'relating_basepeople',
  458. '+',
  459. ],
  460. Person: [
  461. 'friends_inherited_rel_+',
  462. 'followers_concrete',
  463. 'relating_people',
  464. '+',
  465. ],
  466. Relation: [
  467. 'm2m_abstract_rel',
  468. 'm2m_base_rel',
  469. 'm2m_concrete_rel',
  470. ],
  471. },
  472. 'virtual_fields': {
  473. AbstractPerson: [
  474. 'generic_relation_abstract',
  475. 'content_object_abstract',
  476. ],
  477. BasePerson: [
  478. 'generic_relation_base',
  479. 'content_object_base',
  480. 'generic_relation_abstract',
  481. 'content_object_abstract',
  482. ],
  483. Person: [
  484. 'content_object_concrete',
  485. 'generic_relation_concrete',
  486. 'generic_relation_base',
  487. 'content_object_base',
  488. 'generic_relation_abstract',
  489. 'content_object_abstract',
  490. ],
  491. },
  492. }
  493. class OptionsBaseTests(test.TestCase):
  494. def _map_rq_names(self, res):
  495. return tuple((o.field.related_query_name(), m) for o, m in res)
  496. def _map_names(self, res):
  497. return tuple((f.name, m) for f, m in res)
  498. class DataTests(OptionsBaseTests):
  499. def test_fields(self):
  500. for model, expected_result in TEST_RESULTS['fields'].items():
  501. fields = model._meta.fields
  502. self.assertEqual([f.attname for f in fields], expected_result)
  503. def test_local_fields(self):
  504. is_data_field = lambda f: isinstance(f, Field) and not isinstance(f, related.ManyToManyField)
  505. for model, expected_result in TEST_RESULTS['local_fields'].items():
  506. fields = model._meta.local_fields
  507. self.assertEqual([f.attname for f in fields], expected_result)
  508. self.assertTrue(all([f.model is model for f in fields]))
  509. self.assertTrue(all([is_data_field(f) for f in fields]))
  510. def test_local_concrete_fields(self):
  511. for model, expected_result in TEST_RESULTS['local_concrete_fields'].items():
  512. fields = model._meta.local_concrete_fields
  513. self.assertEqual([f.attname for f in fields], expected_result)
  514. self.assertTrue(all([f.column is not None for f in fields]))
  515. class M2MTests(OptionsBaseTests):
  516. def test_many_to_many(self):
  517. for model, expected_result in TEST_RESULTS['many_to_many'].items():
  518. fields = model._meta.many_to_many
  519. self.assertEqual([f.attname for f in fields], expected_result)
  520. self.assertTrue(all([isinstance(f.rel, related.ManyToManyRel) for f in fields]))
  521. def test_many_to_many_with_model(self):
  522. for model, expected_result in TEST_RESULTS['many_to_many_with_model'].items():
  523. models = [model for field, model in model._meta.get_m2m_with_model()]
  524. self.assertEqual(models, expected_result)
  525. class RelatedObjectsTests(OptionsBaseTests):
  526. def setUp(self):
  527. self.key_name = lambda r: r[0]
  528. def test_related_objects(self):
  529. result_key = 'get_all_related_objects_with_model'
  530. for model, expected in TEST_RESULTS[result_key].items():
  531. objects = model._meta.get_all_related_objects_with_model()
  532. self.assertEqual(self._map_rq_names(objects), expected)
  533. def test_related_objects_local(self):
  534. result_key = 'get_all_related_objects_with_model_local'
  535. for model, expected in TEST_RESULTS[result_key].items():
  536. objects = model._meta.get_all_related_objects_with_model(local_only=True)
  537. self.assertEqual(self._map_rq_names(objects), expected)
  538. def test_related_objects_include_hidden(self):
  539. result_key = 'get_all_related_objects_with_model_hidden'
  540. for model, expected in TEST_RESULTS[result_key].items():
  541. objects = model._meta.get_all_related_objects_with_model(include_hidden=True)
  542. self.assertEqual(
  543. sorted(self._map_names(objects), key=self.key_name),
  544. sorted(expected, key=self.key_name)
  545. )
  546. def test_related_objects_include_hidden_local_only(self):
  547. result_key = 'get_all_related_objects_with_model_hidden_local'
  548. for model, expected in TEST_RESULTS[result_key].items():
  549. objects = model._meta.get_all_related_objects_with_model(
  550. include_hidden=True, local_only=True)
  551. self.assertEqual(
  552. sorted(self._map_names(objects), key=self.key_name),
  553. sorted(expected, key=self.key_name)
  554. )
  555. def test_related_objects_proxy(self):
  556. result_key = 'get_all_related_objects_with_model_proxy'
  557. for model, expected in TEST_RESULTS[result_key].items():
  558. objects = model._meta.get_all_related_objects_with_model(
  559. include_proxy_eq=True)
  560. self.assertEqual(self._map_rq_names(objects), expected)
  561. def test_related_objects_proxy_hidden(self):
  562. result_key = 'get_all_related_objects_with_model_proxy_hidden'
  563. for model, expected in TEST_RESULTS[result_key].items():
  564. objects = model._meta.get_all_related_objects_with_model(
  565. include_proxy_eq=True, include_hidden=True)
  566. self.assertEqual(
  567. sorted(self._map_names(objects), key=self.key_name),
  568. sorted(expected, key=self.key_name)
  569. )
  570. class RelatedM2MTests(OptionsBaseTests):
  571. def test_related_m2m_with_model(self):
  572. result_key = 'get_all_related_many_to_many_with_model'
  573. for model, expected in TEST_RESULTS[result_key].items():
  574. objects = model._meta.get_all_related_m2m_objects_with_model()
  575. self.assertEqual(self._map_rq_names(objects), expected)
  576. def test_related_m2m_local_only(self):
  577. result_key = 'get_all_related_many_to_many_local'
  578. for model, expected in TEST_RESULTS[result_key].items():
  579. objects = model._meta.get_all_related_many_to_many_objects(local_only=True)
  580. self.assertEqual([o.field.related_query_name() for o in objects], expected)
  581. def test_related_m2m_asymmetrical(self):
  582. m2m = Person._meta.many_to_many
  583. self.assertIn('following_base', [f.attname for f in m2m])
  584. related_m2m = Person._meta.get_all_related_many_to_many_objects()
  585. self.assertIn('followers_base', [o.field.related_query_name() for o in related_m2m])
  586. def test_related_m2m_symmetrical(self):
  587. m2m = Person._meta.many_to_many
  588. self.assertIn('friends_base', [f.attname for f in m2m])
  589. related_m2m = Person._meta.get_all_related_many_to_many_objects()
  590. self.assertIn('friends_inherited_rel_+', [o.field.related_query_name() for o in related_m2m])
  591. class VirtualFieldsTests(OptionsBaseTests):
  592. def test_virtual_fields(self):
  593. for model, expected_names in TEST_RESULTS['virtual_fields'].items():
  594. objects = model._meta.virtual_fields
  595. self.assertEqual(sorted([f.name for f in objects]), sorted(expected_names))
  596. class GetFieldByNameTests(OptionsBaseTests):
  597. def test_get_data_field(self):
  598. field_info = Person._meta.get_field_by_name('data_abstract')
  599. self.assertEqual(field_info[1:], (BasePerson, True, False))
  600. self.assertIsInstance(field_info[0], CharField)
  601. def test_get_m2m_field(self):
  602. field_info = Person._meta.get_field_by_name('m2m_base')
  603. self.assertEqual(field_info[1:], (BasePerson, True, True))
  604. self.assertIsInstance(field_info[0], related.ManyToManyField)
  605. def test_get_related_object(self):
  606. field_info = Person._meta.get_field_by_name('relating_baseperson')
  607. self.assertEqual(field_info[1:], (BasePerson, False, False))
  608. self.assertIsInstance(field_info[0], related.ForeignObjectRel)
  609. def test_get_related_m2m(self):
  610. field_info = Person._meta.get_field_by_name('relating_people')
  611. self.assertEqual(field_info[1:], (None, False, True))
  612. self.assertIsInstance(field_info[0], related.ForeignObjectRel)
  613. def test_get_generic_foreign_key(self):
  614. # For historic reasons generic foreign keys aren't available.
  615. with self.assertRaises(FieldDoesNotExist):
  616. Person._meta.get_field_by_name('content_object_base')
  617. def test_get_generic_relation(self):
  618. field_info = Person._meta.get_field_by_name('generic_relation_base')
  619. self.assertEqual(field_info[1:], (None, True, False))
  620. self.assertIsInstance(field_info[0], GenericRelation)