Fields - Django Gcloud Connectors Documentation

# Fields

gcloudc includes a collection of Django model fields which leverage aspects of the Google Cloud Datastore.

## ListField

This field takes advantage of the Datastore's ability to store multiple values under a single field/property name.

The field takes another field definition as its first argument, and will then store a list of values of the given field.

Example usage:

    from gcloudc.db.models.fields.charfields import CharField
    from gcloudc.db.models.fields.iterable import ListField

    class MyModel(models.Model):
        things = ListField(CharField(), choices=[('a', 'A'), ('b', 'B')])

Note that the `choices` are set on the outer `ListField`, not on the inner `Charfield`.

See also Querying on iterable fields

## SetField

This is essentially the same as `ListField`, but removes duplicate values and the values are unordered.

## CharOrNoneField

A field that stores only non-empty strings or None (it won't store empty strings). This is useful if you want values to be unique but also want to allow empty values.

It is generally not good practice to put `null=True` on a Django `CharField`, and even if you do, when you edit such a field through a Django form, an empty value will be stored as an empty string rather than `None`.

This field will instead store empty values as `None`, which then allows enforcement of uniqueness for non-empty values (because multiple empty string values will violate a unique constraint, whereas multiple `None` values will not).

## TrueOrNoneField

A field that stores either `True` or `None`. This is useful for when you want to enforce that only one object can have this field set to `True`. Any objects on which the field value is `None` will be ignored by unique constraints, thereby allowing you to set `unique=True` on the field to enforce that only one object can have the field set to `True`.

Similarly, you can use the field in a `unique_together` constraint, and any `None` values will be ignored by the constraint.

## CharField

On the Cloud Datastore, every `str` property has the same maximum length of 1500 bytes (not characters), so the required `max_length` argument of Django's `CharField` is both ignored and unreliable.

gcloudc's `CharField` sets a default `max_length` of 1500 and enforces it in bytes, the same way as the Datastore does.

This means you can omit the `max_length` argument from the field, and can rely on the field to correctly validate the values to the requirements of the database.

## RelatedListField

This is a specific variation of `SetField` which essentially stores a list of `ForeignKey`s.

This is a powerful and very useful alternative to Django's `ManyToManyField`. There is a limit to the number of related objects which can be stored in a single field, so you need to think about your architecture carefully in terms of how it will scale, but for many use cases it can be a great solution.

For example, if you have an application in which each user can browse products and add products to a list of favourites, you could have a `User` model with a `RelatedListField` of `Product` objects, and so long as you restrict each use to a maximum of 500 favourited products, the application can scale to an unlimited number of users without any problems.

    RelatedListfield(to, limit_choices_to=None, related_name=None, on_delete=models.DO_NOTHING, **kwargs)

Example usage:

    from gcloudc.db.models.fields.related import RelatedListField

    class Product(models.Model):
        ...

    class User(models.Model):
        favourites = RelatedListField(Product)

    user = User.objects.get(pk=1)
    product = Product.objects.get(name="kettle")
    user.favourites.append(product)
    user.save()

## RelatedSetField

This is essentially the same as `RelatedListField`, but removes duplicate values and the values are unordered.

## Computed fields

In order to ensure that all queries are efficient, the Cloud Datastore does not allow queries which perform query-time calculations on the field values, such as `HOUR(field_name)` or `field_a > field_b`. In some of these cases (such as the `HOUR` example), gcloudc's special indexes functionality can pre-compute these values for you and save them to an index. But sometimes you'll want to pre-compute values yourself in order to query on them.

`gcloudc.db.models.fields.computed` provides a set of fields which allow you to easily compute a value at save-time which can then be queried directly.

Each computed field generally takes the same values as the standard version of the field, but the first argument must be either:

- A callable which will be passed the model instance and should return the computed value to be stored.
- A string giving the name of a method on the model class which will return the computed value to be stored.

Example usage:

    class MyModel(models.Model):
        wholesale_price = PositiveIntegerField()
        retail_price = PositiveIntegerField()

        profit = ComputedPositiveIntegerField("_calculate_profit")

        def _calculate_profit(self):
            return self.retail_price - self.wholesale_price

With all computed fields, the values are computed and saved during the execution of the `save` method. So if you're adding a computed field to an existing model, you'll need to re-save all existing objects before you can query on the computed values.

The available computed fields are:

- `ComputedCharField`
- `ComputedTextField`
- `ComputedIntegerField`
- `ComputedPositiveIntegerField`
- `ComputedBooleanField`
- `ComputedCollationField` (see below)

If you need another type of computed field, you can easily make your own using `ComputedFieldMixin`, like this:

    from gcloudc.db.models.fields.computed import ComputedFieldMixin

    class ComputedDateField(ComputedFieldMixin, models.Datefield):
        pass

`ComputedCollationField` works slightly differently to the others. App Engine sorts strings based on the unicode codepoints that make them up. When you have strings from non-ASCII languages this makes the sort order incorrect (e.g. Ł will be sorted after Z). This field uses the pyuca library to calculate a sort key using the Unicode Collation Algorithm, which can then be used for ordering querysets correctly.

Unlike the other computed fields, this field should be passed the name of the field whose collation it is storing as the first argument.

Example usage:

    from gcloudc.db.models.fields.charfields import CharField
    from gcloudc.db.models.fields.computed import ComputedCollationField

    class Customer(models.Model):
        name = CharField()
        sortable_name = ComputedCollationField("name")

    Customer.objects.create(name="Ale")
    Customer.objects.create(name="Łukasz")
    Customer.objects.create(name="Rachel")

    Customer.objects.order_by("name")
    [<Customer Ale>, <Customer Rachel>, <Customer Łukasz>]

    Customer.objects.order_by("sortable_name")
    [<Customer Ale>, <Customer Łukasz>, <Customer Rachel>]

## Querying on iterable fields

`ListField`, `SetField`, `RelatedListField` and `RelatedSetField` can all be queried using the `__contains` and `__overlap` filters that you can use on the Postgres ArrayField. The `__contained_by` filter is not currently supported.

Note that for `__contains` filters, if you're only querying with a single value then you can simply do: `.filter(iterable_field__contains=value)` rather than `.filter(iterable_field__contains=[value])`.

For the `RelatedListField` and `RelatedSetField` you can pass either model instances or primary keys as values to the filter.

GitLab « Previous Next »