rapidfields.py 2.9 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879
  1. # coding=utf-8
  2. from __future__ import absolute_import
  3. from __future__ import division
  4. from __future__ import print_function
  5. from __future__ import unicode_literals
  6. from django.contrib.contenttypes.fields import GenericForeignKey
  7. from django.contrib.contenttypes.models import ContentType
  8. from rapid.rapidforms import RapidAlternativesField
  9. from django.db import models
  10. __author__ = 'marcos'
  11. """
  12. Model fields specific for Rapid Django.
  13. """
  14. class AlternativeData(GenericForeignKey):
  15. """
  16. A generic relation that Rapid will display as an inline form or a group of data at the
  17. edit and view actions.
  18. Create like a Django GenericForeignKey, but use an AlternativeDataTables instead of a
  19. ForeignKey to ContentTypes.
  20. That is, a model becomes something like this:
  21. class MyModel(models.Model):
  22. alt_data_type = rapidfields.AlternativeDataTables((Model1, Model2))
  23. alt_data_id = models.PositiveIntegerField()
  24. alt_data = rapidfields.AlternativeData('alt_data_type', 'alt_data_id', verbose_name='fill either a model1 or
  25. a model2 object')
  26. In forms, Rapid will display a select widget with the options "model1" and "model2",
  27. and show the appropriate form after selected.
  28. """
  29. is_rapid_alternatives = True
  30. def __init__(self, *args, **kwargs):
  31. verbose_name = kwargs.get('verbose_name')
  32. if 'verbose_name' in kwargs:
  33. del(kwargs['verbose_name'])
  34. super(AlternativeData, self).__init__(*args, **kwargs)
  35. if verbose_name:
  36. self.verbose_name = verbose_name
  37. elif self.name:
  38. self.verbose_name = self.name.replace('_', ' ')
  39. def formfield(self, **kwargs):
  40. kwargs['form_class'] = RapidAlternativesField
  41. # noinspection PyUnresolvedReferences
  42. return super(GenericForeignKey, self).formfield(**kwargs)
  43. class AlternativeDataTables(models.ForeignKey):
  44. """
  45. Use an AlternativeDataTables model field on AlternativeData representations, instead of
  46. a ForeignKey with ContentTypes.
  47. """
  48. is_rapid_alternatives = True
  49. def __init__(self, alternatives=(), **kwargs):
  50. """
  51. Receives the same named parameters of a ForeignKey, but instead of a target table,
  52. receives a list of the tables that may keep the alternative data.
  53. :param alternatives: List of the tables that hold the alternative data.
  54. :param kwargs: Arguments to the ForeignKey, without a relationship target.
  55. """
  56. pks = []
  57. try:
  58. pks = [ContentType.objects.get_for_model(a).pk for a in alternatives]
  59. except RuntimeError:
  60. # Querying ContentType within a content type is an issue at migrations
  61. pass
  62. kwargs['limit_choices_to'] = {'pk__in': pks}
  63. kwargs['to'] = ContentType
  64. super(AlternativeDataTables, self).__init__(**kwargs)
  65. self.alternatives = alternatives