Skip to content

Instantly share code, notes, and snippets.

@mw3i
Last active September 22, 2024 04:36
Show Gist options
  • Save mw3i/b879895272a28d1c789f23ee91555620 to your computer and use it in GitHub Desktop.
Save mw3i/b879895272a28d1c789f23ee91555620 to your computer and use it in GitHub Desktop.
Truly Standalone Django-ORM Wrapper
'''
Proof of Concept:
Django devs built an ORM that seems way more straightforward than many existing tools. This class lets you leverage the django-orm without any project settings or other aspects of a django setup.
There are probably weak points and functionality missing, but it seems like a relatively intuitive proof of concept
'''
import os
import django
from django.conf import settings
from django.db import models, connections
class Database:
def __init__(self, engine='django.db.backends.sqlite3', name=None, user=None, password=None, host=None, port=None):
self.Model = None
# Define the DATABASES dictionary
databases = {
'default': {
'ENGINE': engine,
'NAME': name,
'USER': user,
'PASSWORD': password,
'HOST': host,
'PORT': port,
'APP_LABEL': 'isolated',
}
}
# Update the settings with the custom DATABASES dictionary
settings.configure(DATABASES=databases)
# Initialize Django
django.setup()
# Create the custom base model
class CustomBaseModel(models.Model):
class Meta:
app_label = 'isolated'
abstract = True
self.Model = CustomBaseModel
# Create a table if it doesnt exist
def create_table(self, model):
with connections['default'].schema_editor() as schema_editor:
if model._meta.db_table not in connections['default'].introspection.table_names():
schema_editor.create_model(model)
# Update table if you added fields (doesn't drop fields as far as i know, which i was too afraid to implement)
def update_table(self, model):
with connections['default'].schema_editor() as schema_editor:
# Check if the table exists
if model._meta.db_table in connections['default'].introspection.table_names():
# Get the current columns in the table
current_columns = [field.column for field in model._meta.fields]
# Get the database columns
database_columns = connections['default'].introspection.get_table_description(connections['default'].cursor(), model._meta.db_table)
database_column_names = [column.name for column in database_columns]
# Check if each field in the model exists in the database table
for field in model._meta.fields:
if field.column not in database_column_names:
# Add the new column to the table
schema_editor.add_field(model, field)
# Example Usage (pretty easy right?)
if __name__ == '__main__':
db = Database(engine='django.db.backends.sqlite3', name='mydatabase')
# This is required
class Test(db.Model):
name = models.CharField(max_length = 200, null = True)
email = models.CharField(max_length = 200, null = True)
Test._meta.db_table = 'test' # <-- this is also required; otherwise, django assumes the table is named `{appname}_{tablename}`, which in this case would be 'isolated_test'
db.create_table(Test) # <-- this is required if the table doesnt already exist; could probably even make this happen automatically when initializing the table
# Add row to table
test = Test(name = 'hey', email = '[email protected]')
test.save()
test = Test(name = 'hi')
test.save()
'''
This feels like it covers 95% of use cases for most lightweight projects involving relational databases, but I could be wrong
Some cool changes might be:
- add a line `fields = models` so you can just import this module and have access to all the django fields (rather than even more import statements)
'''
@progressify
Copy link

How does it work with migrations?

@mw3i
Copy link
Author

mw3i commented Jul 11, 2024

@progressify it's not (as far as I know) keeping track of migrations. So it's probably flexible to schema changes (assuming you update the db.Model class), but it also isn't going to maintain a history of changes either

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment