Created
March 11, 2011 12:03
-
-
Save andialbrecht/865808 to your computer and use it in GitHub Desktop.
Adds Meta option db_column_prefix that prepends a per-model prefix to db column names
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# -*- coding: utf-8 -*- | |
# This hack adds a new Meta option "db_column_prefix". If not None all | |
# database columns in a model will be prepended with this prefix (the | |
# database columns, not the attributes). See Person model for an | |
# example. | |
# | |
# Issues: | |
# - How to set a prefix for a m2m table? - If "through" argument is | |
# not specified on a M2MField, Django automatically adds a model | |
# representing the m2m table (search for | |
# create_many_to_many_intermediary_model). It's not easy to hook | |
# into this process without really ugly hacks. So the easiest way is | |
# to use the "through" argument... | |
# - Get rid of monkey patching | |
# - If your db admin is sitting next to you, you need to have prefixes | |
# for tables generated by other apps (like auth) too. With this | |
# approach there's currently no way to achieve this. It'd be great | |
# to have a central place for building table and column names (maybe | |
# the db backend?) | |
from django.db import models | |
# Monkey-patch DEFAULT_NAMES for Meta options. Otherwise | |
# db_column_prefix would raise an error. | |
from django.db.models import options | |
options.DEFAULT_NAMES += ("db_column_prefix",) | |
class ColumnPrefixModelMeta(models.base.ModelBase): | |
"""Model metaclass that adds Meta.db_column_prefix to a db column name.""" | |
def __new__(cls, name, bases, attrs): | |
new_cls = super(ColumnPrefixModelMeta, cls).__new__( | |
cls, name, bases, attrs) | |
prefix = getattr(new_cls._meta, "db_column_prefix", None) | |
# db_column_prefix on abstract base classes will be ignored. | |
if not new_cls._meta.abstract and prefix is not None: | |
# Shamelessly stolen from ModelBase.__new__: | |
new_fields = new_cls._meta.local_fields + \ | |
new_cls._meta.local_many_to_many + \ | |
new_cls._meta.virtual_fields | |
for field in new_fields: | |
if field.db_column is None: | |
field.db_column = field.get_attname() | |
if not field.db_column.startswith(prefix): | |
field.db_column = "%s%s" % (prefix, field.db_column) | |
# This sets field.column which is needed for build SQL | |
# statements | |
field.set_attributes_from_name(field.name) | |
return new_cls | |
class Person(models.Model): | |
__metaclass__ = ColumnPrefixModelMeta | |
first_name = models.CharField(max_length=30) | |
last_name = models.CharField(max_length=30) | |
created = models.DateTimeField( | |
auto_now_add=True, db_column="crdate") | |
modified = models.DateTimeField( | |
auto_now=True, db_column="upddate") | |
class Meta: | |
# The following column names will be used: per_first_name, | |
# per_last_name, per_crdate, per_uppdate. | |
db_column_name = "per_" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment