I am trying to deploy a django
app on vercel
that requires a module mysqlclient
but it seems to be failing because of some error for mysql_config
. I am using PlanetScale and had added integration. The error is:
Error: Command failed: pip3.9 install --disable-pip-version-check --target . --upgrade -r /vercel/path0/requirements.txt
error: subprocess-exited-with-error
× python setup.py egg_info did not run successfully.
│ exit code: 1
╰─> [16 lines of output]
/bin/sh: mysql_config: command not found
/bin/sh: mariadb_config: command not found
/bin/sh: mysql_config: command not found
Traceback (most recent call last):
File "<string>", line 2, in <module>
File "<pip-setuptools-caller>", line 34, in <module>
File "/tmp/pip-install-xudcpdyi/mysqlclient_9d1c2ef21f0b41d6aa185af14610a5f3/setup.py", line 15, in <module>
metadata, options = get_config()
File "/tmp/pip-install-xudcpdyi/mysqlclient_9d1c2ef21f0b41d6aa185af14610a5f3/setup_posix.py", line 70, in get_config
libs = mysql_config("libs")
File "/tmp/pip-install-xudcpdyi/mysqlclient_9d1c2ef21f0b41d6aa185af14610a5f3/setup_posix.py", line 31, in mysql_config
raise OSError("{} not found".format(_mysql_config_path))
OSError: mysql_config not found
mysql_config --version
mariadb_config --version
mysql_config --libs
[end of output]
note: This error originates from a subprocess, and is likely not a problem with pip.
error: metadata-generation-failed
And the final error is:
1: Command failed: pip3.9 install --disable-pip-version-check --target . --upgrade -r /vercel/path0/requirements.txt error: subprocess-exited-with-error × python setup.py egg_info did not run successfully. │ exit code: 1 ╰─> [16 lines of output] /bin/sh: mysql_config: command not found /bin/sh: mariadb_config: command not found /bin/sh: mysql_config: command not found Traceback (most recent call last): File "<string>", line 2, in <module> File "<pip-setuptools-caller>", line 34, in <module> File "/tmp/pip-install-xudcpdyi/mysqlclient_9d1c2ef21f0b41d6aa185af14610a5f3/setup.py", line 15, in <module> metadata, options = get_config() File "/tmp/pip-install-xudcpdyi/mysqlclient_9d1c2ef21f0b41d6aa185af14610a5f3/setup_posix.py", line 70, in get_config libs = mysql_config("libs") File "/tmp/pip-install-xudcpdyi/mysqlclient_9d1c2ef21f0b41d6aa185af14610a5f3/setup_posix.py", line 31, in mysql_config raise OSError("{} no
This solution works for me. I used planetscale.com to host my MySQL Database, but I'm sure it works with any other provider like AWS RDS MySQL (just make sure to tweak your settings.py file to remove or add OPTIONS as necessary).
first, install pyMySQL and dj_database_url packages
pip install pymysql
pip install dj_database_url
or if you are using pipenv:
pipenv install pymysql
pipenv install dj_database_url
Then, create a new file in your project folder, for example, mysql_setup.py.(e.g., this is the directory where you find the settings.py and wsgi.py files, your_project/your_project/mysql_setup.py) and add the following lines of code:
import pymysql
pymysql.version_info = (1, 4, 3, "final", 0)
pymysql.install_as_MySQLdb()
next, add the following lines of code at the beginning of your Django project's init.py file, which is located inside the same project folder (e.g., again, this is the directory where you find the settings.py and wsgi.py files, your_project/your_project/_init_.py):
add the following code:
from . import mysql_setup
Next, in your settings.py file
import dj_database_url
....
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': BASE_DIR / 'db.sqlite3',
}
}
DATABASES['default'] = dj_database_url.config(conn_max_age=600, ssl_require=True)
DATABASES['default']['OPTIONS']['charset'] = 'utf8mb4'
del DATABASES['default']['OPTIONS']['sslmode']
DATABASES['default']['OPTIONS']['ssl'] = {'ca': os.environ.get('MYSQL_ATTR_SSL_CA')}
Next, remember to update your requirements.txt file to include the installed packages
dj-database-url==2.0.0
PyMySQL==1.0.3
or recreate the entire requirements.txt file using the pip freeze command:
pip freeze > requirements.txt
NOTES: You will need to add the DATABASE_URL variable to the Vercel env variables for the project.
It looks something like this:
DATABASE_URL=mysql://user:password@host/dbname
you can get your connection string by going inside your planetscale project, go to overview and hit the "connect" button.
then, in the "Connect With" option select "Rust" and on the "Terminal" tab you will find your connection string in the format you need.
I didn't have to add the MYSQL_ATTR_SSL_CA variable to Vercel env variables, but if complains of a missing variable try adding this environment variable: MYSQL_ATTR_SSL_CA=/etc/ssl/cert.pem
NOTE: Remember to change my_project_name with your actual project name.
wsgy.py (just add app = application at the end of your file)
import os
from django.core.wsgi import get_wsgi_application
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'my_project_name.settings')
application = get_wsgi_application()
app = application
This is my build.sh file that I use to tell Vercel what commands to run on this project like installing dependencies and running the migrations:
build.sh (this file should be at the root of the project)
#!/bin/bash
# Build the project
echo "Building the project..."
python3.9 -m pip install -r requirements.txt
echo "Make Migration..."
python3.9 manage.py makemigrations --noinput
python3.9 manage.py migrate --noinput
echo "Collect Static..."
python3.9 manage.py collectstatic --noinput --clear
vercel.json (this file should be at the root of the project)
{
"version": 2,
"builds": [
{
"src": "your_project_name/wsgi.py",
"use": "@vercel/python",
"config": {
"maxLambdaSize": "15mb",
"runtime": "python3.9"
}
},
{
"src": "build.sh",
"use": "@vercel/static-build",
"config": {
"distDir": "staticfiles_build"
}
}
],
"routes": [
{
"src": "/static/(.*)",
"dest": "/static/$1"
},
{
"src": "/(.*)",
"dest": "your_project_name/wsgi.py"
}
]
}
Also, remember to make these changes to the settings.py file in order to make the collectstatic command works correctly inside the build.sh file.
settings.py
DEBUG = False
.....
STATIC_URL = '/static/'
STATIC_ROOT = BASE_DIR / 'staticfiles_build' / 'static'