models.py 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  1. # -*- coding: utf-8 -*-
  2. from __future__ import unicode_literals
  3. from django.db import models
  4. from polymorphic import PolymorphicModel
  5. from coin.offers.models import OfferSubscription
  6. from django.db.models.signals import post_save, post_delete
  7. from django.core.exceptions import ObjectDoesNotExist
  8. from django.dispatch import receiver
  9. from coin.resources.models import IPSubnet
  10. """
  11. Implementation note : Configuration is a PolymorphicModel.
  12. The childs of Configuration are the differents models to store
  13. technical informations of a subscription.
  14. To add a new configuration backend, you have to create a new app with a model
  15. which inherit from Configuration.
  16. Your model can implement Meta verbose_name to have human readable name and a
  17. url_namespace variable to specify the url namespace used by this model.
  18. """
  19. class Configuration(PolymorphicModel):
  20. offersubscription = models.OneToOneField(OfferSubscription,
  21. related_name='configuration',
  22. verbose_name='abonnement')
  23. comment = models.CharField(blank=True, max_length=512,
  24. verbose_name="commentaire")
  25. @staticmethod
  26. def get_configurations_choices_list():
  27. """
  28. Génère automatiquement la liste de choix possibles de configurations
  29. en fonction des classes enfants de Configuration
  30. """
  31. return tuple((x().__class__.__name__,x()._meta.verbose_name)
  32. for x in Configuration.__subclasses__())
  33. def model_name(self):
  34. return self.__class__.__name__
  35. model_name.short_description = 'Nom du modèle'
  36. def configuration_type_name(self):
  37. return self._meta.verbose_name
  38. configuration_type_name.short_description = 'Type'
  39. def get_absolute_url(self):
  40. """
  41. Renvoi l'URL d'accès à la page "details" de l'objet
  42. Une url doit être nommée "details"
  43. """
  44. from django.core.urlresolvers import reverse
  45. return reverse('%s:details' % self.get_url_namespace(),
  46. args=[str(self.id)])
  47. def get_url_namespace(self):
  48. """
  49. Renvoi le namespace utilisé par la configuration. Utilise en priorité
  50. celui définit dans la classe enfant dans url_namespace sinon
  51. par défaut utilise le nom de la classe en minuscule
  52. """
  53. if self.url_namespace:
  54. return self.url_namespace
  55. else:
  56. return self.model_name().lower()
  57. class Meta:
  58. verbose_name = 'configuration'
  59. @receiver(post_save, sender=IPSubnet)
  60. def subnet_save_event(sender, **kwargs):
  61. """Fires when a subnet is saved (created/modified). We tell the
  62. configuration backend to do whatever it needs to do with it.
  63. We should use a pre_save signal, so that if anything goes wrong in the
  64. backend (exception raised), nothing is actually saved in the database.
  65. But it has a big problem: the configuration backend will not see the
  66. change, since it has not been saved into the database yet.
  67. That's why we use a post_save signal instead. But surprisingly, all
  68. is well: if we raise an exception here, the IPSubnet object will not
  69. be saved in the database. But the backend *does* see the new state of
  70. the database. It looks like the database rollbacks if an exception is
  71. raised. Whatever the reason, this is not a documented feature of
  72. Django signals.
  73. """
  74. subnet = kwargs['instance']
  75. try:
  76. config = subnet.configuration
  77. config.save_subnet(subnet, kwargs['created'])
  78. except ObjectDoesNotExist:
  79. pass
  80. @receiver(post_delete, sender=IPSubnet)
  81. def subnet_delete_event(sender, **kwargs):
  82. """Fires when a subnet is deleted. We tell the configuration backend to
  83. do whatever it needs to do with it.
  84. """
  85. subnet = kwargs['instance']
  86. try:
  87. config = subnet.configuration
  88. config.delete_subnet(subnet)
  89. except ObjectDoesNotExist:
  90. pass