{ "info": { "author": "Anssi K\u00e4\u00e4ri\u00e4inen", "author_email": "akaariai@gmail.com", "bugtrack_url": null, "classifiers": [ "Development Status :: 5 - Production/Stable", "Environment :: Console", "Framework :: Django", "Intended Audience :: Developers", "License :: OSI Approved :: BSD License", "Operating System :: OS Independent", "Programming Language :: Python :: 2", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.2", "Programming Language :: Python :: 3.3", "Programming Language :: Python :: 3.4" ], "description": "django-reverse-unique\n=====================\n\n.. image:: https://travis-ci.org/akaariai/django-reverse-unique.svg?branch=master\n :target: https://travis-ci.org/akaariai/django-reverse-unique\n :alt: Build Status\n\n.. image:: https://coveralls.io/repos/akaariai/django-reverse-unique/badge.svg?branch=master\n :target: https://coveralls.io/r/akaariai/django-reverse-unique?branch=master\n :alt: Coverage Status\n\nA ReverseUnique model field implementation for Django\n\nThe ReverseUnique field can be used to access single model instances from\nthe reverse side of ForeignKey. Essentially, ReverseUnique can be used to\ngenerate OneToOneField like behaviour in the reverse direction of a normal\nForeignKey. The idea is to add an unique filter condition when traversing the\nforeign key to reverse direction.\n\nTo be able to use reverse unique, you will need a unique constraint for the\nreverse side or otherwise know that only one instance on the reverse side can\nmatch.\n\nExample\n~~~~~~~\n\nIt is always nice to see actual use cases. We will model employees with time\ndependent salaries in this example. This use case could be modelled as::\n\n class Employee(models.Model):\n name = models.TextField()\n\n class EmployeeSalary(models.Model):\n employee = models.ForeignKey(Employee, related_name='employee_salaries')\n salary = models.IntegerField()\n valid_from = models.DateField()\n valid_until = models.DateField(null=True)\n\nIt is possible to save data like \"Anssi has salary of 10\u20ac from 2000-1-1 to 2010-1-1,\nand salary of 11\u20ac from 2010-1-1 to infinity (modelled as None in the models).\n\nUnfortunately when using these models it isn't trivial to just fetch the\nemployee and his salary to display to the user. It would be possible to do so by\nlooping through all salaries of an employee and checking which of the EmployeeSalaries\nis currently in effect. However, this approach has a couple of drawbacks:\n\n - It doesn't perform well in list views\n - Most of all It is impossible to execute queries that refer the employee's current\n salary. For example, getting the top 10 best paid employees or the average\n salary of employees is impossible to achieve in single query.\n\nDjango-reverse-unique to the rescue! Lets change the Employee model to::\n\n from datetime import datetime\n class Employee(models.Model):\n name = models.TextField()\n current_salary = models.ReverseUnique(\n \"EmployeeSalary\",\n filter=Q(valid_from__gte=datetime.now) &\n (Q(valid_until__isnull=True) | Q(valid_until__lte=datetime.now))\n )\n\nNow we can simply issue a query like::\n\n Employee.objects.order_by('current_salary__salary')[0:10]\n\nor::\n\n Employee.objects.aggregate(avg_salary=Avg('current_salary__salary'))\n\nWhat did happen there? We added a ReverseUnique field. This field is the reverse\nof the EmployeeSalary.employee foreign key with an additional restriction that the\nrelation must be valid at the moment the query is executed. The first\n\"EmployeeSalary\" argument refers to the EmployeeSalary model (we have to use\nstring as the EmployeeSalary model is defined after the Employee model). The\nfilter argument is a Q-object which can refer to the fields of the remote model.\n\nAnother common problem for Django applications is how to store model translations.\nThe storage problem can be solved with django-reverse-unique. Here is a complete\nexample for that use case::\n\n from django.db import models\n from reverse_unique import ReverseUnique\n from django.utils.translation import get_language, activate\n\n class Article(models.Model):\n active_translation = ReverseUnique(\"ArticleTranslation\",\n filters=Q(lang=get_language))\n\n class ArticleTranslation(models.Model):\n article = models.ForeignKey(Article)\n lang = models.CharField(max_length=2)\n title = models.CharField(max_length=100)\n body = models.TextField()\n\n class Meta:\n unique_together = ('article', 'lang')\n\n activate(\"fi\")\n objs = Article.objects.filter(\n active_translation__title__icontains=\"foo\"\n ).select_related('active_translation')\n # Generated query is\n # select article.*, article_translation.*\n # from article\n # join article_translation on article_translation.article_id = article.id\n # and article_translation.lang = 'fi'\n # If you activate \"en\" instead, the lang is changed.\n # Now you can access objs[0].active_translation without generating more\n # queries.\n\nSimilarly one could fetch current active reservation for a hotel room etc.\n\nInstallation\n~~~~~~~~~~~~\n\nThe requirement for ReverseUnique is Django 1.6+. You will need to place the\nreverse_unique directory in Python path, then just use it like done in above\nexample. The tests (reverse_unique/tests.py) contain a couple more examples.\nEasiest way to install is::\n\n pip install -e git://github.com/akaariai/django-reverse-unique.git#egg=reverse_unique\n\nTesting\n~~~~~~~\n\nYou'll need to have a supported version of Django installed. Go to\ntestproject directory and run::\n\n python manage.py test reverse_unique", "description_content_type": null, "docs_url": null, "download_url": null, "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/akaariai/django-reverse-unique", "keywords": null, "license": "BSD", "maintainer": null, "maintainer_email": null, "name": "django-reverse-unique", "package_url": "https://pypi.org/project/django-reverse-unique/", "platform": "UNKNOWN", "project_url": "https://pypi.org/project/django-reverse-unique/", "project_urls": { "Homepage": "https://github.com/akaariai/django-reverse-unique" }, "release_url": "https://pypi.org/project/django-reverse-unique/1.0/", "requires_dist": null, "requires_python": null, "summary": "A ReverseUnique field implementation for Django", "version": "1.0" }, "last_serial": 1707538, "releases": { "1.0": [ { "comment_text": "", "digests": { "md5": "cf39f2253c9ec6d77f268b115dd77a20", "sha256": "f2dbbfee2467bf6d43285d80e6c0c5dbf3169943b81777e1fbeeeff8e936253f" }, "downloads": -1, "filename": "django_reverse_unique-1.0-py2.py3-none-any.whl", "has_sig": true, "md5_digest": "cf39f2253c9ec6d77f268b115dd77a20", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 8929, "upload_time": "2015-09-04T06:39:38", "url": "https://files.pythonhosted.org/packages/5d/4f/7e483a8d3dcca5d2f4b651d2f935df94e56d6862072bca8ca3a5c202e2d6/django_reverse_unique-1.0-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "7e24ca83d113bc2cb7fec521f1122a1f", "sha256": "3eb5fda7d79aa15bdaae564ebfae4e9c5fde6fd8c7bcf0079a06c03e393455f9" }, "downloads": -1, "filename": "django-reverse-unique-1.0.tar.gz", "has_sig": true, "md5_digest": "7e24ca83d113bc2cb7fec521f1122a1f", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 5876, "upload_time": "2015-09-04T06:39:42", "url": "https://files.pythonhosted.org/packages/62/8f/76c1a9959b3bfa70c482a5460516f71f0041341ef29ea80ea4658630a78a/django-reverse-unique-1.0.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "cf39f2253c9ec6d77f268b115dd77a20", "sha256": "f2dbbfee2467bf6d43285d80e6c0c5dbf3169943b81777e1fbeeeff8e936253f" }, "downloads": -1, "filename": "django_reverse_unique-1.0-py2.py3-none-any.whl", "has_sig": true, "md5_digest": "cf39f2253c9ec6d77f268b115dd77a20", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 8929, "upload_time": "2015-09-04T06:39:38", "url": "https://files.pythonhosted.org/packages/5d/4f/7e483a8d3dcca5d2f4b651d2f935df94e56d6862072bca8ca3a5c202e2d6/django_reverse_unique-1.0-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "7e24ca83d113bc2cb7fec521f1122a1f", "sha256": "3eb5fda7d79aa15bdaae564ebfae4e9c5fde6fd8c7bcf0079a06c03e393455f9" }, "downloads": -1, "filename": "django-reverse-unique-1.0.tar.gz", "has_sig": true, "md5_digest": "7e24ca83d113bc2cb7fec521f1122a1f", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 5876, "upload_time": "2015-09-04T06:39:42", "url": "https://files.pythonhosted.org/packages/62/8f/76c1a9959b3bfa70c482a5460516f71f0041341ef29ea80ea4658630a78a/django-reverse-unique-1.0.tar.gz" } ] }