diff --git a/CHANGELOG.md b/CHANGELOG.md index 2c87ff08..2c5dd99f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,8 @@ We follow [Semantic Versions](https://semver.org/) starting at the `0.14.0` rele ### Bug Fixes +- Fixes AttributeError when using CSVFormField [[#187](https://github.com/jazzband/django-eav2/issues/187)] + ## 1.2.1 (2021-02-08) ### Bug Fixes diff --git a/eav/forms.py b/eav/forms.py index 0e3e00df..b6117d71 100644 --- a/eav/forms.py +++ b/eav/forms.py @@ -32,6 +32,7 @@ class CSVFormField(forms.Field): def __init__(self, *args, **kwargs): kwargs.pop('max_length', None) + self.separator = kwargs.pop('separator', self.default_separator) super().__init__(*args, **kwargs) def to_python(self, value): @@ -39,10 +40,10 @@ def to_python(self, value): return [] return [v.strip() for v in value.split(self.separator) if v] - def validate(self, value): - super().validate(value) + def validate(self, field_value): + super().validate(field_value) try: - isinstance(value.split(self.separator), list) + isinstance(field_value, list) except ValidationError: raise ValidationError(self.message, code=self.code) diff --git a/eav/widgets.py b/eav/widgets.py index e68887e5..30d862e2 100644 --- a/eav/widgets.py +++ b/eav/widgets.py @@ -21,3 +21,21 @@ def prep_value(self, value): def render(self, name, value, **kwargs): value = self.prep_value(value) return super().render(name, value, **kwargs) + + def value_from_datadict(self, data, files, name): + """ + Return the value of this widget or None. + + Since we're only given the value of the entity name and the data dict + contains the '_eav_config_cls' (which we don't have access to) as the + key, we need to loop through each field checking if the eav attribute + exists with the given 'name'. + """ + widget_value = None + for data_value in data: + try: + widget_value = getattr(data.get(data_value), name) + except AttributeError: + pass # noqa: WPS420 + + return widget_value diff --git a/tests/test_forms.py b/tests/test_forms.py index 291663c8..7ab61a85 100644 --- a/tests/test_forms.py +++ b/tests/test_forms.py @@ -1,5 +1,5 @@ import sys - +import pytest from django.contrib.admin.sites import AdminSite from django.core.handlers.base import BaseHandler from django.forms import ModelForm @@ -50,6 +50,12 @@ class Meta: fields = '__all__' +class PatientDynamicForm(BaseDynamicEntityForm): + class Meta: + model = Patient + fields = '__all__' + + class M2MModelForm(ModelForm): class Meta: model = M2MModel @@ -111,3 +117,51 @@ def test_m2m(self): form = M2MModelForm(dict(name='Lorem', models=[model.pk]), instance=m2mmodel) form.save() self.assertEqual(len(m2mmodel.models.all()), 1) + + +@pytest.fixture() +def patient() -> Patient: + """Return an eav enabled Patient instance.""" + eav.register(Patient) + return Patient.objects.create(name='Jim Morrison') + + +@pytest.mark.django_db() +@pytest.mark.parametrize( + 'csv_data, separator', + [ + ('', ';'), + ('justone', ','), + ('one;two;three', ';'), + ('alpha,beta,gamma', ','), + (None, ','), + ], +) +def test_csvdynamicform(patient, csv_data, separator) -> None: + """Ensure that a TYPE_CSV field works correctly with forms.""" + Attribute.objects.create(name='csv', datatype=Attribute.TYPE_CSV) + patient.eav.csv = csv_data + patient.save() + patient.refresh_from_db() + + form = PatientDynamicForm( + patient.__dict__, + instance=patient, + ) + form.fields['csv'].separator = separator + assert form.is_valid() + jim = form.save() + + expected_result = str(csv_data).split(separator) if csv_data else [] + assert jim.eav.csv == expected_result + + +@pytest.mark.django_db() +def test_csvdynamicform_empty(patient) -> None: + """Test to ensure an instance with no eav values is correct.""" + form = PatientDynamicForm( + patient.__dict__, + instance=patient, + ) + assert form.is_valid() + assert form.save()