2๐
After reading a bit more โ running SQL to load data in the migration is the wrong way to go about it. Using fixtures is much better.
Iโve since added a fixture and will use that file for bringing in the data.
First, to create the fixture I had to add my data to the table (I just ran the SQL file manually to add it to the appropriate table).
Then I ran
manage.py dumpdata mileage.mileage --indent 2 --format=json --output initial_mileages.json
That created my fixture, which I then loaded with
manage.py loaddata initial_mileages.json
and it imported beautifully.
15๐
migrations.RunSQL()
Does not accept a file as input. Only raw SQL. To solve this you need to use either:
migrations.RunSQL(
"""
INSERT INTO 'mileages_mileages' ('id', 'miles', 'start_location', 'end_location')
VALUES
(NULL,3, 'Location 1', 'Location 2');
""")
or
def load_data_from_sql(apps, schema_editor):
file_path = os.path.join(os.path.dirname(__file__), 'file_name.sql')
sql_statement = open(file_path).read()
with connection.cursor() as c:
c.execute(sql_statement)
class Migration(migrations.Migration):
dependencies = [
('..', '...'),
]
operations = [
migrations.RunPython(load_data_from_sql),
]
- Psycopg2 OperationalError: cursor does not exist
- Django: default language i18n
- Django โ check cookies's "SameSite" attribute
5๐
Here is the full script(not perfect, but as is) for converting MySQL statements with DELIMITER to SQL execution.
Information about multiply delimiters in SQL statement https://stackoverflow.com/a/52292690/9521312
Add script execution in migration file
There are both examples of using script: run sql file or run raw MySQL statement
from anywhere import migrate_run_sql
operations = [
migrations.RunPython(migrate_run_sql.run_sql_file('contract_triggers.sql')),
migrations.RunPython(migrate_run_sql.run_sql(
"""
DELIMITER $$
CREATE TRIGGER trigger_name BEFORE INSERT ON table
FOR EACH ROW
BEGIN
IF NEW.number <> 'anynumber' AND NEW.number <> 'anynumber'
THEN
SET NEW.number = 'anynumber';
END IF;
END$$
"""
))
]
Script file
# -*- coding: utf-8 -*-
from django.db import connection
import re
from StringIO import StringIO
from django.conf import settings
import os
# this function get raw MySQL statement
def run_sql(sql):
def load_data_from_sql(app, schema_editor):
f = StringIO(sql)
return _runsql(f)
return load_data_from_sql
# this function get sql file
def run_sql_file(filename):
def load_data_from_sql(app, schema_editor):
filepath = os.path.join(settings.PROJECT_PATH, '../deploy/mysql/', filename)
with open(filepath, 'rb') as f:
return _runsql(f)
return load_data_from_sql
# in this function content splits and checks line by line
def _runsql(f):
with connection.cursor() as c:
file_data = f.readlines()
statement = ''
delimiter = ';\n'
for line in file_data:
if re.findall('DELIMITER', line): # found delimiter
if re.findall('^\s*DELIMITER\s+(\S+)\s*$', line):
delimiter = re.findall('^\s*DELIMITER\s+(\S+)\s*$', line)[0] + '\n'
continue
else:
raise SyntaxError('Your usage of DELIMITER is not correct, go and fix it!')
statement += line # add lines while not met lines with current delimiter
if line.endswith(delimiter):
if delimiter != ';\n':
statement = statement.replace(';', '; --').replace(delimiter, ';') # found delimiter, add dash symbols (or any symbols you want) for converting MySQL statements with multiply delimiters in SQL statement
c.execute(statement) # execute current statement
statement = '' # begin collect next statement
Hope it will help!
- Create UUID on client and save primary key with Django REST Framework and using a POST
- Django: Lookup by length of text field
- Deploying Django to Elastic Beanstalk, migrations failed
- Is it possible to create subparsers in a django management command?
- Django: Using Annotate, Count and Distinct on a Queryset
2๐
When using migrations.RunSQL
, if you get the following error:
sqlparse is required if you donโt split your SQL
You just need to install sqlparse
to solve the problem:
pip install sqlparse
- How to use forms in django-cms?
- Django count related objects
- Django-admin command error while project creation
1๐
You can execute a raw SQL
operations = [
migrations.RunSQL('sql statement here')
]
- Django: passing JSON from view to template
- Extending User object in Django: User model inheritance or use UserProfile?
- Django: What's the use of the context_instance parameter in the render shortcut function?
- There is a way to add features to an existing django command?
0๐
Inspiration from paveldrooโs solution by creating a wrapper around migrations.RunSQL
to load the sql file:
# core/migrations.py
from pathlib import Path
from typing import AnyStr
from django.db import migrations
def _read_sql_file(path: Path) -> AnyStr:
with open(path, "r") as sql_file:
return sql_file.read()
class RunSQLFile(migrations.RunSQL):
def __init__(
self,
sql_file_path: Path,
reverse_sql=None,
state_operations=None,
hints=None,
elidable=False,
):
sql = _read_sql_file(sql_file_path)
super().__init__(
sql=sql,
reverse_sql=reverse_sql,
state_operations=state_operations,
hints=hints,
elidable=elidable,
)
# app/models.py
class MyModelView(models.Model):
class Meta:
managed = False
db_table = "my_model_view"
id = models.IntegerField(primary_key=True)
name = models.CharField(max_length=1024)
updated = models.DateTimeField()
-- app/sql/my_model_view.sql
DROP VIEW IF EXISTS my_model_view;
CREATE VIEW my_model_view AS (
-- SELECT HERE
)
# app/migrations/0002_create_my_model_view.py
# Generated by Django 3.2 on 2023-03-06 22:11
from pathlib import Path
from django.db import migrations, models
from core.migrations import RunSQLFile
class Migration(migrations.Migration):
dependencies = [
("0001_initial"),
]
operations = [
migrations.CreateModel(
name="MyModelView",
fields=[
("id", models.IntegerField(primary_key=True, serialize=False)),
("name", models.CharField(max_length=1024)),
("updated", models.DateTimeField()),
],
options={
"db_table": "my_model_view",
"managed": False,
},
),
RunSQLFile(
sql_file_path=Path(
"./app/sql/my_model_view.sql"
),
reverse_sql="DROP VIEW IF EXISTS my_model_view",
),
]
- How to convert request.user into a proxy auth.User class?
- How do I restrict access to admin pages in Django?
- Client-Side (JavaScript) Django/Jinja-like template inheritance