A reusable Django model field to store collections.
- This is a fork of a fork. The original repository does not appear to be active. I needed to use the library for Django 2.
- Original: https://github.com/escer/django-collectionfield
- Fork: https://github.com/russoz/django-collectionfield
- highly configurable model field (changing collection and item types, sorting, choices, item uniqueness and more)
- custom lookups to simplify queries over collection items
- form fields for working with collections
- collection item validators
- extended
get_FIELD_display
method for model fields with choices - works with database backends without native support for multi-value columns (like ArrayField for PostgreSQL)
pip install django-collectionfield
Define model with field that stores lists of strings:
# models.py
from django.db import models
from collectionfield.models import CollectionField
class MyModel(models.Model):
tags = CollectionField()
Pass values to model field:
my_model = MyModel.objects.create(tags=['test', 'values'])
my_model.values
['test', 'values']
Retrieve model instances with particular value present in the collection:
MyModel.objects.filter(tags__has='test')
Retrieve model instances with ALL values present in the collection (ignoring items' order):
MyModel.objects.filter(tags__hasall=['test', 'values'])
Retrieve model instances with ANY of values present in the collection:
MyModel.objects.filter(tags__hasany=['test', 'values'])
Custom collection and item type:
class IntegerSet(models.Model):
# This field will provide sets of integers
# instead of default lists of strings:
values = CollectionField(collection_type=set, item_type=int)
Sorting and uniqueness:
class SortedUniqueTextList(models.Model):
# Before saving, items will be sorted and duplicates dropped:
texts = CollectionField(sort=True, unique_items=True)
Choices and collection size limit:
class TaggedModel(models.Model):
tags = CollectionField(
# Both choices and max_items limit are checked during model validation.
choices=(
('action', "Action"),
('comedy', "Comedy"),
('horror', "Horror"),
# ...
),
max_items=2
)
get_FIELD_display
method can handle multiple choices and provide options to customize the display:
tagged_model = TaggedModel.objects.create(tags=['action', 'horror'])
tagged_model.get_tags_display()
"Action, Horror"
def li_mapper(value, label):
return "<li>{0}</li>".format(label)
def ul_wrapper(field_display):
return "<ul>{0}</ul>".format(field_display)
tagged_model.get_tags_display(delimiter='', mapper=li_mapper, wrapper=ul_wrapper)
'<ul><li>Action</li><li>Horror</li></ul>'
Django built-in validators work with entire field values. django-collectionfield
provide validation of single collection items:
from collectionfield.validators import (
ItemMinValueValidator, ItemMaxValueValidator
)
class IntegerList(models.Model):
values = CollectionField(
item_type=int,
# item validators check each item separately:
validators=[ItemMinValueValidator(1), ItemMaxValueValidator(5)]
)
django-collectionfield
comes with 2 form fields:
from collectionfield.forms import CollectionField, CollectionChoiceField
# ``collectionfield.forms.CollectionField`` converts comma-separated text
# into collection of values:
class MyForm(forms.Form):
values = CollectionField()
my_form = MyForm({'values': "A, B, C"})
my_form.is_valid()
True
my_form.cleaned_data['values']
['A', 'B', 'C']
# ``collectionfield.forms.CollectionChoiceField`` behaves more like
# regular MultipleChoiceField:
class MyChoiceForm(forms.Form):
values = CollectionChoiceField(
choices=(
('action', "Action"),
('comedy', "Comedy"),
('horror', "Horror"),
# ...
)
)
my_choice_form = MyChoiceForm({'values': ['action', 'comedy']})
my_choice_form.is_valid()
True
my_choice_form.cleaned_data['values']
['action', 'comedy']
Both form fields support the same set of parameters as the model field:
from collectionfield.forms import CollectionField
class MyForm(forms.Form):
values = CollectionField(collection_type=set, item_type=int)
my_form = MyForm({'values': "1, 2, 1, 3"})
my_form.is_valid()
True
my_form.cleaned_data['values']
{1, 2, 3}
CollectionField converts its values into string of up to 1024 characters using the following format:
"|item1|item2|item3|"
Default delimiter ('|') and maximum length can be configured:
class MyModel(models.Model):
values = CollectionField(delimiter="$", max_length=2000)
Python: 2.7, 3.4, 3.5
Django: 1.8, 1.9, 1.10