Listening for postgres NOTIFY with django.db - adding support for connection.fileno()

702 views
Skip to first unread message

Fábio Molinar

unread,
Dec 31, 2018, 6:38:31 AM12/31/18
to Django developers (Contributions to Django itself)
Hi, 

I have a custom method on my model manager that allows me to listen for notifications from modifications on the DB using postgreSQL. A short version of this code looks like this:

def listen_for_notify(self):
        import select
        import psycopg2
        import psycopg2.extensions

        from django.conf import settings
        
        db_data = settings.DATABASES['default']
        listened = None
        returned_empty = None
search_timeout = 15

        conn = psycopg2.connect(dbname=db_data['NAME'], user=db_data['USER'], password=db_data['PASSWORD'], host=db_data['HOST'], port=db_data['PORT'])
        conn.set_isolation_level(psycopg2.extensions.ISOLATION_LEVEL_AUTOCOMMIT)
        curs = conn.cursor()
        curs.execute("LISTEN default;")

        timeout = timezone.now() + timezone.timedelta(0, search_timeout)
        while timezone.now() < timeout:
            time_diff = timeout - timezone.now()
            if select.select([conn], [], [], float(time_diff.seconds)) == ([], [], []):
                listened = False
                timeout = timezone.now()
            else:
                conn.poll()
                while conn.notifies:
                    notify = conn.notifies.pop(0)
                    if notify.payload == "notified":
                        listened = True
                        returned_empty = False
                        timeout = timezone.now()
                    if notify.payload == 'search request returned empty':
                        listened = True
                        returned_empty = True
                        timeout = timezone.now()
        curs.close()
        conn.close()
        return listened, returned_empty

It would be really nice if instead of using the psycopg2 library, I could use only django.db. Something like this:

def listen_for_notify(self):
        from django.db import connection as conn
        
        listened = None
        returned_empty = None
search_timeout = 15

        with conn.cursor() as curs
timeout = timezone.now() + timezone.timedelta(0, search_timeout)
while timezone.now() < timeout:
time_diff = timeout - timezone.now()
if select.select([conn], [], [], float(time_diff.seconds)) == ([], [], []):
listened = False
timeout = timezone.now()
else:
conn.poll()
while conn.notifies:
notify = conn.notifies.pop(0)
if notify.payload == "notified":
listened = True
returned_empty = False
timeout = timezone.now()
if notify.payload == 'search request returned empty':
listened = True
returned_empty = True
timeout = timezone.now()
        return listened, returned_empty

I tried out the solution above using django.db, but it doesn't work because the django.db.connection object don't have a fileno() method.

Is this currently not supported or am I missing something? I though that the django.db is kind of just a wrapper around the actual psycopg2 library. So I wonder why I can't use the fileno() method on it.

Florian Apolloner

unread,
Jan 1, 2019, 8:50:20 AM1/1/19
to Django developers (Contributions to Django itself)
Hi,


On Monday, December 31, 2018 at 12:38:31 PM UTC+1, Fábio Molinar wrote:
Is this currently not supported or am I missing something? I though that the django.db is kind of just a wrapper around the actual psycopg2 library. So I wonder why I can't use the fileno() method on it.

django.db.connection provides a common interface for all databases, the underlying actual connection is stored as connection attribute as seen in https://github.com/django/django/blob/master/django/db/backends/base/base.py#L194 -- I hope this helps.

cheers,
Florian

Fábio Molinar

unread,
Jan 4, 2019, 3:16:42 PM1/4/19
to django-d...@googlegroups.com
Thank you sir, that's what I was hoping to find! :)

Yours sincerely,

Fábio Thomaz Molinar


--
You received this message because you are subscribed to a topic in the Google Groups "Django developers (Contributions to Django itself)" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/django-developers/BeugSYXeO2I/unsubscribe.
To unsubscribe from this group and all its topics, send an email to django-develop...@googlegroups.com.
To post to this group, send email to django-d...@googlegroups.com.
Visit this group at https://groups.google.com/group/django-developers.
To view this discussion on the web visit https://groups.google.com/d/msgid/django-developers/cd615dbc-689a-4f34-84a1-6110157ee16f%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
Reply all
Reply to author
Forward
0 new messages