{ "info": { "author": "Aymeric Augustin, Flocklet Technologies", "author_email": "opensource@flocklet.com", "bugtrack_url": null, "classifiers": [ "Development Status :: 5 - Production/Stable", "Environment :: Web Environment", "Framework :: Django", "Framework :: Django :: 1.10", "Framework :: Django :: 1.11", "Framework :: Django :: 1.8", "Framework :: Django :: 1.9", "Intended Audience :: Developers", "License :: OSI Approved :: BSD License", "Operating System :: OS Independent", "Programming Language :: Python", "Programming Language :: Python :: 2", "Programming Language :: Python :: 2.7" ], "description": "django-sequences\n################\n\nThe problem\n===========\n\nDjango's default, implicit primary keys aren't guaranteed to be sequential.\n\nIf a transaction inserts a row and then is rolled back, the sequence counter\nisn't rolled back for performance reasons, creating a gap in primary keys.\n\nThis can cause compliance issues for some use cases such as accounting.\n\nThis risk isn't well known. Since most transactions succeed, values look\nsequential. Gaps will only be revealed by audits.\n\nThe solution\n============\n\ndjango-sequences provides just one function, ``get_next_value``, which is\ndesigned to be used as follows::\n\n from django.db import transaction\n\n from sequences import get_next_value\n\n from invoices.models import Invoice\n\n with transaction.atomic():\n Invoice.objects.create(number=get_next_value('invoice_numbers'))\n\n**The guarantees of django-sequences only apply if you call** ``get_next_value``\n**and save its return value to the database within the same transaction!**\n\nInstallation\n============\n\nInstall django-sequences::\n\n $ pip install django-sequences-py2\n\nAdd it to the list of applications in your project's settings::\n\n INSTALLED_APPS += ['sequences.apps.SequencesConfig']\n\nRun migrations::\n\n $ django-admin migrate\n\nAPI\n===\n\n``get_next_value`` generates a gap-less sequence of integer values::\n\n >>> get_next_value()\n 1\n >>> get_next_value()\n 2\n >>> get_next_value()\n 3\n\nIt supports multiple independent sequences::\n\n >>> get_next_value('cases')\n 1\n >>> get_next_value('cases')\n 2\n >>> get_next_value('invoices')\n 1\n >>> get_next_value('invoices')\n 2\n\nThe first value defaults to 1. It can be customized::\n\n >>> get_next_value('customers', initial_value=1000) # pro growth hacking\n\nThe ``initial_value`` parameter only matters when ``get_next_value`` is called\nfor the first time for a given sequence \u2014 assuming the corresponding database\ntransaction gets committed; as discussed above, if the transaction is rolled\nback, the generated value isn't consumed. It's also possible to initialize a\nsequence in a data migration and not use ``initial_value`` in actual code.\n\nSequences can loop::\n\n >>> get_next_value('seconds', initial_value=0, reset_value=60)\n\nWhen the sequence reaches ``reset_value``, it restarts at ``initial_value``.\nIn other works, it generates ``reset_value - 2``, ``reset_value - 1``,\n``initial_value``, ``initial_value + 1``, etc. In that case, each call to\n``get_next_value`` must provide ``initial_value`` and ``reset_value``.\n\nDatabase transactions that call ``get_next_value`` for a given sequence are\nserialized. In other words, when you call ``get_next_value`` in a database\ntransaction, other callers which attempt to get a value from the same sequence\nwill block until the transaction completes, either with a commit or a rollback.\nYou should keep such transactions short to minimize the impact on performance.\n\nPassing ``nowait=True`` will cause ``get_next_value`` to raise an exception\ninstead of blocking. This will rarely be useful. Also it doesn't work for the\nfirst call. (Arguably this is a bug. Patches welcome.)\n\nCalls to ``get_next_value`` for distinct sequences don't interact with one\nanother.\n\nFinally, passing ``using='...'`` allows selecting the database on which the\ncurrent sequence value is stored. When this parameter isn't provided, the\ncurrent value is stored in the default database for writing to models of the\n``sequences`` application. See below for details.\n\nTo sum up, the complete signature of ``get_next_value`` is::\n\n get_next_value(sequence_name='default', initial_value=1, reset_value=None,\n *, nowait=False, using=None)\n\nUnder the hood, it relies on the database's transactional integrity to\nguarantee that each value will be returned exactly once.\n\nContributing\n============\n\nYou can run tests with::\n\n $ make test\n\nIf you'd like to contribute, please open an issue or a pull request on GitHub!\n\nOther databases\n===============\n\n``INTEGER PRIMARY KEY AUTOINCREMENT`` fields on SQLite don't have this problem.\n\nThe author doesn't know if this problem can happens on MySQL or Oracle. If it\ndoes, then the current implementation of django-sequences should work. If you\ntest this, please open an issue on GitHub to report your findings. Note that\nMySQL won't support the ``nowait`` parameter.\n\nMultiple databases\n==================\n\nSince django-sequences relies on the database to guarantee transactional\nintegrity, the current value for a given sequence must be stored in the same\ndatabase as models containing generated values.\n\nIn a project that uses multiple databases, you must write a suitable database\nrouter to create tables for the ``sequences`` application on all databases\nstoring models containing sequential numbers.\n\nEach database has its own namespace: a sequence with the same name stored in\ntwo databases will have independent counters in each database.\n\nChangelog\n=========\n\n2.2\n---\n\n* Optimized performance on PostgreSQL \u2265 9.5.\n\n2.1\n---\n\n* Provide looping sequences with ``reset_value``.\n\n2.0\n---\n\n* Add support for multiple databases.\n* Add translations.\n* ``nowait`` becomes keyword-only argument.\n* Drop support for Python 2.\n\n1.0\n---\n\n* Initial stable release.\n\n\n", "description_content_type": null, "docs_url": null, "download_url": "", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/flocklet/django-sequences-py2", "keywords": "", "license": "BSD", "maintainer": "", "maintainer_email": "", "name": "django-sequences-py2", "package_url": "https://pypi.org/project/django-sequences-py2/", "platform": "", "project_url": "https://pypi.org/project/django-sequences-py2/", "project_urls": { "Homepage": "https://github.com/flocklet/django-sequences-py2" }, "release_url": "https://pypi.org/project/django-sequences-py2/0.2/", "requires_dist": null, "requires_python": "", "summary": "Forked from augustien's django-sequences, this package aims to maintain py2 compatibility.", "version": "0.2" }, "last_serial": 3290340, "releases": { "0.1": [ { "comment_text": "", "digests": { "md5": "f8f717df65c5d14f9ae2833781708262", "sha256": "1bc4c5c532bcd1d0530a45cdf38aae17a360a765c1129138ebc695654da99b6c" }, "downloads": -1, "filename": "django_sequences_py2-0.1-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "f8f717df65c5d14f9ae2833781708262", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 11126, "upload_time": "2017-10-30T09:32:24", "url": "https://files.pythonhosted.org/packages/67/a1/2102700510f63f7b562dfbc5670c8d03905f4d2d8518d9b99ff17965f232/django_sequences_py2-0.1-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "d96344f15e0c72e8094d689cec8d9c32", "sha256": "4e5f9120a2c166132cb08eb566543128ce94bd0357341310c208a68105e89ff7" }, "downloads": -1, "filename": "django-sequences-py2-0.1.tar.gz", "has_sig": false, "md5_digest": "d96344f15e0c72e8094d689cec8d9c32", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 7300, "upload_time": "2017-10-30T09:27:38", "url": "https://files.pythonhosted.org/packages/f5/30/cff8777d1605b46edc03e3874503854f98827a3405d6b3a2d0a2116506d6/django-sequences-py2-0.1.tar.gz" } ], "0.2": [ { "comment_text": "", "digests": { "md5": "e26758b9c07a8f5d24c703652dec132c", "sha256": "4ef662b7ab5090ea494088fcdb2dc8e7a108b2d7045584bda7c4de4fd4f6c535" }, "downloads": -1, "filename": "django_sequences_py2-0.2-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "e26758b9c07a8f5d24c703652dec132c", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 11124, "upload_time": "2017-10-30T09:38:01", "url": "https://files.pythonhosted.org/packages/d9/20/e042b37dfa1be5732e8276eee6ab9e962f36c04d9dd93bd8a7b33d1fa3c4/django_sequences_py2-0.2-py2.py3-none-any.whl" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "e26758b9c07a8f5d24c703652dec132c", "sha256": "4ef662b7ab5090ea494088fcdb2dc8e7a108b2d7045584bda7c4de4fd4f6c535" }, "downloads": -1, "filename": "django_sequences_py2-0.2-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "e26758b9c07a8f5d24c703652dec132c", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 11124, "upload_time": "2017-10-30T09:38:01", "url": "https://files.pythonhosted.org/packages/d9/20/e042b37dfa1be5732e8276eee6ab9e962f36c04d9dd93bd8a7b33d1fa3c4/django_sequences_py2-0.2-py2.py3-none-any.whl" } ] }