{ "info": { "author": "Emil Madsen", "author_email": "emil@magenta.dk", "bugtrack_url": null, "classifiers": [ "Environment :: Web Environment", "Framework :: Django", "Intended Audience :: Developers", "License :: OSI Approved", "License :: OSI Approved :: Mozilla Public License 2.0 (MPL 2.0)", "Operating System :: OS Independent", "Programming Language :: Python", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "Topic :: Internet :: WWW/HTTP", "Topic :: Internet :: WWW/HTTP :: Dynamic Content", "Topic :: Internet :: WWW/HTTP :: WSGI", "Topic :: Software Development :: Libraries :: Python Modules" ], "description": "Django Queryset Constraint\n==========================\n\n[![Build Status](https://travis-ci.com/magenta-aps/django_queryset_constraint.svg?branch=master)](https://travis-ci.com/magenta-aps/django_queryset_constraint)\n\nThis library enables one to write reliable data invariants, by compiling Django\nQuerysets to database insert/update triggers, via. the migration system.\n\nMotivation\n==========\nDjango has a built-in signal system, which emits signals on various events, for\ninstance model creations, updates and deletions. However these signals are not\nemmited for queryset operations, and as such cannot be used to maintain data\ninvariants.\n\nAn attempt to ratify this was made with the [Django Queryset Signals](https://github.com/magenta-aps/django-queryset-signals) library.\nWhile this library comes closer to a reliable solution, it does not succeed,\nas it is stil possible to break the data invariants by accessing the database\ndirectly.\n\nDatabase Constraint Triggers will effectively protect against all scenarios.\n\nInstallation\n============\n```\npip install django_queryset_constraint\n```\n\nUsage\n=====\n\n- Add the `django_queryset_constraint` app to `INSTALLED_APPS`:\n\n```\n# settings.py\nINSTALLED_APPS = {\n 'django_queryset_constraint',\n ...\n}\n```\n\n*Note: This should be done **before** any apps that will be checked*\n\n- Add `QuerysetConstraint` to `constraints` to the Meta class of the models to checked:\n\n```\n# models.py\nfrom django.db import models\nfrom django.db.models import Count\nfrom django_queryset_constraint import M, QuerysetConstraint\n\n\nclass Topping(models.Model):\n name = models.CharField(max_length=30)\n\n def __str__(self):\n return self.name\n\nclass PizzaTopping(models.Model):\n class Meta:\n unique_together = (\"pizza\", \"topping\")\n constraints = [\n # A pizza with more than 5 toppings gets soggy\n QuerysetConstraint(\n name='At most 5 toppings',\n queryset=M().objects.values(\n 'pizza'\n ).annotate(\n num_toppings=Count('topping')\n ).filter(\n num_toppings__gt=5\n ),\n ),\n # This constraint should be self-explanatory for civilized people\n QuerysetConstraint(\n name='No pineapple',\n queryset=M().objects.filter(\n topping__name=\"Pineapple\"\n )\n ),\n ]\n\n pizza = models.ForeignKey('Pizza', on_delete=models.CASCADE)\n topping = models.ForeignKey(Topping, on_delete=models.CASCADE)\n\nclass Pizza(models.Model):\n name = models.CharField(max_length=30)\n toppings = models.ManyToManyField(Topping, through=PizzaTopping)\n\n def __str__(self):\n return self.name\n```\n\n- Make migrations: `python manage.py makemigrations`\n- Run migrations: `python manage.py migrate`\n\n*Note: Complex triggers introduce performance overhead.*\n\nSupport Matrix\n==============\nThis app supports the following combinations of Django and Python:\n\n| Django | Python |\n| ---------- | ----------------------- |\n| 2.2 | 3.5, 3.6, 3.7 |", "description_content_type": "text/markdown", "docs_url": null, "download_url": "https://github.com/magenta-aps/django_queryset_constraint/archive/master.zip", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/magenta-aps/django_queryset_constraint", "keywords": "django", "license": "MPL-2.0", "maintainer": "", "maintainer_email": "", "name": "django-queryset-constraint", "package_url": "https://pypi.org/project/django-queryset-constraint/", "platform": "", "project_url": "https://pypi.org/project/django-queryset-constraint/", "project_urls": { "Download": "https://github.com/magenta-aps/django_queryset_constraint/archive/master.zip", "Homepage": "https://github.com/magenta-aps/django_queryset_constraint", "Source": "https://github.com/magenta-aps/django_queryset_constraint" }, "release_url": "https://pypi.org/project/django-queryset-constraint/1.0.0.0/", "requires_dist": null, "requires_python": ">=3.5", "summary": "A library for writing reliable data invariants in Django.", "version": "1.0.0.0" }, "last_serial": 5950023, "releases": { "1.0.0.0": [ { "comment_text": "", "digests": { "md5": "9960b2c257162f54ae6f720920e3d7b9", "sha256": "ea88975cb53c5a913ab1b268a3c2562391adb5ddcc7efd83fdbfb67f50bb0229" }, "downloads": -1, "filename": "django_queryset_constraint-1.0.0.0.tar.gz", "has_sig": false, "md5_digest": "9960b2c257162f54ae6f720920e3d7b9", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.5", "size": 13994, "upload_time": "2019-10-09T14:10:03", "url": "https://files.pythonhosted.org/packages/0c/81/7adbf3a758e221dd953a033f831b3da2ca9b9f80ffb0f6b4f24363c7d9f1/django_queryset_constraint-1.0.0.0.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "9960b2c257162f54ae6f720920e3d7b9", "sha256": "ea88975cb53c5a913ab1b268a3c2562391adb5ddcc7efd83fdbfb67f50bb0229" }, "downloads": -1, "filename": "django_queryset_constraint-1.0.0.0.tar.gz", "has_sig": false, "md5_digest": "9960b2c257162f54ae6f720920e3d7b9", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.5", "size": 13994, "upload_time": "2019-10-09T14:10:03", "url": "https://files.pythonhosted.org/packages/0c/81/7adbf3a758e221dd953a033f831b3da2ca9b9f80ffb0f6b4f24363c7d9f1/django_queryset_constraint-1.0.0.0.tar.gz" } ] }