{
"info": {
"author": "Robert Singer",
"author_email": "robertgsinger@gmail.com",
"bugtrack_url": null,
"classifiers": [
"Development Status :: 4 - Beta",
"License :: OSI Approved :: MIT License",
"Programming Language :: Python :: 3.4",
"Programming Language :: Python :: 3.5",
"Programming Language :: Python :: 3.6",
"Programming Language :: Python :: 3.7"
],
"description": "# Django Lifecycle Hooks\n\n[](https://pypi.python.org/pypi/django-lifecycle)\n[](https://img.shields.io/pypi/status/django-lifecycle.svg/)\n\nThis project provides a `@hook` decorator as well as a base model and mixin to add lifecycle hooks to your Django models. Django's built-in approach to offering lifecycle hooks is [Signals](https://docs.djangoproject.com/en/dev/topics/signals/). However, my team often finds that Signals introduce unnesseary indirection and are at odds with Django's \"fat models\" approach.\n\nIn short, you can write model code like this:\n\n```python\nfrom django_lifecycle import LifecycleModel, hook\n\n\nclass Article(LifecycleModel):\n contents = models.TextField()\n updated_at = models.DateTimeField(null=True)\n status = models.ChoiceField(choices=['draft', 'published'])\n editor = models.ForeignKey(AuthUser)\n\n @hook('before_update', when='contents', has_changed=True)\n def on_content_change(self):\n self.updated_at = timezone.now()\n\n @hook('after_update', when=\"status\", was=\"draft\", is_now=\"published\")\n def on_publish(self):\n send_email(self.editor.email, \"An article has published!\")\n```\n\nInstead of overriding `save` and `__init___` in a clunky way that hurts readability:\n\n```python\n # same class and field declarations as above ...\n \n def __init__(self, *args, **kwargs):\n super().__init__(*args, **kwargs)\n self._orig_contents = self.contents\n self._orig_status = self.status\n \n \n def save(self, *args, **kwargs):\n if self.pk is not None and self.contents != self._orig_contents):\n self.updated_at = timezone.now()\n\n super().save(*args, **kwargs)\n\n if self.status != self._orig_status:\n send_email(self.editor.email, \"An article has published!\")\n```\n\n---\n\n**Documentation**: https://rsinger86.github.io/django-lifecycle\n\n**Source Code**: https://github.com/rsinger86/django-lifecycle\n\n---\n\n# Changelog\n\n## 0.6.0 (October 2019)\n* Adds `when_any` hook paramter to watch multiple fields for state changes\n\n## 0.5.0 (September 2019)\n* Adds `was_not` condition\n* Allow watching changes to FK model field values, not just FK references\n\n## 0.4.2 (July 2019)\n* Fixes missing README.md issue that broke install.\n\n## 0.4.1 (June 2019)\n* Fixes [urlman](https://github.com/andrewgodwin/urlman)-compatability.\n\n## 0.4.0 (May 2019)\n* Fixes `initial_value(field_name)` behavior - should return value even if no change. Thanks @adamJLev!\n\n## 0.3.2 (February 2019)\n* Fixes bug preventing hooks from firing for custom PKs. Thanks @atugushev!\n\n## 0.3.1 (August 2018)\n* Fixes m2m field bug, in which accessing auto-generated reverse field in `before_create` causes exception b/c PK does not exist yet. Thanks @garyd203!\n\n## 0.3.0 (April 2018)\n* Resets model's comparison state for hook conditions after `save` called.\n\n## 0.2.4 (April 2018)\n* Fixed support for adding multiple `@hook` decorators to same method.\n\n## 0.2.3 (April 2018)\n* Removes residual mixin methods from earlier implementation.\n\n## 0.2.2 (April 2018)\n* Save method now accepts `skip_hooks`, an optional boolean keyword argument that controls whether hooked methods are called.\n\n## 0.2.1 (April 2018)\n* Fixed bug in `_potentially_hooked_methods` that caused unwanted side effects by accessing model instance methods decorated with `@cache_property` or `@property`. \n\n## 0.2.0 (April 2018)\n* Added Django 1.8 support. Thanks @jtiai!\n* Tox testing added for Python 3.4, 3.5, 3.6 and Django 1.8, 1.11 and 2.0. Thanks @jtiai!\n\n# Testing\n\nTests are found in a simplified Django project in the ```/tests``` folder. Install the project requirements and do ```./manage.py test``` to run them.\n\n# License\n\nSee [License](LICENSE.md).",
"description_content_type": "text/markdown",
"docs_url": null,
"download_url": "",
"downloads": {
"last_day": -1,
"last_month": -1,
"last_week": -1
},
"home_page": "https://github.com/rsinger86/django-lifecycle",
"keywords": "django model lifecycle hooks callbacks",
"license": "MIT",
"maintainer": "",
"maintainer_email": "",
"name": "django-lifecycle",
"package_url": "https://pypi.org/project/django-lifecycle/",
"platform": "",
"project_url": "https://pypi.org/project/django-lifecycle/",
"project_urls": {
"Homepage": "https://github.com/rsinger86/django-lifecycle"
},
"release_url": "https://pypi.org/project/django-lifecycle/0.6.0/",
"requires_dist": null,
"requires_python": "",
"summary": "Declarative model lifecycle hooks.",
"version": "0.6.0"
},
"last_serial": 5942955,
"releases": {
"0.1.0": [
{
"comment_text": "",
"digests": {
"md5": "afc2a507fd7361de33eccfd990bfe277",
"sha256": "595241e758187a74c4726c2086791f397f82cf0c59b35851583c115a655a3215"
},
"downloads": -1,
"filename": "django-lifecycle-0.1.0.tar.gz",
"has_sig": false,
"md5_digest": "afc2a507fd7361de33eccfd990bfe277",
"packagetype": "sdist",
"python_version": "source",
"requires_python": null,
"size": 6275,
"upload_time": "2018-03-28T13:16:19",
"url": "https://files.pythonhosted.org/packages/04/a4/9b5004160ee8d5e928827271ed7007a7c01119f27c99a29e79de328c65f9/django-lifecycle-0.1.0.tar.gz"
}
],
"0.1.1": [
{
"comment_text": "",
"digests": {
"md5": "e26e2c6773000fb05d663e7d0757d1cc",
"sha256": "e6d58224ee6c3db4c266096332669518ac35f0a20284ab7386aa53c9d37a960d"
},
"downloads": -1,
"filename": "django-lifecycle-0.1.1.tar.gz",
"has_sig": false,
"md5_digest": "e26e2c6773000fb05d663e7d0757d1cc",
"packagetype": "sdist",
"python_version": "source",
"requires_python": null,
"size": 6364,
"upload_time": "2018-03-30T00:06:00",
"url": "https://files.pythonhosted.org/packages/57/2e/d04b2347a4de14a531988f205fe7ca7ff5c37ab9d569be92b8408c854a14/django-lifecycle-0.1.1.tar.gz"
}
],
"0.1.2": [
{
"comment_text": "",
"digests": {
"md5": "2129d086f422ae9c5fd0287c3bd99dad",
"sha256": "24cc8481e8ddfdc760f2ba7ebfb0b2423e3e051f5a9bfd5552b1468fede9aded"
},
"downloads": -1,
"filename": "django-lifecycle-0.1.2.tar.gz",
"has_sig": false,
"md5_digest": "2129d086f422ae9c5fd0287c3bd99dad",
"packagetype": "sdist",
"python_version": "source",
"requires_python": null,
"size": 6460,
"upload_time": "2018-03-31T18:28:44",
"url": "https://files.pythonhosted.org/packages/38/f3/46f2f611628f8855ad3207e0b59a3be5d0a62a9aeb5bbd42b9e70ea138fe/django-lifecycle-0.1.2.tar.gz"
}
],
"0.1.3": [
{
"comment_text": "",
"digests": {
"md5": "2edb3618f87f8f6ad736d80498847f88",
"sha256": "22da4a5b75a524c5ae7b56c3edc17917e2699590694ff3060d483054091fe6d1"
},
"downloads": -1,
"filename": "django-lifecycle-0.1.3.tar.gz",
"has_sig": false,
"md5_digest": "2edb3618f87f8f6ad736d80498847f88",
"packagetype": "sdist",
"python_version": "source",
"requires_python": null,
"size": 6420,
"upload_time": "2018-03-31T18:35:25",
"url": "https://files.pythonhosted.org/packages/4b/89/d6e0163db328aff97ba2a4eb99a41304485d1bfad1184e04e50d1a87f170/django-lifecycle-0.1.3.tar.gz"
}
],
"0.2.0": [
{
"comment_text": "",
"digests": {
"md5": "c28e543103b859092332213735a44bb0",
"sha256": "40bdd64dfb68e7f58c0cbb599bb27bf4cd428194ee92e9196b1952472aa5a055"
},
"downloads": -1,
"filename": "django-lifecycle-0.2.0.tar.gz",
"has_sig": false,
"md5_digest": "c28e543103b859092332213735a44bb0",
"packagetype": "sdist",
"python_version": "source",
"requires_python": null,
"size": 6916,
"upload_time": "2018-04-04T01:32:38",
"url": "https://files.pythonhosted.org/packages/2f/25/25f143ae3286feda292131f353ea41f88c9f74eeeacef951747162d293d7/django-lifecycle-0.2.0.tar.gz"
}
],
"0.2.1": [
{
"comment_text": "",
"digests": {
"md5": "ac754c0d346d79346c241e9f5efa71f6",
"sha256": "d4827c032305c6ad23d7f3c35d482d3654500a3bebaf745775f4a3ce7c47f0b5"
},
"downloads": -1,
"filename": "django-lifecycle-0.2.1.tar.gz",
"has_sig": false,
"md5_digest": "ac754c0d346d79346c241e9f5efa71f6",
"packagetype": "sdist",
"python_version": "source",
"requires_python": null,
"size": 7433,
"upload_time": "2018-04-07T22:05:34",
"url": "https://files.pythonhosted.org/packages/e7/63/7862d9f9d47b5c7b579494bab7f499b4563712e6ea6169dc003dc84d3c71/django-lifecycle-0.2.1.tar.gz"
}
],
"0.2.2": [
{
"comment_text": "",
"digests": {
"md5": "6c103caafe9f4f324f5c8e32e20c33d7",
"sha256": "21c7333379130dcf5f7075732741a5a0cdcad13f30b29dcc31d5dfce172303a0"
},
"downloads": -1,
"filename": "django-lifecycle-0.2.2.tar.gz",
"has_sig": false,
"md5_digest": "6c103caafe9f4f324f5c8e32e20c33d7",
"packagetype": "sdist",
"python_version": "source",
"requires_python": null,
"size": 7626,
"upload_time": "2018-04-07T22:49:39",
"url": "https://files.pythonhosted.org/packages/a4/76/0cd558aad01eff7acb6eeff2ffad9bab58b6e15a60aeb943d9a2240cf260/django-lifecycle-0.2.2.tar.gz"
}
],
"0.2.3": [
{
"comment_text": "",
"digests": {
"md5": "7057dbac418d8f02b0aeba4b00027817",
"sha256": "1eed1d5e4f2472aaa02811fabc8df1131fba8cdda4e47901f0461e53a686f961"
},
"downloads": -1,
"filename": "django-lifecycle-0.2.3.tar.gz",
"has_sig": false,
"md5_digest": "7057dbac418d8f02b0aeba4b00027817",
"packagetype": "sdist",
"python_version": "source",
"requires_python": null,
"size": 7611,
"upload_time": "2018-04-08T15:45:44",
"url": "https://files.pythonhosted.org/packages/31/e1/e17b810281885203e48f5be640689508504286cc6193647bca40d9c8a897/django-lifecycle-0.2.3.tar.gz"
}
],
"0.2.4": [
{
"comment_text": "",
"digests": {
"md5": "876575c142af5de3718ff878eee9986c",
"sha256": "0fcaa93d23a0344aa33ecd2384d7023b4ab1b201e0f6e910501397c294440b14"
},
"downloads": -1,
"filename": "django-lifecycle-0.2.4.tar.gz",
"has_sig": false,
"md5_digest": "876575c142af5de3718ff878eee9986c",
"packagetype": "sdist",
"python_version": "source",
"requires_python": null,
"size": 7753,
"upload_time": "2018-04-10T02:52:03",
"url": "https://files.pythonhosted.org/packages/92/ff/4b888f49a9b7845db05db960e7110badffb58d485d614ad2e3cb56442d2d/django-lifecycle-0.2.4.tar.gz"
}
],
"0.2.5": [
{
"comment_text": "",
"digests": {
"md5": "3c55bebee61c1c1458de85fec5bdd2f5",
"sha256": "93537c963bec3c60f566d2e48aa98ab41fedb939c86d3b6f8b411f569c909079"
},
"downloads": -1,
"filename": "django-lifecycle-0.2.5.tar.gz",
"has_sig": false,
"md5_digest": "3c55bebee61c1c1458de85fec5bdd2f5",
"packagetype": "sdist",
"python_version": "source",
"requires_python": null,
"size": 7897,
"upload_time": "2018-04-10T03:17:44",
"url": "https://files.pythonhosted.org/packages/ab/21/6ab9643effae2e6bfd38f059d5402d1bb63a568d875dd434b5870db96313/django-lifecycle-0.2.5.tar.gz"
}
],
"0.3.0": [
{
"comment_text": "",
"digests": {
"md5": "6d947a9887848d88279f58f570a44991",
"sha256": "6372f6850951e1ccaddb50b741020ff5ff2230b50e18e25fded5bf2dd9cdef2e"
},
"downloads": -1,
"filename": "django-lifecycle-0.3.0.tar.gz",
"has_sig": false,
"md5_digest": "6d947a9887848d88279f58f570a44991",
"packagetype": "sdist",
"python_version": "source",
"requires_python": null,
"size": 7975,
"upload_time": "2018-04-13T01:14:18",
"url": "https://files.pythonhosted.org/packages/e7/55/94934ff9e333a63942e8803768757e5cb8dbb5a095dcfbeed5d550960263/django-lifecycle-0.3.0.tar.gz"
}
],
"0.3.1": [
{
"comment_text": "",
"digests": {
"md5": "9ee119de2fd2244292cbedab648c45bc",
"sha256": "90940b7eae5b526deb0ad76d18d5da13555460fc77f1c9f6129b6948fcdee429"
},
"downloads": -1,
"filename": "django-lifecycle-0.3.1.tar.gz",
"has_sig": false,
"md5_digest": "9ee119de2fd2244292cbedab648c45bc",
"packagetype": "sdist",
"python_version": "source",
"requires_python": null,
"size": 8598,
"upload_time": "2018-08-19T05:23:56",
"url": "https://files.pythonhosted.org/packages/8e/84/bd12db7b8557c3c54be78ca7a3280f278e7726968b181336d01a601d1e7d/django-lifecycle-0.3.1.tar.gz"
}
],
"0.3.2": [
{
"comment_text": "",
"digests": {
"md5": "97ee7f482174cd1780cda0fb4842e2a1",
"sha256": "19f213d962e73fa1e2fdde04964f59bd49648606cc5e596ef47ce376e04ad326"
},
"downloads": -1,
"filename": "django-lifecycle-0.3.2.tar.gz",
"has_sig": false,
"md5_digest": "97ee7f482174cd1780cda0fb4842e2a1",
"packagetype": "sdist",
"python_version": "source",
"requires_python": null,
"size": 8711,
"upload_time": "2019-03-07T02:27:24",
"url": "https://files.pythonhosted.org/packages/6a/be/62015fa21b21f248ecfbe895627fe3cd8102b2e0a765912e121a9a1663bd/django-lifecycle-0.3.2.tar.gz"
}
],
"0.4.0": [
{
"comment_text": "",
"digests": {
"md5": "76c953c30be4912466dd467554e0a5ce",
"sha256": "a4b02f6b997f74e7ad2bba4e24dcd5bf40ed2bc7e0e2816954c9fa93bbfa161d"
},
"downloads": -1,
"filename": "django-lifecycle-0.4.0.tar.gz",
"has_sig": false,
"md5_digest": "76c953c30be4912466dd467554e0a5ce",
"packagetype": "sdist",
"python_version": "source",
"requires_python": null,
"size": 8818,
"upload_time": "2019-05-11T20:52:30",
"url": "https://files.pythonhosted.org/packages/26/ee/3567041e69ceefcf68ab92da2c31108759409303c80a7f99922a5a203e3d/django-lifecycle-0.4.0.tar.gz"
}
],
"0.4.1": [
{
"comment_text": "",
"digests": {
"md5": "cfbb25ed9f727b73a2d152f906c0a655",
"sha256": "a49a7ded1ab46f25135a67f5b6886e85571c129c058e0ac3642680c9647fb3a0"
},
"downloads": -1,
"filename": "django-lifecycle-0.4.1.tar.gz",
"has_sig": false,
"md5_digest": "cfbb25ed9f727b73a2d152f906c0a655",
"packagetype": "sdist",
"python_version": "source",
"requires_python": null,
"size": 9507,
"upload_time": "2019-06-30T21:37:19",
"url": "https://files.pythonhosted.org/packages/d4/ab/9daddd333fdf41bf24da744818a00ce8caa8e39d93da466b752b291ce412/django-lifecycle-0.4.1.tar.gz"
}
],
"0.4.2": [
{
"comment_text": "",
"digests": {
"md5": "eb003632d20bfa176fbcd3fb87d3e5ff",
"sha256": "4517255d87c1e5b2394d502aeafe7acc12cf286c49807f701ce4cced8c8f865a"
},
"downloads": -1,
"filename": "django-lifecycle-0.4.2.tar.gz",
"has_sig": false,
"md5_digest": "eb003632d20bfa176fbcd3fb87d3e5ff",
"packagetype": "sdist",
"python_version": "source",
"requires_python": null,
"size": 8979,
"upload_time": "2019-07-06T18:13:02",
"url": "https://files.pythonhosted.org/packages/b2/51/3bf43cccce7aadf663fad7e68bf999a7b0417e74b2344647f925e1b2e1c1/django-lifecycle-0.4.2.tar.gz"
}
],
"0.5.0": [
{
"comment_text": "",
"digests": {
"md5": "c089cef1741282842d68f80e0325628a",
"sha256": "60ee9aad8a1fa3ab2410b60cfd93f4299e928c57f9b8c8c90a49a37aaa0d744d"
},
"downloads": -1,
"filename": "django-lifecycle-0.5.0.tar.gz",
"has_sig": false,
"md5_digest": "c089cef1741282842d68f80e0325628a",
"packagetype": "sdist",
"python_version": "source",
"requires_python": null,
"size": 10690,
"upload_time": "2019-09-29T18:51:53",
"url": "https://files.pythonhosted.org/packages/e7/34/a559e8fc04883f9523afb08ac214b345c73983d6f4df082458936635011f/django-lifecycle-0.5.0.tar.gz"
}
],
"0.6.0": [
{
"comment_text": "",
"digests": {
"md5": "c0618f24712f0ca3fd168c595ba3635b",
"sha256": "de5000e2ccd1435ddd6872f12a9c237b0ea4077ac1f85dd7cb2bd2cf5f658b15"
},
"downloads": -1,
"filename": "django-lifecycle-0.6.0.tar.gz",
"has_sig": false,
"md5_digest": "c0618f24712f0ca3fd168c595ba3635b",
"packagetype": "sdist",
"python_version": "source",
"requires_python": null,
"size": 7180,
"upload_time": "2019-10-08T05:34:31",
"url": "https://files.pythonhosted.org/packages/9b/cb/9c7ea329c8735a0acb8ab73186714efd542fc41e1eac6a03cdf289357088/django-lifecycle-0.6.0.tar.gz"
}
]
},
"urls": [
{
"comment_text": "",
"digests": {
"md5": "c0618f24712f0ca3fd168c595ba3635b",
"sha256": "de5000e2ccd1435ddd6872f12a9c237b0ea4077ac1f85dd7cb2bd2cf5f658b15"
},
"downloads": -1,
"filename": "django-lifecycle-0.6.0.tar.gz",
"has_sig": false,
"md5_digest": "c0618f24712f0ca3fd168c595ba3635b",
"packagetype": "sdist",
"python_version": "source",
"requires_python": null,
"size": 7180,
"upload_time": "2019-10-08T05:34:31",
"url": "https://files.pythonhosted.org/packages/9b/cb/9c7ea329c8735a0acb8ab73186714efd542fc41e1eac6a03cdf289357088/django-lifecycle-0.6.0.tar.gz"
}
]
}