{ "info": { "author": "Ramast Magdy", "author_email": "ramast.com@gmail.com", "bugtrack_url": null, "classifiers": [ "Development Status :: 4 - Beta", "Intended Audience :: Developers", "License :: OSI Approved :: MIT License", "Programming Language :: Python :: 2", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.4", "Topic :: Software Development :: Libraries :: Python Modules" ], "description": "**Model helpers** are small collection of django functions and classes that make working with models easier. All functions here are compliant with pylint and has test cases with over 95% code coverage. This doc describe each of these helpers.\n\nupload_to_\n Pass this function to your `FileField` as `upload_to` argument\n\ncached_model_property_\n Decorate a model function with that decorator to cache function's result\n\nChoices_\n A feature rich solution for implementing choice field\n\nKeyValueField_\n A field that can store multiple key/value entries in a human readable form\n \n.. _upload_to:\n\n**model\\_helpers.upload\\_to**\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nPass ``model_helpers.upload_to`` as ``upload_to`` parameter for any FileField or ImageField. This will - by default - generate slugified version of the file name. By default each model get its own storage folder named after model's name.\n\n``upload_to`` function also block files with certain harmful extensions like \"php\" or \"py\" from being uploaded.\n\n**Sample usage:**\n\n::\n\n import model_helpers\n\n class Profile(models.model):\n name = CharField(max_length=100)\n picture = ImageField(upload_to=model_helpers.upload_to)\n\nuploaded images for this model will be stored in: ``media/Profile//``.\n\n**settings**\n\nsettings for ``upload_to`` function should be placed in ``UPLOAD_TO_OPTIONS`` inside your *settings.py* file These are the default settings\n\n::\n\n settings.UPLOAD_TO_OPTIONS = {\n \"black_listed_extensions\": [\"php\", \"html\", \"htm\", \"js\", \"vbs\", \"py\", \"pyc\", \"asp\", \"aspx\", \"pl\"],\n \"max_filename_length\": 40,\n \"file_name_template\": \"{model_name}/%Y/{filename}.{extension}\"\n }\n\n- ``black_listed_extensions`` prevent any file with any of these extensions from being saved.\n- ``max_filename_length`` trim filename if it exceeds certain length to mitigate DB errors when user upload long filename\n- ``file_name_template`` controls where the file should be saved.\n\n**specifying ``file_name_template``**\n\n``file_name_template`` pass your string to strftime() function; ``'%Y'`` in the example above is the four-digit year. other accepted variables are:\n\n- ``model_name``: name of the model which the file is being uploaded for.\n- ``filename``: name of the file - without extension - after it has been processed by ``upload_to`` (trimmed and slugified)\n- ``extension``: file's extension\n- ``instance``: the model instance passed to ``upload_to`` function\n\nFor example to save uploaded files to a directory like this\n\n::\n\n model name/current year/current month/instance's name(dot)file's extension\n\nyou do\n\n::\n\n UPLOAD_TO_OPTIONS = {\"file_name_template\": \"{model_name}/%Y/%m/{instance.name}.{extension}\" }\n\n**customizing ``upload_to`` per model**\n\nIf you want to have different ``upload_to`` options for different models, use ``UploadTo`` class instead. For example to have ``ImageField`` that allow all file extensions, You can do this:\n\n::\n\n my_image = models.ImageField(upload_to=models_helper.UploadTo(black_listed_extensions=[])\n\n``UploadTo`` class accepts all ``upload_to`` settings documented above. You can also inherit from this class if you want to have very custom file naming schema (like if you want file name be based on its md5sum)\n\n.. _cached_model_property:\n\ncached_model_property decorator\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n``cached_model_property`` is a decorator for model functions that takes no arguments. The decorator convert the function into a property that support caching out of the box\n\n**Note**: ``cached_model_property`` is totally different from django's ``cached_property`` the later is not true caching but rather memorizing function's return value.\n\n**Sample usage:**\n\n::\n\n class Team(models.Model):\n @cached_model_property\n def points(self):\n # Do complex DB queries\n return result\n\n @cached_model_property(readonly=False)\n def editable_points(self):\n # get result\n return result\n\n @cached_model_property(cache_timeout=1)\n def one_second_cache(self):\n # get result\n return result\n\nNow try\n\n::\n\n team = Team.objects.first()\n\n- ``team.points`` <-- complex DB queries will happen, result will be returned\n- ``team.points`` <-- this time result is returned from cache (points function is not called\n- ``del team.points`` <-- points value has been removed from cache\n- ``team.points`` <-- complex DB queries will happen, result will be returned\n\n**How does it work?**: first time the decorator store the function output in the cache with ``key = \"__\"`` so if you have two models with same name, or have model that provide no primary key you can't use this decorator.\n\nset ``readonly`` parameter to ``False`` to make the property writeable\n\n``team.editable_points = 88``\n\nIn this case the assigned value will replace the value stored in the cache\n\n``team.editable_points`` returns 88\n\nI personally don't use the writable cached property option but might be useful to someone else\n\n.. _Choices:\n\nChoices class (inspired by `Django Choices `_. )\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nDealing with Django's ``choices`` attribute is a pain. Here is a proper way of implementing choice field in Django\n\n::\n\n class Student(models.Model):\n FRESHMAN = 'FR'\n SOPHOMORE = 'SO'\n JUNIOR = 'JR'\n SENIOR = 'SR'\n YEAR_IN_SCHOOL_CHOICES = (\n (FRESHMAN, 'Freshman'),\n (SOPHOMORE, 'Sophomore'),\n (JUNIOR, 'Junior'),\n (SENIOR, 'Senior'),\n )\n year_in_school = models.CharField(\n max_length=2,\n choices=YEAR_IN_SCHOOL_CHOICES,\n default=FRESHMAN)\n\nThen you can do\n\n::\n\n student = Student.objects.first()\n if student.year_in_school == Student.SENIOR:\n # do some senior stuff\n\nWith Choices class this becomes\n\n::\n\n YEAR_IN_SCHOOL_CHOICES = Choices({\n \"freshman\": \"FR\",\n \"sophomore\": \"SO\",\n \"junior\": \"JR\",\n \"Senior\": \"SR\"\n })\n\n\n class Student(models.Model):\n year_in_school = models.CharField(\n max_length=2,\n choices=YEAR_IN_SCHOOL_CHOICES(),\n default=YEAR_IN_SCHOOL_CHOICES.freshman)\n\nThen you can do\n\n::\n\n student = Student.objects.first()\n if student.year_in_school == YEAR_IN_SCHOOL_CHOICES.senior:\n # do some senior stuff\n\n``YEAR_IN_SCHOOL_CHOICES`` is a readonly OrderedDict and you can treat it as such. for example: ``YEAR_IN_SCHOOL_CHOICES.keys()`` or ``YEAR_IN_SCHOOL_CHOICES.iteritems()``\n\n``Choices`` class is more flexible because it allow you to specify 3 values. choice name, choice db value, choice display name. The example above can be better written like that\n\n::\n\n YEAR_IN_SCHOOL_CHOICES = Choices({\n \"freshman\": {\"id\": 0, \"display\": \"New comer\"},\n \"sophomore\": 1,\n \"junior\": 2,\n \"Senior\": 3\n }, order_by=\"id\")\n\n\n class Student(models.Model):\n year_in_school = models.SmalllIntegerField(\n choices=YEAR_IN_SCHOOL_CHOICES(),\n default=YEAR_IN_SCHOOL_CHOICES.freshman)\n\nThen you can do something like this\n\n::\n\n Student.objects.filter(\n year_in_school__gt=YEAR_IN_SCHOOL_CHOICES.sophomore)\n\nTo return all students in grades higher than Sophomore\n\n- A choice can be defined as key/value ``\"sophomore\": 1`` in which case display name will be code name capitalized ``\"Sophomore\"`` and will be saved in DB as number ``1``\n- A choice can be fully defined as key/dict ``\"freshman\": {\"id\": 0, \"display\": \"New comer\"}`` in which case display name will be ``\"New comer\"`` and id will be ``0``\n\nDefining extra keys to use in your code.\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\nAs mentioned before ``Choices`` can be treated as an OrderedDictionary and so you should feel free to use the free functionality, for example adding extra keys\n\n::\n\n AVAILABLE_SETTINGS = Choices({\n \"max_page_width\": {\"id\": 0, \"display\": \"Maximum page width in pixels\", \"default\": 100})\n\nthen in your code you can do\n\n::\n\n settings = Settings.objects.filter(name=AVAILABLE_SETTINGS.max_page_width).first()\n if settings:\n return settings.value\n return AVAILABLE_SETTINGS[\"max_page_width\"][\"default\"]\n\nOrdering your ``Choices``\n^^^^^^^^^^^^^^^^^^^^^^^^^\n\nAssuming you have a big list of choices you might prefer to ask Choices class to order them for you.\n\n**Example:**\n\n::\n\n Choices({\n \"usa\": {\"display\": \"United States\", \"id\": 0},\n \"egypt\": 1,\n \"uk\": {\"display\": \"United Kingdom\", \"id\": 2},\n \"ua\": {\"display\": \"Ukraine\", \"id\": 3}\n }, order_by=\"display\")\n\nThe fields will be in the order \"Egypt\", \"Ukraine\", \"United Kingdom\", \"United States\".\n\n``order_by=\"id\"`` will order the list by id\n\nIf you don't want any sort of ordering then set ``order_by=None`` and in this case its better that you pass your choices as tuple of dictionaries to maintain order\n\n::\n\n Choices((\n (\"uk\", {\"display\": \"United Kingdom\", \"id\": 2),\n (\"usa\", {\"display\": \"United States\", \"id\": 0),\n (\"egypt\", 1),\n (\"ua\": {\"display\": \"Ukraine\", \"id\": 3})\n ), order_by=None)\n\n**Note:** By default choices are ordered by display name\n\nUseful functions of ``Choices`` class\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\n- ``get_display_name``: given choice id, return the display name of that id. same as model's ``get__display()``\n- ``get_code_name``: Given choice id same as ``get_display_name`` but return code name\n- ``get_value``: Given choice id, return value of any key defined inside choice entry\n\n**Example:**\n\n::\n\n CHOICES_EXAMPLE = Choices({\"my_key\": {\"id\": 0, \"display\": \"Display Of My Key\", \"additional_key\": 1234})\n >>> CHOICES_EXAMPLE.get_display_name(0)\n \"Display Of My Key\"\n >>> CHOICES_EXAMPLE.get_code_name(0)\n \"my_key\"\n >>> CHOICES_EXAMPLE.get_value(0, \"additional_key\")\n 1234\n\n.. _KeyValueField:\n\n**model\\_helpers.KeyValueField**\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nSometimes you need to have a simple key/value field. most developers would rely on ``JsonField`` which is good for some use cases but people using django admin may not like to modify json object that look like this\n\n::\n\n {\"key1\": \"value of some sort\", \"key2\": \"value containing \\\" character\"}\n\n``KeyValueField`` serialize objects in a more readable way. the dictionary above would be stored and displayed like this.\n\n::\n\n key1 = value of some sort\n key2 = value containing \" character\n\nThat's it. For you as a developer you will access your ``KeyValueField`` as a dictionary.\n\n**Example**:\n\n::\n\n class MyModel(models.Model):\n options = KeyValueField(separator=\":\")\n\n >> my_model.options = \"key1 : val1 \\n key2 : val2\"\n >> my_model.options\n {\"key1\": \"val1\", \"key2\": \"val2\"}\n >>> str(my_model.options)\n \"key1 : val1 \\n key2 : val2\"\n\nYou can find more examples in the test file ``tests/test_key_value_field.py``\n\n**``KeyValueField`` is NOT good for:**\n\n- Maintain original value's datatype. all values are converted to unicode strings\n- Store a multiline value", "description_content_type": null, "docs_url": null, "download_url": "UNKNOWN", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/rewardz/django_model_helpers", "keywords": "django models keyvaluefield cached_model_property", "license": "MIT", "maintainer": null, "maintainer_email": null, "name": "django_model_helpers", "package_url": "https://pypi.org/project/django_model_helpers/", "platform": "UNKNOWN", "project_url": "https://pypi.org/project/django_model_helpers/", "project_urls": { "Download": "UNKNOWN", "Homepage": "https://github.com/rewardz/django_model_helpers" }, "release_url": "https://pypi.org/project/django_model_helpers/1.2.1/", "requires_dist": null, "requires_python": null, "summary": "Helpful functions and classes for your django app's models", "version": "1.2.1" }, "last_serial": 1958961, "releases": { "1.0.1": [ { "comment_text": "", "digests": { "md5": "07be11548e25df90b46155287d92a3c7", "sha256": "d74e21782f40f2baf6720f9ee12ad7b48dffab328a43fcf686245fc6a471fcf7" }, "downloads": -1, "filename": "django_model_helpers-1.0.1-py2-none-any.whl", "has_sig": false, "md5_digest": "07be11548e25df90b46155287d92a3c7", "packagetype": "bdist_wheel", "python_version": "py2", "requires_python": null, "size": 11198, "upload_time": "2015-12-05T06:32:19", "url": "https://files.pythonhosted.org/packages/2a/52/e77f47f3c200e561bbd14e3c0a3b10e534a44de09b940655155ba5117cb7/django_model_helpers-1.0.1-py2-none-any.whl" }, { "comment_text": "", "digests": { "md5": "935ef20db965599b61919f3680cfda42", "sha256": "9d3dbbedfefd1eed874973e8f9391e8942fff6bc38feac6e0dce462c565ae971" }, "downloads": -1, "filename": "django_model_helpers-1.0.1.tar.gz", "has_sig": false, "md5_digest": "935ef20db965599b61919f3680cfda42", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 8985, "upload_time": "2015-12-05T06:32:25", "url": "https://files.pythonhosted.org/packages/0a/c3/552cffdc3ab0d330165aae4870acb7a994bd81031f8f551aab95de8dc076/django_model_helpers-1.0.1.tar.gz" } ], "1.0.2": [ { "comment_text": "", "digests": { "md5": "7081a6bfb9c0ee17b4e860d07ee273ba", "sha256": "a99932b575646d06560380049e197c479d4d6c50b566df83a15efafb452da57f" }, "downloads": -1, "filename": "django_model_helpers-1.0.2-py2-none-any.whl", "has_sig": false, "md5_digest": "7081a6bfb9c0ee17b4e860d07ee273ba", "packagetype": "bdist_wheel", "python_version": "py2", "requires_python": null, "size": 13584, "upload_time": "2015-12-05T17:58:19", "url": "https://files.pythonhosted.org/packages/34/d0/bbee37fa011ddbc0c330ebc1721249ef57855b2c9365a93bb2e813f1d679/django_model_helpers-1.0.2-py2-none-any.whl" }, { "comment_text": "", "digests": { "md5": "147ba8e0a362609c35d92589b9359401", "sha256": "dc5402ac15cc19edb28a006af8b8a6f02d06cbddf8a51a2bf502255ca2abf3c2" }, "downloads": -1, "filename": "django_model_helpers-1.0.2.tar.gz", "has_sig": false, "md5_digest": "147ba8e0a362609c35d92589b9359401", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 10501, "upload_time": "2015-12-05T17:58:26", "url": "https://files.pythonhosted.org/packages/24/ea/4596ff50950dcd05a57b05f84cfe164e40502130bedca2eddd727cfdee7c/django_model_helpers-1.0.2.tar.gz" } ], "1.0.3": [ { "comment_text": "", "digests": { "md5": "f7455e2dc72ea81a86aea300de29476e", "sha256": "fc301ffb3d2118bc0a50a15e971e3b488bc57de30a83ee6233be2ef6c6b18cb4" }, "downloads": -1, "filename": "django_model_helpers-1.0.3-py2-none-any.whl", "has_sig": false, "md5_digest": "f7455e2dc72ea81a86aea300de29476e", "packagetype": "bdist_wheel", "python_version": "py2", "requires_python": null, "size": 13597, "upload_time": "2015-12-17T05:29:37", "url": "https://files.pythonhosted.org/packages/4f/a8/b4df16019fcc27d13d87f4f03b10d7b51605023d8043abcbdbaa09c72531/django_model_helpers-1.0.3-py2-none-any.whl" }, { "comment_text": "", "digests": { "md5": "540e166c8a109cfa9a7c4d79316ad083", "sha256": "7be80b506a9e6d3c303b2af217b3c8b0b728ea45b5ccc5e4403dd2e89f559bed" }, "downloads": -1, "filename": "django_model_helpers-1.0.3.tar.gz", "has_sig": false, "md5_digest": "540e166c8a109cfa9a7c4d79316ad083", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 10517, "upload_time": "2015-12-17T05:29:44", "url": "https://files.pythonhosted.org/packages/c2/21/46d9d20cd78d7f355b15ec82b9330650bc6feeeeaf18fb2b630331997fd0/django_model_helpers-1.0.3.tar.gz" } ], "1.0.4": [ { "comment_text": "", "digests": { "md5": "ced17470ed789a45359363bf17fe1df6", "sha256": "8e3b2a9441c2b8f43602e09ce6d0a0ca8b636135700eff777e7890a077b14d15" }, "downloads": -1, "filename": "django_model_helpers-1.0.4-py2-none-any.whl", "has_sig": false, "md5_digest": "ced17470ed789a45359363bf17fe1df6", "packagetype": "bdist_wheel", "python_version": "py2", "requires_python": null, "size": 15373, "upload_time": "2016-01-01T12:13:45", "url": "https://files.pythonhosted.org/packages/34/f1/6f3ed1df2136ea44e025d1aa9879ebcd764cdf7caff25c1bbdb920ceb509/django_model_helpers-1.0.4-py2-none-any.whl" }, { "comment_text": "", "digests": { "md5": "7de0300c12d24b369737f2183f8e5485", "sha256": "01fbb6cf88f34a0ef1f08236819c6c49559bcec9b46a2f0bba947d99eaa94e8e" }, "downloads": -1, "filename": "django_model_helpers-1.0.4.tar.gz", "has_sig": false, "md5_digest": "7de0300c12d24b369737f2183f8e5485", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 11379, "upload_time": "2016-01-01T12:14:58", "url": "https://files.pythonhosted.org/packages/f2/62/01386f915474b4270c1e46b1e9e81de5b12896015d4f151a7efa1a6f290c/django_model_helpers-1.0.4.tar.gz" } ], "1.2.0": [ { "comment_text": "", "digests": { "md5": "5de3ab7a6a313129158e0674fefcfe9b", "sha256": "3d521809ee0d8a5771855c9829950a6d8b4ec33405d4c78eb047343f093122d4" }, "downloads": -1, "filename": "django_model_helpers-1.2.0-py3-none-any.whl", "has_sig": false, "md5_digest": "5de3ab7a6a313129158e0674fefcfe9b", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 15445, "upload_time": "2016-02-09T09:19:00", "url": "https://files.pythonhosted.org/packages/d5/c6/8963dca3d239260db67e8255d7f3aa22709c472a74c8b6fc658446def5df/django_model_helpers-1.2.0-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "3af49b8adef436f2ec634c86f5445bc6", "sha256": "034fdd7b3188609ae4cb4958db61141f05fbc4bfab3af106fdcb79db5b658508" }, "downloads": -1, "filename": "django_model_helpers-1.2.0.tar.gz", "has_sig": false, "md5_digest": "3af49b8adef436f2ec634c86f5445bc6", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 11467, "upload_time": "2016-02-09T09:19:10", "url": "https://files.pythonhosted.org/packages/7d/35/c63d5ea4d4d977b94355b86da8d921267ab7f94dcb8808790d3804bc2817/django_model_helpers-1.2.0.tar.gz" } ], "1.2.1": [ { "comment_text": "", "digests": { "md5": "0fa9d4d957a39be6a4c9a8b577822341", "sha256": "b9c230ccecc553a901003a477452eb5bf5f430b267e87dd7be6793dbc7c07474" }, "downloads": -1, "filename": "django_model_helpers-1.2.1-py3-none-any.whl", "has_sig": false, "md5_digest": "0fa9d4d957a39be6a4c9a8b577822341", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 15471, "upload_time": "2016-02-16T10:07:34", "url": "https://files.pythonhosted.org/packages/b8/56/0783ebdfedac321f929ac0196b920cdf23905f491db7ec6e636f9d33ab9a/django_model_helpers-1.2.1-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "03a4c2887e5ebe4501c13b419252b5d0", "sha256": "6b5c58c25b9c7acab2e8fbe91aca3aa28d2e499874b22d78af0f92ccc779e60d" }, "downloads": -1, "filename": "django_model_helpers-1.2.1.tar.gz", "has_sig": false, "md5_digest": "03a4c2887e5ebe4501c13b419252b5d0", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 11479, "upload_time": "2016-02-16T10:07:42", "url": "https://files.pythonhosted.org/packages/18/2b/a07eedccfc678928152e4ef30b0c45640a0ce4cc5c7f0ff926f70a74ab93/django_model_helpers-1.2.1.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "0fa9d4d957a39be6a4c9a8b577822341", "sha256": "b9c230ccecc553a901003a477452eb5bf5f430b267e87dd7be6793dbc7c07474" }, "downloads": -1, "filename": "django_model_helpers-1.2.1-py3-none-any.whl", "has_sig": false, "md5_digest": "0fa9d4d957a39be6a4c9a8b577822341", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 15471, "upload_time": "2016-02-16T10:07:34", "url": "https://files.pythonhosted.org/packages/b8/56/0783ebdfedac321f929ac0196b920cdf23905f491db7ec6e636f9d33ab9a/django_model_helpers-1.2.1-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "03a4c2887e5ebe4501c13b419252b5d0", "sha256": "6b5c58c25b9c7acab2e8fbe91aca3aa28d2e499874b22d78af0f92ccc779e60d" }, "downloads": -1, "filename": "django_model_helpers-1.2.1.tar.gz", "has_sig": false, "md5_digest": "03a4c2887e5ebe4501c13b419252b5d0", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 11479, "upload_time": "2016-02-16T10:07:42", "url": "https://files.pythonhosted.org/packages/18/2b/a07eedccfc678928152e4ef30b0c45640a0ce4cc5c7f0ff926f70a74ab93/django_model_helpers-1.2.1.tar.gz" } ] }