django-pgfields exposes several new fields corresponding to data types available in PostgreSQL that are not available in other databases supported by Django.
These fields are available on the django_pg.models module (see Using django-pgfields for more on this).
PostgreSQL supports an array datatype. This is most similar to arrays in many statically-typed languages such as C or Java, in that you explicitly declare that you want an array of a specific type (for instance, an array of integers or an array of strings).
django-pgfields exposes this by having the array field accept another field as its initial argument (or, alternatively, by using the of keyword argument).:
from django_pg import models class Hobbit(models.Model): name = models.CharField(max_length=50) favorite_foods = models.ArrayField(models.CharField(max_length=100)) created = models.DateTimeField(auto_now_add=True) modified = models.DateTimeField(auto_now=True)
This will create an array of strings in the database (to be precise: character varying(100) ). Assignment of values is done using standard Python lists:
pippin = Hobbit.objects.create( name='Peregrin Took', favorite_foods=['apples', 'lembas bread', 'potatoes'], )
As a note, do not attempt to store a full list of any hobbit’s favorite foods. Your database server does not have sufficient memory or swap space for such a list.
When looking up data against an array field, the field supports three lookup types: exact (implied), contains, and len.
The exact lookup type is the implied lookup type when doing a lookup in the Django ORM, and does not need to be explicitly specified. A straight lookup simply checks for array equality. Continuing the example immediately above:
>>> hobbit = Hobbit.objects.get( favorite_foods=['apples', 'lembas bread', 'potatoes'], ) >>> hobbit.name 'Peregrin Took'
The contains lookup type checks to see whether all of the provided values exist in the array. If you only need to check for a single value, and the value is not itself an array (in a nested case, for instance), you may specify the lookup value directly:
>>> hobbit = Hobbit.objects.get(favorite_foods__contains='apples') >>> hobbit.name 'Peregrin Took'
If you choose to do a contains lookup on multiple values, then be aware that order is not relevant. The database will check to ensure that each value is present, but ignore order of values in the array altogether:
>>> hobbit = Hobbit.objects.get( favorite_foods__contains=['lembas bread', 'apples'], ) >>> hobbit.name 'Peregrin Took'
The len lookup type checks the length of the array, rather than its contents. It maps to the array_length function in PostgreSQL (with the second argument set to 1).
Such lookups are simple and straightforward:
>>> hobbit = Hobbit.objects.get(favorite_foods__len=3) >>> hobbit.name 'Peregrin Took'
PostgreSQL 9.2 added initial support for a JSON data type. If you wish to store JSON natively in PostgreSQL, use the JSONField field:
from django_pg import models class Dwarf(models.Model): name = models.CharField(max_length=50) data = models.JSONField() created = models.DateTimeField(auto_now_add=True) modified = models.DateTimeField(auto_now=True)
If you’re using a version of PostgreSQL earlier than 9.2, this field will fall back to the text data type.
As of PostgreSQL 9.2, storing JSON is fully supported, but doing any useful kind of lookup (including direct equality) on it is not.
As such, django-pgfields supports storing JSON data, and will return the JSON fields’ data to you when you lookup a record by other means, but it does not support any kind of lookup against JSON fields. Attempting any lookup will raise TypeError.
Because field subclasses are called to convert values over and over again, there are a few cases where the conversion is not idempotent. In particular, strings that are also valid JSON (or look sufficiently close to valid JSON) will be deserialized again.
The short version: write Python dictionaries, lists, and scalars, and the JSON field will figure out what to do with it.
In order to store UUIDs in the database under the PostgreSQL UUID type, use the UUIDField field:
from django_pg import models class Elf(models.Model): id = models.UUIDField(auto_add=True, primary_key=True) name = models.CharField(max_length=50) created = models.DateTimeField(auto_now_add=True) modified = models.DateTimeField(auto_now=True)
The UUID field implements the following field options in addition to the field options available to all fields.
The UUID field interprets and writes blank values as SQL NULL. Therefore, setting blank=True requires null=True also. Setting the former but not the latter will raise AttributeError.
Normally, the UUIDField works like any other Field subclass; you are expected to provide a value, and the value is saved to the database directly.
If auto_add=True is set, then explicitly providing a value becomes optional. If no value is provided, then the field will auto-generate a random version 4 UUID, which will be saved to the database (and assigned to the model instance).
This is a particularly useful construct if you wish to store UUIDs for primary keys; they’re a completely acceptable substitute for auto-incrementing integers:
>>> legolas = Elf(name='Legolas Greenleaf') >>> legolas.id '' >>> legolas.save() >>> legolas.id UUID('b1f12115-3337-4ec0-acb9-1bcf63e44477')
By default, the to_python method on UUIDField will coerce values to UUID objects. Setting this option will use a different class constructor within to_python.
The general use-case for this is if you want to get strings instead of UUID objects. The following example would be the output in the case that you assigned coerce_to=str:
>>> legolas = Elf(name='Legolas Greenleaf') >>> legolas.save() >>> legolas.id 'b1f12115-3337-4ec0-acb9-1bcf63e44477'
The UUID field will return values from the database as Python UUID objects.
If you choose to do so, you may assign a valid string to the field. The string will be converted to a uuid.UUID object upon assignment to the instance:
>>> legolas = Elf(name='Legolas Greenleaf') >>> legolas.id = '01234567-abcd-abcd-abcd-0123456789ab' >>> legolas.id UUID('01234567-abcd-abcd-abcd-0123456789ab') >>> type(legolas.id) <class 'uuid.UUID'>
Lookups can be performed using either strings or Python UUID objects.