Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Standardize widget render() #1657

Merged
Show file tree
Hide file tree
Changes from 26 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
f613b17
initial check-in
matthewhegarty Oct 13, 2023
7801134
doc updates
matthewhegarty Oct 18, 2023
c7e9d73
updated widgets
matthewhegarty Oct 18, 2023
3700adc
test fixes
matthewhegarty Oct 18, 2023
24ef4f6
fixed test
matthewhegarty Oct 18, 2023
39ea2ab
removed print()
matthewhegarty Oct 18, 2023
a739900
added Field callable test
matthewhegarty Oct 18, 2023
c134f7d
removed coerce_to_string from CharWidget clean()
matthewhegarty Oct 18, 2023
581be3b
corrected docs
matthewhegarty Oct 19, 2023
148b022
added coerce_to_string for BooleanWidget
matthewhegarty Oct 19, 2023
c8f3442
updated
matthewhegarty Oct 19, 2023
97afd3c
added deprecation tests
matthewhegarty Oct 19, 2023
f462198
added deprecation ignore test wrapper
matthewhegarty Oct 19, 2023
28e29ae
added test deprecation decorator
matthewhegarty Oct 19, 2023
a9c5bab
updated changelog
matthewhegarty Oct 19, 2023
9c87447
Merge branch 'release-4' into issue-1649-widget-string-handling
matthewhegarty Oct 20, 2023
7ab54d4
tidied advanced_usage docs
matthewhegarty Oct 20, 2023
67d9229
updated faq
matthewhegarty Oct 20, 2023
31e58c1
test fixes
matthewhegarty Oct 20, 2023
0ec6a43
updated field docs
matthewhegarty Oct 20, 2023
060deaa
updated docs for use of coerce_to_string
matthewhegarty Oct 22, 2023
a4ea2ba
added support for export native ArrayWidget
matthewhegarty Oct 23, 2023
b36702f
Merge branch 'release-4' into issue-1649-widget-string-handling
matthewhegarty Oct 23, 2023
538d465
Merge branch 'release-4' into issue-1649-widget-string-handling
matthewhegarty Oct 23, 2023
0778614
Merge branch 'issue-1649-widget-string-handling' of github.com:matthe…
matthewhegarty Oct 23, 2023
9e1fe29
added ignore_widget_deprecation_warning decorator
matthewhegarty Oct 23, 2023
cdb99cc
clarified test method name
matthewhegarty Oct 24, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
31 changes: 22 additions & 9 deletions docs/advanced_usage.rst
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ There are widgets associated with character data, numeric values, dates, foreign
widget and associate it with the field.

A :class:`~import_export.resources.ModelResource` creates fields with a default widget for a given field type via
instrospection. If the widget should be initialized with different arguments, this can be done via an explicit
introspection. If the widget should be initialized with different arguments, this can be done via an explicit
declaration or via the widgets dict.

For example, the ``published`` field is overridden to use a different date format. This format will be used both for
Expand All @@ -156,7 +156,9 @@ importing and exporting resource::
class Meta:
model = Book

Alternatively, widget parameters can be overridden using the widgets dict declaration::
Declaring fields may affect the export order of the fields. If this is an issue, you can either declare the
:attr:`~import_export.resources.ResourceOptions.export_order` attribute, or declare widget parameters using the widgets
dict declaration::

class BookResource(resources.ModelResource):

Expand All @@ -166,10 +168,26 @@ Alternatively, widget parameters can be overridden using the widgets dict declar
'published': {'format': '%d.%m.%Y'},
}

Modify :meth:`.render` return type
----------------------------------

By default, :meth:`.render` will return a string type for export. There may be use cases where a native type is
required from export. If so, you can use the ``coerce_to_string`` parameter if the widget supports it.

By default, ``coerce_to_string`` is ``True``, but if you set this to ``False``, then the native type will be returned
during export::

class BookResource(resources.ModelResource):
published = Field(attribute='published', column_name='published_date',
widget=DateWidget(format='%Y-%m-%d', coerce_to_string=False))

class Meta:
model = Book

.. seealso::

:doc:`/api_widgets`
available widget types and options.
Available widget types and options.

.. _import_model_relations:

Expand Down Expand Up @@ -899,7 +917,7 @@ return books for the publisher::
Interoperability with 3rd party libraries
-----------------------------------------

import_export extends the Django Admin interface. There is a possibility that clashes may occur with other 3rd party
import-export extends the Django Admin interface. There is a possibility that clashes may occur with other 3rd party
libraries which also use the admin interface.

django-admin-sortable2
Expand Down Expand Up @@ -930,11 +948,6 @@ Refer to `this PR <https://github.com/django-import-export/django-import-export/

.. _admin_security:

.. warning::
If you use django-import-export using with `django-debug-toolbar <https://pypi.org/project/django-debug-toolbar>`_.
then you need to configure debug_toolbar=False or DEBUG=False,
otherwise the import/export time will increase ~10 times.

Security
--------

Expand Down
1 change: 1 addition & 0 deletions docs/changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ Please refer to :doc:`release notes<release_notes>`.
- Enable optional tablib dependencies (#1647)
- Removed unused method ``utils.original()``
- Clarified ``skip_diff`` documentation (#1655)
- Standardised interface of :meth:`~import_export.widgets.Widget.render` (#1657)

4.0.0-alpha.5 (2023-09-22)
--------------------------
Expand Down
2 changes: 2 additions & 0 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
"sphinx.ext.autosectionlabel",
]

autoclass_content = "both"

autosectionlabel_prefix_document = True

# Add any paths that contain templates here, relative to this directory.
Expand Down
16 changes: 16 additions & 0 deletions docs/faq.rst
Original file line number Diff line number Diff line change
Expand Up @@ -180,3 +180,19 @@ with this issue. Refer to `this comment <https://github.com/django-import-expor

This indicates that the change_list_template attribute could not be set, most likely due to a clash with a third party
library. Refer to :ref:`interoperability`.

``FileNotFoundError`` during Admin import 'confirm' step
--------------------------------------------------------

You may receive an error during import such as::

FileNotFoundError [Errno 2] No such file or directory: '/tmp/tmp5abcdef'

This usually happens because you are running the Admin site in a multi server or container environment.
During import, the import file has to be stored temporarily and then retrieved for storage after confirmation.
Therefore ``FileNotFoundError`` error can occur because the temp storage is not available to the server process after
confirmation.

To resolve this, you should avoid using temporary file system storage in multi server environments.

Refer to :ref:`import process<import-process>` for more information.
6 changes: 2 additions & 4 deletions docs/installation.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
Installation and configuration
==============================

import_export is available on the Python Package Index (PyPI), so it
import-export is available on the Python Package Index (PyPI), so it
can be installed with standard Python tools like ``pip`` or ``easy_install``::

pip install django-import-export
Expand Down Expand Up @@ -38,9 +38,7 @@ let Django collect its static files.
$ python manage.py collectstatic

All prerequisites are set up! See :doc:`getting_started` to learn how to use
import_export in your project.


import-export in your project.

Settings
========
Expand Down
36 changes: 29 additions & 7 deletions docs/release_notes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5,27 +5,51 @@ Release Notes
v4
==

v4 introduces breaking changes in order to address some long-standing issues.
In all cases, please test thoroughly before deploying v4 to production.
v4 introduces breaking changes in order to fix some long-standing issues.
Refer to the :doc:`changelog<changelog>` for more information. Please ensure you test
thoroughly before deploying v4 to production.

This guide describes the major changes and how to upgrade.

Installation
============

We have modified installation methods to allow for optional dependencies.
This means that you have to explicitly declare dependencies when installing import_export.
This means that you have to explicitly declare dependencies when installing import-export.

If you are not sure, or want to preserve the pre-v4 behaviour, then ensure that
import_export is installed as follows (either in your requirements file or during
import-export is installed as follows (either in your requirements file or during
installation)::

django-import-export[all]


CharWidget
==========

:meth:`~import_export.widgets.CharWidget.clean` will now return a string type as the default.
The ``coerce_to_string`` option introduced in v3 is no longer used in this method.

Export format
=============

We have standardized the export output which is returned from
:meth:`~import_export.widgets.Widget.render`.

Prior to v4, the export format returned from ``render()`` varied between Widget implementations.
In v4, return values are rendered as strings by default (where applicable), with
``None`` values returned as empty strings. Widget params can modify this behavior.

Refer to the :doc:`documentation<api_widgets>` for more information.

The ``obj`` param passed to :meth:`~import_export.widgets.Widget.render` is deprecated.
The :meth:`~import_export.widgets.Widget.render` method should not need to have a reference to
model instance.

API changes
===========

v4 of import_export (released Q4 2023) contains a number of minor changes to the API.
v4 of import-export contains a number of minor changes to the API.

If you have customized import-export by overriding methods, then you will have to
modify your installation before working with v4. If you have not overridden any
Expand All @@ -35,8 +59,6 @@ should be necessary.
The API changes include changes to method arguments, although some method names have
changed.

Test thoroughly before deploying v4 to production.

Refer to
`this PR <https://github.com/django-import-export/django-import-export/pull/1641/>`_
for more information.
Expand Down
26 changes: 14 additions & 12 deletions import_export/fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,13 @@

class Field:
"""
Field represent mapping between `object` field and representation of
this field.
``Field`` represents a mapping between an ``instance`` field and a representation of
the field's data.

:param attribute: A string of either an instance attribute or callable off
the object.
:param attribute: A string of either an instance attribute or callable of
the instance.

:param column_name: Lets you provide a name for the column that represents
:param column_name: An optional column name for the column that represents
this field in the export.

:param widget: Defines a widget that will be used to represent this
Expand All @@ -24,12 +24,16 @@ class Field:
during import.

:param default: This value will be returned by
:meth:`~import_export.fields.Field.clean` if this field's widget did
not return an adequate value.
:meth:`~import_export.fields.Field.clean` if this field's widget returned
a value defined in :attr:`~import_export.fields.empty_values`.

:param saves_null_values: Controls whether null values are saved on the instance.
This can be used if the widget returns null, but there is a default instance
value which should not be overwritten.

:param saves_null_values: Controls whether null values are saved on the object
:param dehydrate_method: Lets you choose your own method for dehydration rather
than using `dehydrate_{field_name}` syntax.

:param m2m_add: changes save of this field to add the values, if they do not exist,
to a ManyToMany field instead of setting all values. Only useful if field is
a ManyToMany field.
Expand Down Expand Up @@ -93,7 +97,7 @@ def clean(self, row, **kwargs):

def get_value(self, instance):
"""
Returns the value of the object's attribute.
Returns the value of the instance's attribute.
"""
if self.attribute is None:
return None
Expand All @@ -119,7 +123,7 @@ def get_value(self, instance):

def save(self, instance, row, is_m2m=False, **kwargs):
"""
If this field is not declared readonly, the object's attribute will
If this field is not declared readonly, the instance's attribute will
be set to the value returned by :meth:`~import_export.fields.Field.clean`.
"""
if not self.readonly:
Expand All @@ -142,8 +146,6 @@ def export(self, instance):
representation.
"""
value = self.get_value(instance)
if value is None:
return ""
return self.widget.render(value, instance)

def get_dehydrate_method(self, field_name=None):
Expand Down