Django: Step-by-step Slack integration
I recently added Slack integration into my Django app, and wanted to share the steps I took to get there. Overall the process was quite painless, and the slack_sdk
does make things very simple. In this article I’ll be piecing together the various components necessary to get this integration working.
Create a Slack App
Readers who already have a Slack app installed in their workspace can skip this step and re-use their existing app. I was in a situation where I didn’t have such an app, so I had to run the steps below:
- Over at the Slack API website, choose “My App”, then use the button “Create new app” and select the “from scratch” option.
- On the App settings page, navigate to the “OAuth & Permissions” page from the left-hand menu.
- Add the scopes:
users:read
andusers:read:email
andchat:write:bot
andim:write
(others may be necessary as well depending on what you want your integration to do) - Install the app to your test workspace.
- Navigate back to the “OAuth and Permissions” page, there should now be an “OAuth Access Token” displayed which we will use in the next section to connect to Slack.
Install the SDK to your Django environment
Now that we have a Slack app ready for our Django instance to use, the next step to install the Slack Python SDK to our environment and start using it!
First, install the SDK using pip: pip install slack_sdk
(or use python -m pip
depending on how your environment is configured)
Once installed, we can initialize a connection to our Slack workspace using the SDK as follows:
from slack_sdk import WebClient
MY_SLACK_TOKEN = 'OAuth Token Goes Here'
MY_CHANNEL_ID = 'ABCD1F2GH'
client = WebClient(token=MY_SLACK_TOKEN)
response = self.client.chat_postMessage(
channel=MY_CHANNEL_ID,
text='Hello world!'
)
Note the Channel ID, which is obtained by observing the last part of the URL when navigating to the desired channel in Slack in your browser.
Once run, the code above will post the message Hello World!
to the Slack channel using the Slack App’s OAuth token obtained from step 5 of the prior section.
The next logical step is to move the MY_SLACK_TOKEN
variable into settings.py
though for my Django app, I moved it into my secrets manager, then have Django retrieve it from there.
Our Django app can now send messages to Slack channels of our choosing, but what about DMs to specific users? Turns out that is slightly more complex.
Determine the Slack User ID
In order to send DMs to specific users, we’ll need to know their Slack User ID. As the Django user ID and the Slack user IDs are not the same, we’ll need to create a “translation” method to reliably get a user’s Slack ID.
In order to do this translation, we’ll need a reliable piece of information to do the lookups against that is shared between both slack and Django. Unfortunately in my case, the usernames were not the same and so those were not a reliable lookup strategy. Instead, I had to use E-mail addresses.
Here is what my lookups look like:
from slack_sdk import WebClient
from django.contrib.auth.models import User
from .settings import SLACK_OAUTH_TOKEN
def get_slack_id(user: User) -> int:
"""
Given a Django `User` record, determine the corresponding Slack User ID
"""
client = WebClient(token=SLACK_OAUTH_TOKEN)
response = client.users_lookupByEmail(email=user.email)
slack_user_id = response.get('user').get('id')
return slack_user_id
Send Slack DM to User
Once we’ve determined the Slack User ID, we can call into the chat_postMessage
method same as before, but this time we need to prepend the @
to the user ID, as seen below:
from slack_sdk import WebClient
from .settings import SLACK_OAUTH_TOKEN
from django.contrib.auth.models import User
django_user = User.objects.get(username='testuser')
slack_user_id = get_slack_id(django_user)
response = self.client.chat_postMessage(
channel=f'@{slack_user_id}',
text=f'Hello {django_user.first_name}!'
)
We can optionally send more complex messages using the blocks
parameter. This utilizes Slack’s block kit to build rich text. For example:
response = client.chat_postMessage(
channel=MY_CHANNEL,
blocks=[
{
"type": "header",
"text": {
"type": "plain_text",
"text": "Greetings From Django!"
}
},
{
"type": "divider"
},
{
"type": "section",
"text": {
"type": "plain_text",
"text": "This is a rich text message from Django, using Slack blocks.",
}
}
],
text='Message without blocks'
)
And that’s the basics of the integration. The slack_sdk
is capable of much more than this, so I encourage delving further into the documentation to see how it can be suit your needs!
Recommended Reading
- Slack Python SDK Documentation
- Slack block kit reference guide
- Slack Apps