Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Django + Postgres = ?

Django + Postgres = ?

Current situation of Postgres support in Django, why it matters and what will change in future Django releases.

Volodymyr Hotsyk

March 05, 2015
Tweet

More Decks by Volodymyr Hotsyk

Other Decks in Programming

Transcript

  1. About me • Python developer at GetGoing • PyCon Ukraine

    organizer • github/twitter/gmail: hotsyk
  2. Outline • Why Postgres • Python + Postgres • PL/Python

    • Django support • Range types • Array type • HStore • JSONType • UUIDField • Indexes • Fulltext search • Pools
  3. Why Postgres • Window functions • Flexible Datatypes • Functions

    • Custom Languages • Extensions • Full text search
  4. Why Postgres • Foreign Data Wrappers • Conditional Constraints and

    Partial Indexes • Listen/Notify • Table Inheritance • Real NoSQL in SQL
  5. PL/Python CREATE FUNCTION pyreplace(x text) RETURNS text AS $$ return

    x.replace('123', '256') $$ LANGUAGE plpythonu;
  6. Django support • Django ORM designed to work with all

    supported DBs • No Postgres specific features • Third-party apps to add support of specific features
  7. contrib.postgres in 1.8 • Specific model fields • ArrayField •

    HStoreField • Range Fields • Specific form fields and widgets • SimpleArrayField • SplitArrayField • HStoreField • Range Fields • Widgets
  8. contrib.postgres in 1.8 • Database migration operations • CreateExtension •

    HStoreExtension • UnaccentExtension • Specific lookups • Unaccent • Validators • KeysValidator • Range validators
  9. Range types • int4range — Range of integer • int8range

    — Range of bigint • numrange — Range of numeric • tsrange — Range of timestamp without time zone • tstzrange — Range of timestamp with time zone • daterange — Range of date
  10. Range types CREATE TABLE reservation (room int, during tsrange); INSERT

    INTO reservation VALUES (1, '[2015-01-31 14:30, 2015-01-31 15:30)');
  11. Range types from django.contrib.postgres import fields from django.db import models

    class Event(models.Model): name = models.CharField(max_length=50) ages = fields.ranges.IntegerRangeField()
  12. Range types Event.objects.create(name='Meetup', ages=(18, 70)) Event.objects.create(name='Meetup 2', ages=(10, 30)) events

    = Event.objects.filter( ages__contains=NumericRange(20, 35)) print([e.name for e in events]) >> [u'Meetup']
  13. Range types events = Event.objects.filter( ages__contained_by=NumericRange(0, 55)) print([e.name for e

    in events]) >> [u'Meetup 2'] events = Event.objects.filter( ages__overlap=NumericRange(18, 22)) print([e.name for e in events]) >> [u'Meetup', u'Meetup 2']
  14. Range types events = Event.objects.filter( ages__fully_lt=NumericRange(31, 35)) print([e.name for e

    in events]) >> [u'Meetup 2'] events = Event.objects.filter( ages__adjacent_to=NumericRange(70, 80)) print([e.name for e in events]) >> [u'Meetup']
  15. Booking example from django.contrib.postgres import fields from django.db import models

    class Hotel(models.Model): title = models.CharField(max_length=200) class Room(models.Model): hotel = models.ForeignKey(Hotel) title = models.CharField(max_length=200) class Booking(models.Model): room = models.ForeignKey(Room) dates = fields.ranges.DateRangeField()
  16. Booking example from psycopg2.extras import DateRange hotel = Hotel.objects.create(title=‘hotel') room

    = Room.objects.create( hotel=hotel, title=‘room') day = datetime.timedelta(days=1) date1 = (datetime.datetime.now() + datetime.timedelta(days=7)).date() date2 = date1 + day
  17. Booking example Booking.objects.create( room=room, dates=(date1, date2)) Booking.objects.create( room=room, dates=(date1, date2

    + day)) print([b for b in Booking.objects.filter( dates__overlap=DateRange( date2, date2 + day, bounds='[)'))]) >> [<Booking: Booking object>]
  18. Array type CREATE TABLE tictactoe (squares integer[3][3]); • Postgres 9.0+

    • Django <=1.7: djorm-pgarray, other apps • Django 1.8: contrib.postgres.fields.array
  19. Array type from django.contrib.postgres import fields class Post(models.Model): name =

    models.CharField( max_length=50) tags = fields.array.ArrayField( models.CharField( max_length=20))
  20. Array type print([p.name for p in Post.objects.filter( tags__contains=['django'])]) >> [u'First',

    u'Third'] print([p.name for p in Post.objects.filter( tags__contains=[‘django', 'thoughts'])]) >> [u'First']
  21. HStore type from django.contrib.postgres import fields from django.db import models

    class Location(models.Model): name = models.CharField( max_length=50) location = \ fields.hstore.HStoreField()
  22. HStore type locations = Location.objects.filter( location__lat__contains='50') print([l.name for l in

    locations]) # >> [u'Kyiv'] locations = Location.objects.filter( location__contained_by={'lat': ’49.85', 'long': '24.0166666667','timezone': 'any'}) print([l.name for l in locations]) # >> [u'Lviv']
  23. JSONType • Postgres 9.4+ • Document DB in your SQL

    DB • Django 1.7, 1.8: bitbucket.org/schinckel/django- postgres/ • Django 1.9: contrib.postgres
  24. JSONType print([m.json for m in MyJson.objects.filter( json__has_all=['a', 'b'])]) >> [{u'a':

    1, u'b': {u'c': 2, u'd': 3}}] print([m.json for m in MyJson.objects.filter( json__path_b_c__gt=2)]) >> [{u'b': {u'c': 4, u'f': 5}, u'd': 3}]
  25. UUID field • UUIDField - new in Django 1.8 •

    With PostgreSQL —> uuid datatype • Otherwise —> char(32).
  26. UUID field import uuid from django.db import models class MyUUIDModel(models.Model):

    id = models.UUIDField( primary_key=True, default=uuid.uuid4, editable=False)
  27. Indexes B-tree, Hash, GiST and GIN CREATE UNIQUE INDEX IDX1

    ON Table1 (t1, t2) WHERE t2 IS NOT NULL; CREATE INDEX CONCURRENTLY IDX2 ON Table1(t2, t3); CREATE INDEX name ON table USING hash (column);
  28. FullText Search class Page(models.Model): name = models.CharField(max_length=200) description = models.TextField()

    search_index = VectorField() objects = SearchManager( fields=('name', 'description'), config='pg_catalog.russian', search_field='search_index', auto_update_search_field = True )
  29. Pools • Postgres database connections are expensive • Django 1.6+

    - builtin pool • Django <1.6 - django-postgrespool, djorm-ext-pool, django-db-pool • Django -> PG Pool / PG Bounce -> Postgres