django-model-import


Namedjango-model-import JSON
Version 0.7.3 PyPI version JSON
download
home_pagehttps://github.com/uptick/django-model-import
SummaryA Django library for importing CSVs and other structured data quickly using Django's ModelForm for validation and deserialisation into an instance.
upload_time2024-03-06 00:49:34
maintainer
docs_urlNone
authorAidan Lister
requires_python>=3.10,<4.0
licenseMIT
keywords
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI
coveralls test coverage No coveralls.
            # django-model-import

[![PyPI version](https://badge.fury.io/py/django-model-import.svg)](https://badge.fury.io/py/django-model-import)

Django Model Import is a light weight CSV importer built for speed.

It uses a standard Django `ModelForm` to parse each row, giving you a familiar API to work with
for data validation and model instantiation. In most cases, if you already have a `ModelForm`
for the `ContentType` you are importing you do not need to create an import specific form.

To present feedback to the end-user running the import you can easily generate a preview
of the imported data by toggling the `commit` parameter.

It also provides some import optimized fields for ForeignKey's, allowing preloading all
possible values, or caching each lookup as it occurs, or looking up a model where multiple
fields are needed to uniquely identify a resource.


## Installation

```bash
poetry add django-model-import
```


## Quickstart

```python
import djangomodelimport

class BookImporter(djangomodelimport.ImporterModelForm):
    name = forms.CharField()
    author = CachedChoiceField(queryset=Author.objects.all(), to_field='name')

    class Meta:
        model = Book
        fields = (
            'name',
            'author',
        )

with default_storage.open('books.csv', 'rb') as fh:
    data = fh.read().decode("utf-8")

# Use tablib
parser = djangomodelimport.TablibCSVImportParser(BookImporter)
headers, rows = parser.parse(data)

# Process
importer = djangomodelimport.ModelImporter(BookImporter)
preview = importer.process(headers, rows, commit=False)
errors = preview.get_errors()

if errors:
    print(errors)

importresult = importer.process(headers, rows, commit=True)
for result in importresult.get_results():
    print(result.instance)
```


## Composite key lookups

Often a relationship cannot be referenced via a single unique string. For this we can use
a `CachedChoiceField` with a `CompositeLookupWidget`. The widget looks for the values
under the `type` and `variant` columns in the source CSV, and does a unique lookup
with the field names specified in `to_field`, e.g. `queryset.get(type__name=type, name=variant)`.

The results of each `get` are cached internally for the remainder of the import minimising
any database access.

```python
class AssetImporter(ImporterModelForm):
    site = djangomodelimport.CachedChoiceField(queryset=Site.objects.active(), to_field='ref')
    type = djangomodelimport.CachedChoiceField(queryset=AssetType.objects.filter(is_active=True), to_field='name')
    type_variant = djangomodelimport.CachedChoiceField(
        queryset=InspectionItemTypeVariant.objects.filter(is_active=True),
        required=False,
        widget=djangomodelimport.CompositeLookupWidget(source=('type', 'variant')),
        to_field=('type__name', 'name'),
    )
    contractor = djangomodelimport.CachedChoiceField(queryset=Contractor.objects.active(), to_field='name')
```


## Flat related fields

Often you'll have a OneToOneField or just a ForeignKey to another model, but you want to be able to
create/update that other model via this one. You can flatten all of the related model's fields onto
this importer using `FlatRelatedField`.

```python
class ClientImporter(ImporterModelForm):
    primary_contact = FlatRelatedField(
        queryset=ContactDetails.objects.all(),
        fields={
            'contact_name': {'to_field': 'name', 'required': True},
            'email': {'to_field': 'email'},
            'email_cc': {'to_field': 'email_cc'},
            'mobile': {'to_field': 'mobile'},
            'phone_bh': {'to_field': 'phone_bh'},
            'phone_ah': {'to_field': 'phone_ah'},
            'fax': {'to_field': 'fax'},
        },
    )

    class Meta:
        model = Client
        fields = (
            'name',
            'ref',
            'is_active',
            'account',

            'primary_contact',
        )
```

## Tests
Run tests with `python example/manage.py test testapp`

            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/uptick/django-model-import",
    "name": "django-model-import",
    "maintainer": "",
    "docs_url": null,
    "requires_python": ">=3.10,<4.0",
    "maintainer_email": "",
    "keywords": "",
    "author": "Aidan Lister",
    "author_email": "aidan@uptickhq.com",
    "download_url": "https://files.pythonhosted.org/packages/2e/a4/80e22160f866a1ad793159b6676ed97f653f5c558cd6b317217c8624034e/django_model_import-0.7.3.tar.gz",
    "platform": null,
    "description": "# django-model-import\n\n[![PyPI version](https://badge.fury.io/py/django-model-import.svg)](https://badge.fury.io/py/django-model-import)\n\nDjango Model Import is a light weight CSV importer built for speed.\n\nIt uses a standard Django `ModelForm` to parse each row, giving you a familiar API to work with\nfor data validation and model instantiation. In most cases, if you already have a `ModelForm`\nfor the `ContentType` you are importing you do not need to create an import specific form.\n\nTo present feedback to the end-user running the import you can easily generate a preview\nof the imported data by toggling the `commit` parameter.\n\nIt also provides some import optimized fields for ForeignKey's, allowing preloading all\npossible values, or caching each lookup as it occurs, or looking up a model where multiple\nfields are needed to uniquely identify a resource.\n\n\n## Installation\n\n```bash\npoetry add django-model-import\n```\n\n\n## Quickstart\n\n```python\nimport djangomodelimport\n\nclass BookImporter(djangomodelimport.ImporterModelForm):\n    name = forms.CharField()\n    author = CachedChoiceField(queryset=Author.objects.all(), to_field='name')\n\n    class Meta:\n        model = Book\n        fields = (\n            'name',\n            'author',\n        )\n\nwith default_storage.open('books.csv', 'rb') as fh:\n    data = fh.read().decode(\"utf-8\")\n\n# Use tablib\nparser = djangomodelimport.TablibCSVImportParser(BookImporter)\nheaders, rows = parser.parse(data)\n\n# Process\nimporter = djangomodelimport.ModelImporter(BookImporter)\npreview = importer.process(headers, rows, commit=False)\nerrors = preview.get_errors()\n\nif errors:\n    print(errors)\n\nimportresult = importer.process(headers, rows, commit=True)\nfor result in importresult.get_results():\n    print(result.instance)\n```\n\n\n## Composite key lookups\n\nOften a relationship cannot be referenced via a single unique string. For this we can use\na `CachedChoiceField` with a `CompositeLookupWidget`. The widget looks for the values\nunder the `type` and `variant` columns in the source CSV, and does a unique lookup\nwith the field names specified in `to_field`, e.g. `queryset.get(type__name=type, name=variant)`.\n\nThe results of each `get` are cached internally for the remainder of the import minimising\nany database access.\n\n```python\nclass AssetImporter(ImporterModelForm):\n    site = djangomodelimport.CachedChoiceField(queryset=Site.objects.active(), to_field='ref')\n    type = djangomodelimport.CachedChoiceField(queryset=AssetType.objects.filter(is_active=True), to_field='name')\n    type_variant = djangomodelimport.CachedChoiceField(\n        queryset=InspectionItemTypeVariant.objects.filter(is_active=True),\n        required=False,\n        widget=djangomodelimport.CompositeLookupWidget(source=('type', 'variant')),\n        to_field=('type__name', 'name'),\n    )\n    contractor = djangomodelimport.CachedChoiceField(queryset=Contractor.objects.active(), to_field='name')\n```\n\n\n## Flat related fields\n\nOften you'll have a OneToOneField or just a ForeignKey to another model, but you want to be able to\ncreate/update that other model via this one. You can flatten all of the related model's fields onto\nthis importer using `FlatRelatedField`.\n\n```python\nclass ClientImporter(ImporterModelForm):\n    primary_contact = FlatRelatedField(\n        queryset=ContactDetails.objects.all(),\n        fields={\n            'contact_name': {'to_field': 'name', 'required': True},\n            'email': {'to_field': 'email'},\n            'email_cc': {'to_field': 'email_cc'},\n            'mobile': {'to_field': 'mobile'},\n            'phone_bh': {'to_field': 'phone_bh'},\n            'phone_ah': {'to_field': 'phone_ah'},\n            'fax': {'to_field': 'fax'},\n        },\n    )\n\n    class Meta:\n        model = Client\n        fields = (\n            'name',\n            'ref',\n            'is_active',\n            'account',\n\n            'primary_contact',\n        )\n```\n\n## Tests\nRun tests with `python example/manage.py test testapp`\n",
    "bugtrack_url": null,
    "license": "MIT",
    "summary": "A Django library for importing CSVs and other structured data quickly using Django's ModelForm for validation and deserialisation into an instance.",
    "version": "0.7.3",
    "project_urls": {
        "Documentation": "https://github.com/uptick/django-model-import/tree/master/tests/djangoexample",
        "Homepage": "https://github.com/uptick/django-model-import",
        "Repository": "https://github.com/uptick/django-model-import"
    },
    "split_keywords": [],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "1312e24f2a7e89add621dcf27fda209ca96374b481e04fc048bfb4f348418402",
                "md5": "e102ac0764022389579d0d083b8ecd43",
                "sha256": "d6f577a262af777009d38d3046f6d30e58f5316d8b7f62aea1b0d345008f5422"
            },
            "downloads": -1,
            "filename": "django_model_import-0.7.3-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "e102ac0764022389579d0d083b8ecd43",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.10,<4.0",
            "size": 18336,
            "upload_time": "2024-03-06T00:49:33",
            "upload_time_iso_8601": "2024-03-06T00:49:33.229569Z",
            "url": "https://files.pythonhosted.org/packages/13/12/e24f2a7e89add621dcf27fda209ca96374b481e04fc048bfb4f348418402/django_model_import-0.7.3-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "2ea480e22160f866a1ad793159b6676ed97f653f5c558cd6b317217c8624034e",
                "md5": "61743e3ab93b5d55a8cbcf456563368a",
                "sha256": "8ca42daad8153bed4f7eb935e9b89df879d82540a5f43f596bdf1fcda9460894"
            },
            "downloads": -1,
            "filename": "django_model_import-0.7.3.tar.gz",
            "has_sig": false,
            "md5_digest": "61743e3ab93b5d55a8cbcf456563368a",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.10,<4.0",
            "size": 15630,
            "upload_time": "2024-03-06T00:49:34",
            "upload_time_iso_8601": "2024-03-06T00:49:34.647666Z",
            "url": "https://files.pythonhosted.org/packages/2e/a4/80e22160f866a1ad793159b6676ed97f653f5c558cd6b317217c8624034e/django_model_import-0.7.3.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2024-03-06 00:49:34",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "uptick",
    "github_project": "django-model-import",
    "travis_ci": true,
    "coveralls": false,
    "github_actions": false,
    "lcname": "django-model-import"
}
        
Elapsed time: 0.27192s