{"id":15486120,"url":"https://github.com/escaped/django-exiffield","last_synced_at":"2025-04-22T15:45:34.917Z","repository":{"id":47228776,"uuid":"126648721","full_name":"escaped/django-exiffield","owner":"escaped","description":"django-exiffield extracts exif data by utilizing the exiftool","archived":false,"fork":false,"pushed_at":"2021-09-07T23:26:07.000Z","size":4971,"stargazers_count":13,"open_issues_count":8,"forks_count":6,"subscribers_count":2,"default_branch":"master","last_synced_at":"2024-10-19T07:05:19.682Z","etag":null,"topics":["django","django-field","exif","exiftool","hacktoberfest","python","python36"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/escaped.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null},"funding":{"github":["escaped"]}},"created_at":"2018-03-24T23:30:41.000Z","updated_at":"2024-03-22T09:39:10.000Z","dependencies_parsed_at":"2022-09-02T12:43:42.209Z","dependency_job_id":null,"html_url":"https://github.com/escaped/django-exiffield","commit_stats":null,"previous_names":[],"tags_count":6,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/escaped%2Fdjango-exiffield","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/escaped%2Fdjango-exiffield/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/escaped%2Fdjango-exiffield/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/escaped%2Fdjango-exiffield/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/escaped","download_url":"https://codeload.github.com/escaped/django-exiffield/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":249273980,"owners_count":21242005,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["django","django-field","exif","exiftool","hacktoberfest","python","python36"],"created_at":"2024-10-02T06:06:38.679Z","updated_at":"2025-04-16T20:32:15.706Z","avatar_url":"https://github.com/escaped.png","language":"Python","funding_links":["https://github.com/sponsors/escaped"],"categories":[],"sub_categories":[],"readme":"# django-exiffield\n\n![PyPI](https://img.shields.io/pypi/v/django-exiffield?style=flat-square)\n![GitHub Workflow Status (master)](https://img.shields.io/github/workflow/status/escaped/django-exiffield/Test%20\u0026%20Lint/master?style=flat-square)\n![Coveralls github branch](https://img.shields.io/coveralls/github/escaped/django-exiffield/master?style=flat-square)\n![PyPI - Python Version](https://img.shields.io/pypi/pyversions/django-exiffield?style=flat-square)\n![PyPI - License](https://img.shields.io/pypi/l/django-exiffield?style=flat-square)\n\ndjango-exiffield extracts exif information by utilizing the exiftool.\n\n## Requirements\n\n* Python 3.6.1 or newer\n* [exiftool](https://www.sno.phy.queensu.ca/~phil/exiftool/)\n* Django \u003e= 2.2\n\n## Installation\n\n1. Install django-exiffield\n\n   ```sh\n   pip install django-exiffield\n   ```\n\n2. Make sure `exiftool` is executable from you environment.\n\n## Integration\n\nLet's assume we have an image Model with a single `ImageField`.\nTo extract exif information for an attached image, add an `ExifField`,\nspecify the name of the `ImageField` in the `source` argument\n\n```python\nfrom django.db import models\n\nfrom exiffield.fields import ExifField\n\n\nclass Image(models.Model):\n    image = models.ImageField()\n    exif = ExifField(\n        source='image',\n    )\n```\n\nand create a migration for the new field.\nThat's it.\n\nAfter attaching an image to your `ImageField`, the exif information is stored\nas a `dict` on the `ExifField`.\nEach exif information of the dictionary consists of two keys:\n\n* `desc`: A human readable description\n* `val`: The value for the entry.\n\nIn the following example we access the camera model\n\n```python\nimage = Image.objects.get(...)\nprint(image.exif['Model'])\n# {\n#     'desc': 'Camera Model Name',\n#     'val': 'DMC-GX7',\n# }\n```\n\nAs the exif information is encoded in a simple `dict` you can iterate and access\nthe values with all familiar dictionary methods.\n\n## Denormalizing Fields\n\nSince the `ExifField` stores its data simply as text, it is not possible to filter\nor access indiviual values efficiently.\nThe `ExifField` provides a convinient way to denormalize certain values using\nthe `denormalized_fields` argument.\nIt takes a dictionary with the target field as key and a simple getter function of\ntype `Callable[[Dict[Dict[str, str]]], Any]`.\nTo denormalize a simple value you can use the provided `exiffield.getters.exifgetter`\n\n```python\nfrom django.db import models\n\nfrom exiffield.fields import ExifField\nfrom exiffield.getters import exifgetter\n\n\nclass Image(models.Model):\n    image = models.ImageField()\n    camera = models.CharField(\n        editable=False,\n        max_length=100,\n    )\n    exif = ExifField(\n        source='image',\n        denormalized_fields={\n            'camera': exifgetter('Model'),\n        },\n    )\n```\n\nThere are more predefined getters in `exiffield.getters`:\n\n`exifgetter(exif_key: str) -\u003e str`  \nGet an unmodified exif value.\n\n`get_type() -\u003e str`  \nGet file type, e.g. video or image\n\n`get_datetaken -\u003e Optional[datetime]`  \nGet when the file was created as `datetime`\n\n`get_orientation  -\u003e exiffield.getters.Orientation`  \nGet orientation of media file.\nPossible values are `LANDSCAPE` and `PORTRAIT`.\n\n`get_sequenctype -\u003e exiffield.getters.Mode`  \nGuess if the image was taken in a sequence.\nPossible values are `BURST`, `BRACKETING`, `TIMELAPSE` and `SINGLE`.\n\n`get_sequencenumber -\u003e int`  \nGet image position in a sequence.\n\n## Development\n\nThis project uses [poetry](https://poetry.eustace.io/) for packaging and\nmanaging all dependencies and [pre-commit](https://pre-commit.com/) to run\n[flake8](http://flake8.pycqa.org/), [isort](https://pycqa.github.io/isort/),\n[mypy](http://mypy-lang.org/) and [black](https://github.com/python/black).\n\nClone this repository and run\n\n```bash\npoetry install\npoetry run pre-commit install\n```\n\nto create a virtual enviroment containing all dependencies.\nAfterwards, You can run the test suite using\n\n```bash\npoetry run pytest\n```\n\nThis repository follows the [Conventional Commits](https://www.conventionalcommits.org/)\nstyle.\n\n### Cookiecutter template\n\nThis project was created using [cruft](https://github.com/cruft/cruft) and the\n[cookiecutter-pyproject](https://github.com/escaped/cookiecutter-pypackage) template.\nIn order to update this repository to the latest template version run\n\n```sh\ncruft update\n```\n\nin the root of this repository.\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fescaped%2Fdjango-exiffield","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fescaped%2Fdjango-exiffield","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fescaped%2Fdjango-exiffield/lists"}