Django

Code

Changeset 7743

Show
Ignore:
Timestamp:
06/25/08 22:11:32 (3 months ago)
Author:
mtredinnick
Message:

Fixed #7109 -- Quote certain values before passing them for substitution in
Field.db_type().

This fixes a problem with using reserved words for field names in Oracle. Only
affects Oracle at the moment, but the same changes could easily be used by
other backends if they are required (requires changing creation.py, only).

This commit also reverts [7501] so that if the fix doesn't work, it will show
up in the tests (and if it does work, the tests will prevent us from breaking
it again).

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • django/trunk/django/db/backends/oracle/creation.py

    r6378 r7743  
    66# be interpolated against the values of Field.__dict__ before being output. 
    77# If a column type is set to None, it won't be included in the output. 
     8# 
     9# Any format strings starting with "qn_" are quoted before being used in the 
     10# output (the "qn_" prefix is stripped before the lookup is performed. 
     11 
    812DATA_TYPES = { 
    913    'AutoField':                    'NUMBER(11)', 
    10     'BooleanField':                 'NUMBER(1) CHECK (%(column)s IN (0,1))', 
     14    'BooleanField':                 'NUMBER(1) CHECK (%(qn_column)s IN (0,1))', 
    1115    'CharField':                    'NVARCHAR2(%(max_length)s)', 
    1216    'CommaSeparatedIntegerField':   'VARCHAR2(%(max_length)s)', 
     
    2024    'IntegerField':                 'NUMBER(11)', 
    2125    'IPAddressField':               'VARCHAR2(15)', 
    22     'NullBooleanField':             'NUMBER(1) CHECK ((%(column)s IN (0,1)) OR (%(column)s IS NULL))', 
     26    'NullBooleanField':             'NUMBER(1) CHECK ((%(qn_column)s IN (0,1)) OR (%(column)s IS NULL))', 
    2327    'OneToOneField':                'NUMBER(11)', 
    2428    'PhoneNumberField':             'VARCHAR2(20)', 
    25     'PositiveIntegerField':         'NUMBER(11) CHECK (%(column)s >= 0)', 
    26     'PositiveSmallIntegerField':    'NUMBER(11) CHECK (%(column)s >= 0)', 
     29    'PositiveIntegerField':         'NUMBER(11) CHECK (%(qn_column)s >= 0)', 
     30    'PositiveSmallIntegerField':    'NUMBER(11) CHECK (%(qn_column)s >= 0)', 
    2731    'SlugField':                    'NVARCHAR2(50)', 
    2832    'SmallIntegerField':            'NUMBER(11)', 
  • django/trunk/django/db/models/fields/__init__.py

    r7643 r7743  
    1717from django import newforms as forms 
    1818from django.core.exceptions import ObjectDoesNotExist 
     19from django.utils.datastructures import DictWrapper 
    1920from django.utils.functional import curry 
    2021from django.utils.itercompat import tee 
     
    162163        # can implement db_type() instead of get_internal_type() to specify 
    163164        # exactly which wacky database column type you want to use. 
     165        data = DictWrapper(self.__dict__, connection.ops.quote_name, "qn_") 
    164166        try: 
    165             return get_creation_module().DATA_TYPES[self.get_internal_type()] % self.__dict__ 
     167            return get_creation_module().DATA_TYPES[self.get_internal_type()] % data 
    166168        except KeyError: 
    167169            return None 
  • django/trunk/django/utils/datastructures.py

    r7140 r7743  
    344344            return dict.__repr__(d) 
    345345        return dict.__repr__(self) 
     346 
     347class DictWrapper(dict): 
     348    """ 
     349    Wraps accesses to a dictionary so that certain values (those starting with 
     350    the specified prefix) are passed through a function before being returned. 
     351    The prefix is removed before looking up the real value. 
     352 
     353    Used by the SQL construction code to ensure that values are correctly 
     354    quoted before being used. 
     355    """ 
     356    def __init__(self, data, func, prefix): 
     357        super(DictWrapper, self).__init__(data) 
     358        self.func = func 
     359        self.prefix = prefix 
     360 
     361    def __getitem__(self, key): 
     362        """ 
     363        Retrieves the real value after stripping the prefix string (if 
     364        present). If the prefix is present, pass the value through self.func 
     365        before returning, otherwise return the raw value. 
     366        """ 
     367        if key.startswith(self.prefix): 
     368            use_func = True 
     369            key = key[len(self.prefix):] 
     370        else: 
     371            use_func = False 
     372        value = super(DictWrapper, self).__getitem__(key) 
     373        if use_func: 
     374            return self.func(value) 
     375        return value 
     376 
  • django/trunk/tests/regressiontests/queries/models.py

    r7741 r7743  
    123123    def get_query_set(self): 
    124124        qs = super(CustomManager, self).get_query_set() 
    125         return qs.filter(is_public=True, tag__name='t1') 
     125        return qs.filter(public=True, tag__name='t1') 
    126126 
    127127class ManagedModel(models.Model): 
    128128    data = models.CharField(max_length=10) 
    129129    tag = models.ForeignKey(Tag) 
    130     is_public = models.BooleanField(default=True) 
     130    public = models.BooleanField(default=True) 
    131131 
    132132    objects = CustomManager() 
     
    731731Updates that are filtered on the model being updated are somewhat tricky to get 
    732732in MySQL. This exercises that case. 
    733 >>> mm = ManagedModel.objects.create(data='mm1', tag=t1, is_public=True) 
     733>>> mm = ManagedModel.objects.create(data='mm1', tag=t1, public=True) 
    734734>>> ManagedModel.objects.update(data='mm') 
    735735