Skip to content

Commit

Permalink
add model mixin from edc-base
Browse files Browse the repository at this point in the history
  • Loading branch information
erikvw committed Dec 7, 2018
1 parent 8c318cd commit 46c04dc
Show file tree
Hide file tree
Showing 3 changed files with 131 additions and 11 deletions.
45 changes: 44 additions & 1 deletion README.rst
Expand Up @@ -3,7 +3,50 @@
edc-list-data
-------------

Populate list data and other static model data on startup.
Populate list data and other static model data on ``Django`` startup.

To install add ``edc_list_data.apps.AppConfig`` to your `INSTALLED_APPS`, then create a ``list_data.py`` in the root of your app.

Most commonly used to populate M2M data known here as ``list_data``. M2M field models should use the ``ListModelMixin``.

For example:

.. code-block:: python
class Antibiotic(ListModelMixin, BaseUuidModel):
class Meta(ListModelMixin.Meta):
pass
An example ``list_data.py``:


.. code-block:: python
from edc_constants.constants import OTHER
from edc_list_data import PreloadData
list_data = {
'my_lists_app.antibiotic': [
('flucloxacillin', 'Flucloxacillin'),
('gentamicin', 'Gentamicin'),
('ceftriaxone', 'Ceftriaxone'),
('amoxicillin_ampicillin', 'Amoxicillin/Ampicillin'),
('doxycycline', 'Doxycycline'),
('erythromycin', 'Erythromycin'),
('ciprofloxacin', 'Ciprofloxacin'),
(OTHER, 'Other, specify')
],
}
preload_data = PreloadData(list_data=list_data)
``PreloadData`` will persist the list data in model ``Antibiotic`` and maintain the order in which the list items are declared.

See also call to ``site_list_data.autodiscover`` called in ``edc_list_data.apps.AppConfig``.



.. |pypi| image:: https://img.shields.io/pypi/v/edc-list-data.svg
Expand Down
69 changes: 69 additions & 0 deletions edc_list_data/model_mixins.py
@@ -0,0 +1,69 @@
from django.db import models


class ListModelManager(models.Manager):

def get_by_natural_key(self, short_name):
return self.get(short_name=short_name)


class ListModelMixin(models.Model):

"""Mixin for list data used in dropdown and radio widgets having
display value and store value pairs.
"""

name = models.CharField(
verbose_name='Name',
max_length=250,
unique=True,
db_index=True,
help_text='(suggest 40 characters max.)',
)

# FIXME: this should be a short string, e.g. 15-25 chars!
short_name = models.CharField(
verbose_name="Stored value",
max_length=250,
unique=True,
db_index=True,
help_text='This is the stored value, required',
)

display_index = models.IntegerField(
verbose_name="display index",
default=0,
db_index=True,
help_text=(
'Index to control display order if not alphabetical, not required'),
)

field_name = models.CharField(
max_length=25,
editable=False,
null=True,
blank=True,
help_text='Not required',
)

version = models.CharField(
max_length=35,
editable=False,
default='1.0',
)
objects = ListModelManager()

def __str__(self):
return self.name

def save(self, *args, **kwargs):
if not self.short_name:
self.short_name = self.name
super().save(*args, **kwargs)

def natural_key(self):
return (self.short_name, )

class Meta:
abstract = True
ordering = ['display_index', 'name']
28 changes: 18 additions & 10 deletions edc_list_data/preload_data.py
Expand Up @@ -19,15 +19,19 @@ def __init__(self, list_data=None, model_data=None, unique_field_data=None):
self.list_data = list_data or {}
self.model_data = model_data or {}
self.unique_field_data = unique_field_data or {}

self.load_list_data()
self.load_model_data()
self.update_unique_field_data()

if self.model_data:
self.load_model_data()
if self.unique_field_data:
self.update_unique_field_data()

def load_list_data(self):
"""Loads data into a list model.
List models have short_name, name where short_name
is the unique field.
is the unique field / stored field.
Format:
{model_name1: [(short_name1, name),
Expand All @@ -39,19 +43,23 @@ def load_list_data(self):
for model_name in self.list_data.keys():
try:
model = django_apps.get_model(model_name)
for data in self.list_data.get(model_name):
short_name, display_value = data
display_index = 0
for display_index, value in enumerate(self.list_data.get(model_name)):
store_value, display_value = value
try:
obj = model.objects.get(short_name=short_name)
obj = model.objects.get(short_name=store_value)
except ObjectDoesNotExist:
model.objects.create(
short_name=short_name, name=display_value)
short_name=store_value,
name=display_value,
display_index=display_index)
else:
obj.name = display_value
obj.display_index = display_index
obj.save()
except Exception as e:
raise PreloadDataError(e)
# sys.stdout.write(style.ERROR(str(e) + '\n'))
except ValueError as e:
raise PreloadDataError(
f'{e} See {self.list_data.get(model_name)}.')

def load_model_data(self):
"""Loads data into a model, creates or updates existing.
Expand Down

0 comments on commit 46c04dc

Please sign in to comment.