Fields of fields

I'm sure you will all be pleased to hear that some progress is being made with the project! The bulk of the work will be done over the summer months, but I am hoping to have a couple of the more interesting new field types done before DjangoConEU in May. (Speaking of DjangoConEU - I will be speaking in more detail there about this project, if you haven't booked your tickets yet you should totally do so - it'll be a great event!)

There is now a "work in progress" pull request available on github for array fields. Comment is very welcome! An array field allows you to store lists of data in a single field. It's like the big brother of Django's CommaSeparatedIntegerField, but it supports most other field types underneath.

The only restriction on the field type is that we do not support any related field type - ForeignKey or ManyToMany. I should not need to explain why the latter is illogical, but in the case of the former it's worth pointing out the reasoning why. In short, Postgres does not allow the use of REFERENCES in array field declarations, so you could build an array of foreign key data, but it would not have referential integrity. As this is a promise of the ForeignKey, we cannot support ArrayField(ForeignKey()). This is an unfortunate restriction as many of the "natural" use cases for arrays would reference other objects, and one which I hope to lift in the future if Postgres support improves. You can of course emulate this with ArrayField(IntegerField()) but this is at your own risk!

Aside from their utility for storing list-like data without the requirement for another table, Postgres array fields can also be queried in a number of ways. Taking as an example a dice-based guessing game where we have an Attempt model which stores the attempts to guess the rolled number, the following queries are all valid:

Attempt.objects.filter(guesses=[1])  # only one guess, value 1
Attempt.objects.filter(guesses__0=1)  # first guess is 1
Attempt.objects.filter(guesses__0_1=[1, 2])  # first guess 1, second guess 2
Attempt.objects.filter(guesses__len__lt=3)  # less than 3 guesses
Attempt.objects.filter(guesses__contains=[1])  # at least one guess is 1
Attempt.objects.filter(guesses__overlap=[1, 2])  # at least one guess is either 1 or 2
Attempt.objects.filter(guesses__contained_by=[1, 2])  # guesses include only 1 and 2

As with other non-text based fields in Django, at the moment array fields still support a number of other lookups which cast the value to text. Personally I consider this to be somewhat misleading at the moment and am considering removing support for them. This is perhaps part of a wider question though - is it logical that a DateField supports __istartswith (probably not) but is it logical that it supports __startswith=200 as an alternative to the upcoming (postgres specific) __decade=2000? My instinct is that we should introduce a __text transform which is available on all data types and casts to text, allowing these filters. This could be done with a deprecation path. I'm interested to hear your views!

The next step is to build a couple of form fields for arrays, one being a simple CharField taking a delimiter with a delimiter to split on, and the other being a more complex Javascript enabled field for the admin which allows a nicer interface. Perhaps we could also include a version of this without the javascript that has a similar API to formsets. After that I just need to write complete documentation and we can merge it in!

A note on JSON support

The Postgres team have recently merged support for a jsonb datatype - binary stored JSON. It is quite likely that I will delay JSON support until Postgres 9.4 is out and only support the jsonb data type. There are several reasons for this, the most significant being that the current json data type is severly limited in its implementation, lacking even an equality operator. This means that some parts of Django annotation code generate invalid queries (see this report) and also means that a __exact lookup has to be forbidden. To handle all these edge cases properly in Django would result in a huge amount of complexity, and the benefits you gain over just storing json in a text field are actually quite limited. 9.4 is due out towards the end of this year, so as a result JSON fields are likely to only feature in the 1.8 release.

Sponsors page updated

The sponsors page has been updated with images and links for all the major sponsors. Go and check out all the great companies and individuals who have supported this project.

blogroll

social