mirror of https://github.com/django/django.git
Refactored meta.py -- created a django.core.meta package, with init.py and fields.py
git-svn-id: http://code.djangoproject.com/svn/django/trunk@378 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
006e9e789b
commit
e0c3dd3318
|
@ -264,7 +264,7 @@ database_check.args = APP_ARGS
|
||||||
|
|
||||||
def get_admin_index(mod):
|
def get_admin_index(mod):
|
||||||
"Returns admin-index template snippet (in list form) for the given module."
|
"Returns admin-index template snippet (in list form) for the given module."
|
||||||
from django.core import meta
|
from django.utils.text import capfirst
|
||||||
output = []
|
output = []
|
||||||
app_label = mod._MODELS[0]._meta.app_label
|
app_label = mod._MODELS[0]._meta.app_label
|
||||||
output.append('{%% if perms.%s %%}' % app_label)
|
output.append('{%% if perms.%s %%}' % app_label)
|
||||||
|
@ -274,7 +274,7 @@ def get_admin_index(mod):
|
||||||
output.append(MODULE_TEMPLATE % {
|
output.append(MODULE_TEMPLATE % {
|
||||||
'app': app_label,
|
'app': app_label,
|
||||||
'mod': klass._meta.module_name,
|
'mod': klass._meta.module_name,
|
||||||
'name': meta.capfirst(klass._meta.verbose_name_plural),
|
'name': capfirst(klass._meta.verbose_name_plural),
|
||||||
'addperm': klass._meta.get_add_permission(),
|
'addperm': klass._meta.get_add_permission(),
|
||||||
'changeperm': klass._meta.get_change_permission(),
|
'changeperm': klass._meta.get_change_permission(),
|
||||||
})
|
})
|
||||||
|
|
|
@ -1,30 +1,20 @@
|
||||||
|
from django.conf import settings
|
||||||
from django.core import formfields, validators
|
from django.core import formfields, validators
|
||||||
from django.core import db
|
from django.core import db
|
||||||
from django.core.exceptions import ObjectDoesNotExist
|
from django.core.exceptions import ObjectDoesNotExist
|
||||||
from django.conf import settings
|
from django.core.meta.fields import *
|
||||||
|
from django.utils.functional import curry
|
||||||
|
from django.utils.text import capfirst
|
||||||
import copy, datetime, os, re, sys, types
|
import copy, datetime, os, re, sys, types
|
||||||
|
|
||||||
# The values to use for "blank" in SelectFields. Will be appended to the start of most "choices" lists.
|
|
||||||
BLANK_CHOICE_DASH = [("", "---------")]
|
|
||||||
BLANK_CHOICE_NONE = [("", "None")]
|
|
||||||
|
|
||||||
# Admin stages.
|
# Admin stages.
|
||||||
ADD, CHANGE, BOTH = 1, 2, 3
|
ADD, CHANGE, BOTH = 1, 2, 3
|
||||||
|
|
||||||
# Values for Relation.edit_inline_type.
|
|
||||||
TABULAR, STACKED = 1, 2
|
|
||||||
|
|
||||||
# Values for filter_interface.
|
|
||||||
HORIZONTAL, VERTICAL = 1, 2
|
|
||||||
|
|
||||||
# Random entropy string used by "default" param.
|
|
||||||
NOT_PROVIDED = 'oijpwojefiojpanv'
|
|
||||||
|
|
||||||
# Size of each "chunk" for get_iterator calls.
|
# Size of each "chunk" for get_iterator calls.
|
||||||
# Larger values are slightly faster at the expense of more storage space.
|
# Larger values are slightly faster at the expense of more storage space.
|
||||||
GET_ITERATOR_CHUNK_SIZE = 100
|
GET_ITERATOR_CHUNK_SIZE = 100
|
||||||
|
|
||||||
# Prefix (in python path style) to location of models.
|
# Prefix (in Python path style) to location of models.
|
||||||
MODEL_PREFIX = 'django.models'
|
MODEL_PREFIX = 'django.models'
|
||||||
|
|
||||||
# Methods on models with the following prefix will be removed and
|
# Methods on models with the following prefix will be removed and
|
||||||
|
@ -37,21 +27,10 @@ MANIPULATOR_FUNCTIONS_PREFIX = '_manipulator_'
|
||||||
|
|
||||||
LOOKUP_SEPARATOR = '__'
|
LOOKUP_SEPARATOR = '__'
|
||||||
|
|
||||||
RECURSIVE_RELATIONSHIP_CONSTANT = 'self'
|
|
||||||
|
|
||||||
####################
|
####################
|
||||||
# HELPER FUNCTIONS #
|
# HELPER FUNCTIONS #
|
||||||
####################
|
####################
|
||||||
|
|
||||||
# capitalizes first letter of string
|
|
||||||
capfirst = lambda x: x and x[0].upper() + x[1:]
|
|
||||||
|
|
||||||
# prepares a value for use in a LIKE query
|
|
||||||
prep_for_like_query = lambda x: str(x).replace("%", "\%").replace("_", "\_")
|
|
||||||
|
|
||||||
# returns the <ul> class for a given radio_admin value
|
|
||||||
get_ul_class = lambda x: 'radiolist%s' % ((x == HORIZONTAL) and ' inline' or '')
|
|
||||||
|
|
||||||
# Django currently supports two forms of ordering.
|
# Django currently supports two forms of ordering.
|
||||||
# Form 1 (deprecated) example:
|
# Form 1 (deprecated) example:
|
||||||
# order_by=(('pub_date', 'DESC'), ('headline', 'ASC'), (None, 'RANDOM'))
|
# order_by=(('pub_date', 'DESC'), ('headline', 'ASC'), (None, 'RANDOM'))
|
||||||
|
@ -82,11 +61,6 @@ def orderlist2sql(order_list, prefix=''):
|
||||||
output.append('%s%s ASC' % (prefix, f))
|
output.append('%s%s ASC' % (prefix, f))
|
||||||
return ', '.join(output)
|
return ', '.join(output)
|
||||||
|
|
||||||
def curry(*args, **kwargs):
|
|
||||||
def _curried(*moreargs, **morekwargs):
|
|
||||||
return args[0](*(args[1:]+moreargs), **dict(kwargs.items() + morekwargs.items()))
|
|
||||||
return _curried
|
|
||||||
|
|
||||||
def get_module(app_label, module_name):
|
def get_module(app_label, module_name):
|
||||||
return __import__('%s.%s.%s' % (MODEL_PREFIX, app_label, module_name), '', '', [''])
|
return __import__('%s.%s.%s' % (MODEL_PREFIX, app_label, module_name), '', '', [''])
|
||||||
|
|
||||||
|
@ -1529,16 +1503,6 @@ def manipulator_save(opts, klass, add, change, self, new_data):
|
||||||
getattr(new_object, 'set_%s_order' % rel_opts.object_name.lower())(order)
|
getattr(new_object, 'set_%s_order' % rel_opts.object_name.lower())(order)
|
||||||
return new_object
|
return new_object
|
||||||
|
|
||||||
def manipulator_validator_unique(f, opts, self, field_data, all_data):
|
|
||||||
"Validates that the value is unique for this field."
|
|
||||||
try:
|
|
||||||
old_obj = opts.get_model_module().get_object(**{'%s__exact' % f.name: field_data})
|
|
||||||
except ObjectDoesNotExist:
|
|
||||||
return
|
|
||||||
if hasattr(self, 'original_object') and getattr(self.original_object, opts.pk.name) == getattr(old_obj, opts.pk.name):
|
|
||||||
return
|
|
||||||
raise validators.ValidationError, "%s with this %s already exists." % (capfirst(opts.verbose_name), f.verbose_name)
|
|
||||||
|
|
||||||
def manipulator_validator_unique_together(field_name_list, opts, self, field_data, all_data):
|
def manipulator_validator_unique_together(field_name_list, opts, self, field_data, all_data):
|
||||||
from django.utils.text import get_text_list
|
from django.utils.text import get_text_list
|
||||||
field_list = [opts.get_field(field_name) for field_name in field_name_list]
|
field_list = [opts.get_field(field_name) for field_name in field_name_list]
|
||||||
|
@ -1583,641 +1547,3 @@ def manipulator_validator_unique_for_date(from_field, date_field, opts, lookup_t
|
||||||
format_string = (lookup_type == 'date') and '%B %d, %Y' or '%B %Y'
|
format_string = (lookup_type == 'date') and '%B %d, %Y' or '%B %Y'
|
||||||
raise validators.ValidationError, "Please enter a different %s. The one you entered is already being used for %s." % \
|
raise validators.ValidationError, "Please enter a different %s. The one you entered is already being used for %s." % \
|
||||||
(from_field.verbose_name, date_val.strftime(format_string))
|
(from_field.verbose_name, date_val.strftime(format_string))
|
||||||
|
|
||||||
def manipulator_valid_rel_key(f, self, field_data, all_data):
|
|
||||||
"Validates that the value is a valid foreign key"
|
|
||||||
mod = f.rel.to.get_model_module()
|
|
||||||
try:
|
|
||||||
mod.get_object(**{'id__iexact': field_data})
|
|
||||||
except ObjectDoesNotExist:
|
|
||||||
raise validators.ValidationError, "Please enter a valid %s." % f.verbose_name
|
|
||||||
|
|
||||||
####################
|
|
||||||
# FIELDS #
|
|
||||||
####################
|
|
||||||
|
|
||||||
class Field(object):
|
|
||||||
|
|
||||||
# Designates whether empty strings fundamentally are allowed at the
|
|
||||||
# database level.
|
|
||||||
empty_strings_allowed = True
|
|
||||||
|
|
||||||
def __init__(self, name, verbose_name=None, primary_key=False,
|
|
||||||
maxlength=None, unique=False, blank=False, null=False, db_index=None,
|
|
||||||
core=False, rel=None, default=NOT_PROVIDED, editable=True,
|
|
||||||
prepopulate_from=None, unique_for_date=None, unique_for_month=None,
|
|
||||||
unique_for_year=None, validator_list=None, choices=None, radio_admin=None,
|
|
||||||
help_text=''):
|
|
||||||
self.name = name
|
|
||||||
self.verbose_name = verbose_name or name.replace('_', ' ')
|
|
||||||
self.primary_key = primary_key
|
|
||||||
self.maxlength, self.unique = maxlength, unique
|
|
||||||
self.blank, self.null = blank, null
|
|
||||||
self.core, self.rel, self.default = core, rel, default
|
|
||||||
self.editable = editable
|
|
||||||
self.validator_list = validator_list or []
|
|
||||||
self.prepopulate_from = prepopulate_from
|
|
||||||
self.unique_for_date, self.unique_for_month = unique_for_date, unique_for_month
|
|
||||||
self.unique_for_year = unique_for_year
|
|
||||||
self.choices = choices or []
|
|
||||||
self.radio_admin = radio_admin
|
|
||||||
self.help_text = help_text
|
|
||||||
if rel and isinstance(rel, ManyToMany):
|
|
||||||
self.help_text += ' Hold down "Control", or "Command" on a Mac, to select more than one.'
|
|
||||||
|
|
||||||
# Set db_index to True if the field has a relationship and doesn't explicitly set db_index.
|
|
||||||
if db_index is None:
|
|
||||||
if isinstance(rel, OneToOne) or isinstance(rel, ManyToOne):
|
|
||||||
self.db_index = True
|
|
||||||
else:
|
|
||||||
self.db_index = False
|
|
||||||
else:
|
|
||||||
self.db_index = db_index
|
|
||||||
|
|
||||||
def pre_save(self, obj, value, add):
|
|
||||||
"""
|
|
||||||
Hook for altering the object obj based on the value of this field and
|
|
||||||
and on the add/change status.
|
|
||||||
"""
|
|
||||||
pass
|
|
||||||
|
|
||||||
def get_db_prep_save(self, value, add):
|
|
||||||
"Returns field's value prepared for saving into a database."
|
|
||||||
return value
|
|
||||||
|
|
||||||
def get_db_prep_lookup(self, lookup_type, value):
|
|
||||||
"Returns field's value prepared for database lookup."
|
|
||||||
if lookup_type in ('exact', 'gt', 'gte', 'lt', 'lte', 'ne', 'month', 'day'):
|
|
||||||
return [value]
|
|
||||||
elif lookup_type in ('range', 'in'):
|
|
||||||
return value
|
|
||||||
elif lookup_type == 'year':
|
|
||||||
return ['%s-01-01' % value, '%s-12-31' % value]
|
|
||||||
elif lookup_type in ('contains', 'icontains'):
|
|
||||||
return ["%%%s%%" % prep_for_like_query(value)]
|
|
||||||
elif lookup_type == 'iexact':
|
|
||||||
return [prep_for_like_query(value)]
|
|
||||||
elif lookup_type in ('startswith', 'istartswith'):
|
|
||||||
return ["%s%%" % prep_for_like_query(value)]
|
|
||||||
elif lookup_type in ('endswith', 'iendswith'):
|
|
||||||
return ["%%%s" % prep_for_like_query(value)]
|
|
||||||
elif lookup_type == 'isnull':
|
|
||||||
return []
|
|
||||||
raise TypeError, "Field has invalid lookup: %s" % lookup_type
|
|
||||||
|
|
||||||
def has_default(self):
|
|
||||||
"Returns a boolean of whether this field has a default value."
|
|
||||||
return self.default != NOT_PROVIDED
|
|
||||||
|
|
||||||
def get_default(self):
|
|
||||||
"Returns the default value for this field."
|
|
||||||
if self.default != NOT_PROVIDED:
|
|
||||||
if hasattr(self.default, '__get_value__'):
|
|
||||||
return self.default.__get_value__()
|
|
||||||
return self.default
|
|
||||||
if self.null:
|
|
||||||
return None
|
|
||||||
return ""
|
|
||||||
|
|
||||||
def get_manipulator_field_names(self, name_prefix):
|
|
||||||
"""
|
|
||||||
Returns a list of field names that this object adds to the manipulator.
|
|
||||||
"""
|
|
||||||
return [name_prefix + self.name]
|
|
||||||
|
|
||||||
def get_manipulator_fields(self, opts, manipulator, change, name_prefix='', rel=False):
|
|
||||||
"""
|
|
||||||
Returns a list of formfields.FormField instances for this field. It
|
|
||||||
calculates the choices at runtime, not at compile time.
|
|
||||||
|
|
||||||
name_prefix is a prefix to prepend to the "field_name" argument.
|
|
||||||
rel is a boolean specifying whether this field is in a related context.
|
|
||||||
"""
|
|
||||||
params = {'validator_list': self.validator_list[:]}
|
|
||||||
if self.maxlength and not self.choices: # Don't give SelectFields a maxlength parameter.
|
|
||||||
params['maxlength'] = self.maxlength
|
|
||||||
if isinstance(self.rel, ManyToOne):
|
|
||||||
if self.rel.raw_id_admin:
|
|
||||||
field_objs = self.get_manipulator_field_objs()
|
|
||||||
params['validator_list'].append(curry(manipulator_valid_rel_key, self, manipulator))
|
|
||||||
else:
|
|
||||||
if self.radio_admin:
|
|
||||||
field_objs = [formfields.RadioSelectField]
|
|
||||||
params['choices'] = self.get_choices(include_blank=self.blank, blank_choice=BLANK_CHOICE_NONE)
|
|
||||||
params['ul_class'] = get_ul_class(self.radio_admin)
|
|
||||||
else:
|
|
||||||
if self.null:
|
|
||||||
field_objs = [formfields.NullSelectField]
|
|
||||||
else:
|
|
||||||
field_objs = [formfields.SelectField]
|
|
||||||
params['choices'] = self.get_choices()
|
|
||||||
elif self.choices:
|
|
||||||
if self.radio_admin:
|
|
||||||
field_objs = [formfields.RadioSelectField]
|
|
||||||
params['choices'] = self.get_choices(include_blank=self.blank, blank_choice=BLANK_CHOICE_NONE)
|
|
||||||
params['ul_class'] = get_ul_class(self.radio_admin)
|
|
||||||
else:
|
|
||||||
field_objs = [formfields.SelectField]
|
|
||||||
params['choices'] = self.get_choices()
|
|
||||||
else:
|
|
||||||
field_objs = self.get_manipulator_field_objs()
|
|
||||||
|
|
||||||
# Add the "unique" validator(s).
|
|
||||||
for field_name_list in opts.unique_together:
|
|
||||||
if field_name_list[0] == self.name:
|
|
||||||
params['validator_list'].append(getattr(manipulator, 'isUnique%s' % '_'.join(field_name_list)))
|
|
||||||
|
|
||||||
# Add the "unique for..." validator(s).
|
|
||||||
if self.unique_for_date:
|
|
||||||
params['validator_list'].append(getattr(manipulator, 'isUnique%sFor%s' % (self.name, self.unique_for_date)))
|
|
||||||
if self.unique_for_month:
|
|
||||||
params['validator_list'].append(getattr(manipulator, 'isUnique%sFor%s' % (self.name, self.unique_for_month)))
|
|
||||||
if self.unique_for_year:
|
|
||||||
params['validator_list'].append(getattr(manipulator, 'isUnique%sFor%s' % (self.name, self.unique_for_year)))
|
|
||||||
if self.unique:
|
|
||||||
params['validator_list'].append(curry(manipulator_validator_unique, self, opts, manipulator))
|
|
||||||
|
|
||||||
# Only add is_required=True if the field cannot be blank. Primary keys
|
|
||||||
# are a special case, and fields in a related context should set this
|
|
||||||
# as False, because they'll be caught by a separate validator --
|
|
||||||
# RequiredIfOtherFieldGiven.
|
|
||||||
params['is_required'] = not self.blank and not self.primary_key and not rel
|
|
||||||
|
|
||||||
# If this field is in a related context, check whether any other fields
|
|
||||||
# in the related object have core=True. If so, add a validator --
|
|
||||||
# RequiredIfOtherFieldsGiven -- to this FormField.
|
|
||||||
if rel and not self.blank and not isinstance(self, AutoField) and not isinstance(self, FileField):
|
|
||||||
# First, get the core fields, if any.
|
|
||||||
core_field_names = []
|
|
||||||
for f in opts.fields:
|
|
||||||
if f.core and f != self:
|
|
||||||
core_field_names.extend(f.get_manipulator_field_names(name_prefix))
|
|
||||||
# Now, if there are any, add the validator to this FormField.
|
|
||||||
if core_field_names:
|
|
||||||
params['validator_list'].append(validators.RequiredIfOtherFieldsGiven(core_field_names, "This field is required."))
|
|
||||||
|
|
||||||
# BooleanFields (CheckboxFields) are a special case. They don't take
|
|
||||||
# is_required or validator_list.
|
|
||||||
if isinstance(self, BooleanField):
|
|
||||||
del params['validator_list'], params['is_required']
|
|
||||||
|
|
||||||
# Finally, add the field_names.
|
|
||||||
field_names = self.get_manipulator_field_names(name_prefix)
|
|
||||||
return [man(field_name=field_names[i], **params) for i, man in enumerate(field_objs)]
|
|
||||||
|
|
||||||
def get_manipulator_new_data(self, new_data, rel=False):
|
|
||||||
"""
|
|
||||||
Given the full new_data dictionary (from the manipulator), returns this
|
|
||||||
field's data.
|
|
||||||
"""
|
|
||||||
if rel:
|
|
||||||
return new_data.get(self.name, [self.get_default()])[0]
|
|
||||||
else:
|
|
||||||
val = new_data.get(self.name, self.get_default())
|
|
||||||
if not self.empty_strings_allowed and val == '' and self.null:
|
|
||||||
val = None
|
|
||||||
return val
|
|
||||||
|
|
||||||
def get_choices(self, include_blank=True, blank_choice=BLANK_CHOICE_DASH):
|
|
||||||
"Returns a list of tuples used as SelectField choices for this field."
|
|
||||||
first_choice = include_blank and blank_choice or []
|
|
||||||
if self.choices:
|
|
||||||
return first_choice + list(self.choices)
|
|
||||||
rel_obj = self.rel.to
|
|
||||||
return first_choice + [(getattr(x, rel_obj.pk.name), repr(x)) for x in rel_obj.get_model_module().get_list(**self.rel.limit_choices_to)]
|
|
||||||
|
|
||||||
class AutoField(Field):
|
|
||||||
empty_strings_allowed = False
|
|
||||||
def get_manipulator_fields(self, opts, manipulator, change, name_prefix='', rel=False):
|
|
||||||
if not rel:
|
|
||||||
return [] # Don't add a FormField unless it's in a related context.
|
|
||||||
return Field.get_manipulator_fields(self, opts, manipulator, change, name_prefix, rel)
|
|
||||||
|
|
||||||
def get_manipulator_field_objs(self):
|
|
||||||
return [formfields.HiddenField]
|
|
||||||
|
|
||||||
def get_manipulator_new_data(self, new_data, rel=False):
|
|
||||||
if not rel:
|
|
||||||
return None
|
|
||||||
return Field.get_manipulator_new_data(self, new_data, rel)
|
|
||||||
|
|
||||||
class BooleanField(Field):
|
|
||||||
def __init__(self, *args, **kwargs):
|
|
||||||
kwargs['blank'] = True
|
|
||||||
Field.__init__(self, *args, **kwargs)
|
|
||||||
|
|
||||||
def get_manipulator_field_objs(self):
|
|
||||||
return [formfields.CheckboxField]
|
|
||||||
|
|
||||||
class CharField(Field):
|
|
||||||
def get_manipulator_field_objs(self):
|
|
||||||
return [formfields.TextField]
|
|
||||||
|
|
||||||
class CommaSeparatedIntegerField(CharField):
|
|
||||||
def get_manipulator_field_objs(self):
|
|
||||||
return [formfields.CommaSeparatedIntegerField]
|
|
||||||
|
|
||||||
class DateField(Field):
|
|
||||||
empty_strings_allowed = False
|
|
||||||
def __init__(self, name, verbose_name=None, auto_now=False, auto_now_add=False, **kwargs):
|
|
||||||
self.auto_now, self.auto_now_add = auto_now, auto_now_add
|
|
||||||
if auto_now or auto_now_add:
|
|
||||||
kwargs['editable'] = False
|
|
||||||
Field.__init__(self, name, verbose_name, **kwargs)
|
|
||||||
|
|
||||||
def get_db_prep_lookup(self, lookup_type, value):
|
|
||||||
if lookup_type == 'range':
|
|
||||||
value = [str(v) for v in value]
|
|
||||||
else:
|
|
||||||
value = str(value)
|
|
||||||
return Field.get_db_prep_lookup(self, lookup_type, value)
|
|
||||||
|
|
||||||
def pre_save(self, obj, value, add):
|
|
||||||
if self.auto_now or (self.auto_now_add and add):
|
|
||||||
setattr(obj, self.name, datetime.datetime.now())
|
|
||||||
|
|
||||||
def get_db_prep_save(self, value, add):
|
|
||||||
# Casts dates into string format for entry into database.
|
|
||||||
if value is not None:
|
|
||||||
value = value.strftime('%Y-%m-%d')
|
|
||||||
return Field.get_db_prep_save(self, value, add)
|
|
||||||
|
|
||||||
def get_manipulator_field_objs(self):
|
|
||||||
return [formfields.DateField]
|
|
||||||
|
|
||||||
class DateTimeField(DateField):
|
|
||||||
def get_db_prep_save(self, value, add):
|
|
||||||
# Casts dates into string format for entry into database.
|
|
||||||
if value is not None:
|
|
||||||
value = value.strftime('%Y-%m-%d %H:%M:%S')
|
|
||||||
return Field.get_db_prep_save(self, value, add)
|
|
||||||
|
|
||||||
def get_manipulator_field_objs(self):
|
|
||||||
return [formfields.DateField, formfields.TimeField]
|
|
||||||
|
|
||||||
def get_manipulator_field_names(self, name_prefix):
|
|
||||||
return [name_prefix + self.name + '_date', name_prefix + self.name + '_time']
|
|
||||||
|
|
||||||
def get_manipulator_new_data(self, new_data, rel=False):
|
|
||||||
date_field, time_field = self.get_manipulator_field_names('')
|
|
||||||
if rel:
|
|
||||||
d = new_data.get(date_field, [None])[0]
|
|
||||||
t = new_data.get(time_field, [None])[0]
|
|
||||||
else:
|
|
||||||
d = new_data.get(date_field, None)
|
|
||||||
t = new_data.get(time_field, None)
|
|
||||||
if d is not None and t is not None:
|
|
||||||
return datetime.datetime.combine(d, t)
|
|
||||||
return self.get_default()
|
|
||||||
|
|
||||||
class EmailField(Field):
|
|
||||||
def get_manipulator_field_objs(self):
|
|
||||||
return [formfields.EmailField]
|
|
||||||
|
|
||||||
class FileField(Field):
|
|
||||||
def __init__(self, name, verbose_name=None, upload_to='', **kwargs):
|
|
||||||
self.upload_to = upload_to
|
|
||||||
Field.__init__(self, name, verbose_name, **kwargs)
|
|
||||||
|
|
||||||
def get_manipulator_fields(self, opts, manipulator, change, name_prefix='', rel=False):
|
|
||||||
field_list = Field.get_manipulator_fields(self, opts, manipulator, change, name_prefix, rel)
|
|
||||||
|
|
||||||
if not self.blank:
|
|
||||||
if rel:
|
|
||||||
# This validator makes sure FileFields work in a related context.
|
|
||||||
class RequiredFileField:
|
|
||||||
def __init__(self, other_field_names, other_file_field_name):
|
|
||||||
self.other_field_names = other_field_names
|
|
||||||
self.other_file_field_name = other_file_field_name
|
|
||||||
self.always_test = True
|
|
||||||
def __call__(self, field_data, all_data):
|
|
||||||
if not all_data.get(self.other_file_field_name, False):
|
|
||||||
c = validators.RequiredIfOtherFieldsGiven(self.other_field_names, "This field is required.")
|
|
||||||
c(field_data, all_data)
|
|
||||||
# First, get the core fields, if any.
|
|
||||||
core_field_names = []
|
|
||||||
for f in opts.fields:
|
|
||||||
if f.core and f != self:
|
|
||||||
core_field_names.extend(f.get_manipulator_field_names(name_prefix))
|
|
||||||
# Now, if there are any, add the validator to this FormField.
|
|
||||||
if core_field_names:
|
|
||||||
field_list[0].validator_list.append(RequiredFileField(core_field_names, field_list[1].field_name))
|
|
||||||
else:
|
|
||||||
v = validators.RequiredIfOtherFieldNotGiven(field_list[1].field_name, "This field is required.")
|
|
||||||
v.always_test = True
|
|
||||||
field_list[0].validator_list.append(v)
|
|
||||||
field_list[0].is_required = field_list[1].is_required = False
|
|
||||||
|
|
||||||
# If the raw path is passed in, validate it's under the MEDIA_ROOT.
|
|
||||||
def isWithinMediaRoot(field_data, all_data):
|
|
||||||
f = os.path.abspath(os.path.join(settings.MEDIA_ROOT, field_data))
|
|
||||||
if not f.startswith(os.path.normpath(settings.MEDIA_ROOT)):
|
|
||||||
raise validators.ValidationError, "Enter a valid filename."
|
|
||||||
field_list[1].validator_list.append(isWithinMediaRoot)
|
|
||||||
return field_list
|
|
||||||
|
|
||||||
def get_manipulator_field_objs(self):
|
|
||||||
return [formfields.FileUploadField, formfields.HiddenField]
|
|
||||||
|
|
||||||
def get_manipulator_field_names(self, name_prefix):
|
|
||||||
return [name_prefix + self.name + '_file', name_prefix + self.name]
|
|
||||||
|
|
||||||
def save_file(self, new_data, new_object, original_object, change, rel):
|
|
||||||
upload_field_name = self.get_manipulator_field_names('')[0]
|
|
||||||
if new_data.get(upload_field_name, False):
|
|
||||||
if rel:
|
|
||||||
getattr(new_object, 'save_%s_file' % self.name)(new_data[upload_field_name][0]["filename"], new_data[upload_field_name][0]["content"])
|
|
||||||
else:
|
|
||||||
getattr(new_object, 'save_%s_file' % self.name)(new_data[upload_field_name]["filename"], new_data[upload_field_name]["content"])
|
|
||||||
|
|
||||||
def get_directory_name(self):
|
|
||||||
return os.path.normpath(datetime.datetime.now().strftime(self.upload_to))
|
|
||||||
|
|
||||||
def get_filename(self, filename):
|
|
||||||
from django.utils.text import get_valid_filename
|
|
||||||
f = os.path.join(self.get_directory_name(), get_valid_filename(os.path.basename(filename)))
|
|
||||||
return os.path.normpath(f)
|
|
||||||
|
|
||||||
class FloatField(Field):
|
|
||||||
empty_strings_allowed = False
|
|
||||||
def __init__(self, name, verbose_name=None, max_digits=None, decimal_places=None, **kwargs):
|
|
||||||
self.max_digits, self.decimal_places = max_digits, decimal_places
|
|
||||||
Field.__init__(self, name, verbose_name, **kwargs)
|
|
||||||
|
|
||||||
def get_manipulator_field_objs(self):
|
|
||||||
return [curry(formfields.FloatField, max_digits=self.max_digits, decimal_places=self.decimal_places)]
|
|
||||||
|
|
||||||
class ImageField(FileField):
|
|
||||||
def __init__(self, name, verbose_name=None, width_field=None, height_field=None, **kwargs):
|
|
||||||
self.width_field, self.height_field = width_field, height_field
|
|
||||||
FileField.__init__(self, name, verbose_name, **kwargs)
|
|
||||||
|
|
||||||
def get_manipulator_field_objs(self):
|
|
||||||
return [formfields.ImageUploadField, formfields.HiddenField]
|
|
||||||
|
|
||||||
def save_file(self, new_data, new_object, original_object, change, rel):
|
|
||||||
FileField.save_file(self, new_data, new_object, original_object, change, rel)
|
|
||||||
# If the image has height and/or width field(s) and they haven't
|
|
||||||
# changed, set the width and/or height field(s) back to their original
|
|
||||||
# values.
|
|
||||||
if change and (self.width_field or self.height_field):
|
|
||||||
if self.width_field:
|
|
||||||
setattr(new_object, self.width_field, getattr(original_object, self.width_field))
|
|
||||||
if self.height_field:
|
|
||||||
setattr(new_object, self.height_field, getattr(original_object, self.height_field))
|
|
||||||
new_object.save()
|
|
||||||
|
|
||||||
class IntegerField(Field):
|
|
||||||
empty_strings_allowed = False
|
|
||||||
def get_manipulator_field_objs(self):
|
|
||||||
return [formfields.IntegerField]
|
|
||||||
|
|
||||||
class IPAddressField(Field):
|
|
||||||
def __init__(self, *args, **kwargs):
|
|
||||||
kwargs['maxlength'] = 15
|
|
||||||
Field.__init__(self, *args, **kwargs)
|
|
||||||
|
|
||||||
def get_manipulator_field_objs(self):
|
|
||||||
return [formfields.IPAddressField]
|
|
||||||
|
|
||||||
class NullBooleanField(Field):
|
|
||||||
def __init__(self, *args, **kwargs):
|
|
||||||
kwargs['null'] = True
|
|
||||||
Field.__init__(self, *args, **kwargs)
|
|
||||||
|
|
||||||
def get_manipulator_field_objs(self):
|
|
||||||
return [formfields.NullBooleanField]
|
|
||||||
|
|
||||||
class PhoneNumberField(IntegerField):
|
|
||||||
def get_manipulator_field_objs(self):
|
|
||||||
return [formfields.PhoneNumberField]
|
|
||||||
|
|
||||||
class PositiveIntegerField(IntegerField):
|
|
||||||
def get_manipulator_field_objs(self):
|
|
||||||
return [formfields.PositiveIntegerField]
|
|
||||||
|
|
||||||
class PositiveSmallIntegerField(IntegerField):
|
|
||||||
def get_manipulator_field_objs(self):
|
|
||||||
return [formfields.PositiveSmallIntegerField]
|
|
||||||
|
|
||||||
class SlugField(Field):
|
|
||||||
def __init__(self, *args, **kwargs):
|
|
||||||
kwargs['maxlength'] = 50
|
|
||||||
kwargs.setdefault('validator_list', []).append(validators.isAlphaNumeric)
|
|
||||||
# Set db_index=True unless it's been set manually.
|
|
||||||
if not kwargs.has_key('db_index'):
|
|
||||||
kwargs['db_index'] = True
|
|
||||||
Field.__init__(self, *args, **kwargs)
|
|
||||||
|
|
||||||
def get_manipulator_field_objs(self):
|
|
||||||
return [formfields.TextField]
|
|
||||||
|
|
||||||
class SmallIntegerField(IntegerField):
|
|
||||||
def get_manipulator_field_objs(self):
|
|
||||||
return [formfields.SmallIntegerField]
|
|
||||||
|
|
||||||
class TextField(Field):
|
|
||||||
def get_manipulator_field_objs(self):
|
|
||||||
return [formfields.LargeTextField]
|
|
||||||
|
|
||||||
class TimeField(Field):
|
|
||||||
empty_strings_allowed = False
|
|
||||||
def __init__(self, name, verbose_name=None, auto_now=False, auto_now_add=False, **kwargs):
|
|
||||||
self.auto_now, self.auto_now_add = auto_now, auto_now_add
|
|
||||||
if auto_now or auto_now_add:
|
|
||||||
kwargs['editable'] = False
|
|
||||||
Field.__init__(self, name, verbose_name, **kwargs)
|
|
||||||
|
|
||||||
def get_db_prep_lookup(self, lookup_type, value):
|
|
||||||
if lookup_type == 'range':
|
|
||||||
value = [str(v) for v in value]
|
|
||||||
else:
|
|
||||||
value = str(value)
|
|
||||||
return Field.get_db_prep_lookup(self, lookup_type, value)
|
|
||||||
|
|
||||||
def pre_save(self, obj, value, add):
|
|
||||||
if self.auto_now or (self.auto_now_add and add):
|
|
||||||
setattr(obj, self.name, datetime.datetime.now().time())
|
|
||||||
|
|
||||||
def get_db_prep_save(self, value, add):
|
|
||||||
# Casts dates into string format for entry into database.
|
|
||||||
if value is not None:
|
|
||||||
value = value.strftime('%H:%M:%S')
|
|
||||||
return Field.get_db_prep_save(self, value, add)
|
|
||||||
|
|
||||||
def get_manipulator_field_objs(self):
|
|
||||||
return [formfields.TimeField]
|
|
||||||
|
|
||||||
class URLField(Field):
|
|
||||||
def __init__(self, name, verbose_name=None, verify_exists=True, **kwargs):
|
|
||||||
if verify_exists:
|
|
||||||
kwargs.setdefault('validator_list', []).append(validators.isExistingURL)
|
|
||||||
Field.__init__(self, name, verbose_name, **kwargs)
|
|
||||||
|
|
||||||
def get_manipulator_field_objs(self):
|
|
||||||
return [formfields.URLField]
|
|
||||||
|
|
||||||
class USStateField(Field):
|
|
||||||
def get_manipulator_field_objs(self):
|
|
||||||
return [formfields.USStateField]
|
|
||||||
|
|
||||||
class XMLField(Field):
|
|
||||||
def __init__(self, name, verbose_name=None, schema_path=None, **kwargs):
|
|
||||||
self.schema_path = schema_path
|
|
||||||
Field.__init__(self, name, verbose_name, **kwargs)
|
|
||||||
|
|
||||||
def get_manipulator_field_objs(self):
|
|
||||||
return [curry(formfields.XMLLargeTextField, schema_path=self.schema_path)]
|
|
||||||
|
|
||||||
class ForeignKey(Field):
|
|
||||||
empty_strings_allowed = False
|
|
||||||
def __init__(self, to, to_field=None, rel_name=None, **kwargs):
|
|
||||||
try:
|
|
||||||
to_name = to._meta.object_name.lower()
|
|
||||||
except AttributeError: # to._meta doesn't exist, so it must be RECURSIVE_RELATIONSHIP_CONSTANT
|
|
||||||
assert to == 'self', "ForeignKey(%r) is invalid. First parameter to ForeignKey must be either a model or the string %r" % (to, RECURSIVE_RELATIONSHIP_CONSTANT)
|
|
||||||
kwargs['name'] = kwargs.get('name', '')
|
|
||||||
kwargs['verbose_name'] = kwargs.get('verbose_name', '')
|
|
||||||
else:
|
|
||||||
to_field = to_field or to._meta.pk.name
|
|
||||||
kwargs['name'] = kwargs.get('name', to_name + '_id')
|
|
||||||
kwargs['verbose_name'] = kwargs.get('verbose_name', to._meta.verbose_name)
|
|
||||||
rel_name = rel_name or to_name
|
|
||||||
kwargs['rel'] = ManyToOne(to, rel_name, to_field,
|
|
||||||
num_in_admin=kwargs.pop('num_in_admin', 0),
|
|
||||||
min_num_in_admin=kwargs.pop('min_num_in_admin', None),
|
|
||||||
max_num_in_admin=kwargs.pop('max_num_in_admin', None),
|
|
||||||
num_extra_on_change=kwargs.pop('num_extra_on_change', 1),
|
|
||||||
edit_inline=kwargs.pop('edit_inline', False),
|
|
||||||
edit_inline_type=kwargs.pop('edit_inline_type', STACKED),
|
|
||||||
related_name=kwargs.pop('related_name', None),
|
|
||||||
limit_choices_to=kwargs.pop('limit_choices_to', None),
|
|
||||||
lookup_overrides=kwargs.pop('lookup_overrides', None),
|
|
||||||
raw_id_admin=kwargs.pop('raw_id_admin', False))
|
|
||||||
Field.__init__(self, **kwargs)
|
|
||||||
|
|
||||||
def get_manipulator_field_objs(self):
|
|
||||||
return [formfields.IntegerField]
|
|
||||||
|
|
||||||
class ManyToManyField(Field):
|
|
||||||
def __init__(self, to, rel_name=None, **kwargs):
|
|
||||||
kwargs['name'] = kwargs.get('name', to._meta.module_name)
|
|
||||||
kwargs['verbose_name'] = kwargs.get('verbose_name', to._meta.verbose_name_plural)
|
|
||||||
rel_name = rel_name or to._meta.object_name.lower()
|
|
||||||
kwargs['rel'] = ManyToMany(to, rel_name,
|
|
||||||
num_in_admin=kwargs.pop('num_in_admin', 0),
|
|
||||||
related_name=kwargs.pop('related_name', None),
|
|
||||||
filter_interface=kwargs.pop('filter_interface', None),
|
|
||||||
limit_choices_to=kwargs.pop('limit_choices_to', None))
|
|
||||||
Field.__init__(self, **kwargs)
|
|
||||||
|
|
||||||
def get_manipulator_field_objs(self):
|
|
||||||
choices = self.get_choices(include_blank=False)
|
|
||||||
return [curry(formfields.SelectMultipleField, size=min(max(len(choices), 5), 15), choices=choices)]
|
|
||||||
|
|
||||||
def get_m2m_db_table(self, original_opts):
|
|
||||||
"Returns the name of the many-to-many 'join' table."
|
|
||||||
return '%s_%s' % (original_opts.db_table, self.name)
|
|
||||||
|
|
||||||
class OneToOneField(IntegerField):
|
|
||||||
def __init__(self, to, to_field=None, rel_name=None, **kwargs):
|
|
||||||
kwargs['name'] = kwargs.get('name', 'id')
|
|
||||||
kwargs['verbose_name'] = kwargs.get('verbose_name', 'ID')
|
|
||||||
to_field = to_field or to._meta.pk.name
|
|
||||||
rel_name = rel_name or to._meta.object_name.lower()
|
|
||||||
kwargs['rel'] = OneToOne(to, rel_name, to_field,
|
|
||||||
num_in_admin=kwargs.pop('num_in_admin', 0),
|
|
||||||
edit_inline=kwargs.pop('edit_inline', False),
|
|
||||||
edit_inline_type=kwargs.pop('edit_inline_type', STACKED),
|
|
||||||
related_name=kwargs.pop('related_name', None),
|
|
||||||
limit_choices_to=kwargs.pop('limit_choices_to', None),
|
|
||||||
lookup_overrides=kwargs.pop('lookup_overrides', None),
|
|
||||||
raw_id_admin=kwargs.pop('raw_id_admin', False))
|
|
||||||
kwargs['primary_key'] = True
|
|
||||||
IntegerField.__init__(self, **kwargs)
|
|
||||||
|
|
||||||
####################
|
|
||||||
# RELATIONSHIPS #
|
|
||||||
####################
|
|
||||||
|
|
||||||
class ManyToOne:
|
|
||||||
def __init__(self, to, name, field_name, num_in_admin=0, min_num_in_admin=None,
|
|
||||||
max_num_in_admin=None, num_extra_on_change=1, edit_inline=False, edit_inline_type=STACKED,
|
|
||||||
related_name=None, limit_choices_to=None, lookup_overrides=None, raw_id_admin=False):
|
|
||||||
try:
|
|
||||||
self.to = to._meta
|
|
||||||
except AttributeError: # to._meta doesn't exist, so it must be RECURSIVE_RELATIONSHIP_CONSTANT
|
|
||||||
assert to == RECURSIVE_RELATIONSHIP_CONSTANT, "'to' must be either a model or the string '%s'" % RECURSIVE_RELATIONSHIP_CONSTANT
|
|
||||||
self.to = to
|
|
||||||
self.name, self.field_name = name, field_name
|
|
||||||
self.num_in_admin, self.edit_inline = num_in_admin, edit_inline
|
|
||||||
self.min_num_in_admin, self.max_num_in_admin = min_num_in_admin, max_num_in_admin
|
|
||||||
self.num_extra_on_change = num_extra_on_change
|
|
||||||
self.edit_inline_type, self.related_name = edit_inline_type, related_name
|
|
||||||
self.limit_choices_to = limit_choices_to or {}
|
|
||||||
self.lookup_overrides = lookup_overrides or {}
|
|
||||||
self.raw_id_admin = raw_id_admin
|
|
||||||
|
|
||||||
def get_cache_name(self):
|
|
||||||
return '_%s_cache' % self.name
|
|
||||||
|
|
||||||
def get_related_field(self):
|
|
||||||
"Returns the Field in the 'to' object to which this relationship is tied."
|
|
||||||
return self.to.get_field(self.field_name)
|
|
||||||
|
|
||||||
class ManyToMany:
|
|
||||||
def __init__(self, to, name, num_in_admin=0, related_name=None,
|
|
||||||
filter_interface=None, limit_choices_to=None):
|
|
||||||
self.to, self.name = to._meta, name
|
|
||||||
self.num_in_admin = num_in_admin
|
|
||||||
self.related_name = related_name
|
|
||||||
self.filter_interface = filter_interface
|
|
||||||
self.limit_choices_to = limit_choices_to or {}
|
|
||||||
self.edit_inline = False
|
|
||||||
|
|
||||||
class OneToOne(ManyToOne):
|
|
||||||
def __init__(self, to, name, field_name, num_in_admin=0, edit_inline=False,
|
|
||||||
edit_inline_type=STACKED, related_name=None, limit_choices_to=None, lookup_overrides=None,
|
|
||||||
raw_id_admin=False):
|
|
||||||
self.to, self.name, self.field_name = to._meta, name, field_name
|
|
||||||
self.num_in_admin, self.edit_inline = num_in_admin, edit_inline
|
|
||||||
self.edit_inline_type, self.related_name = edit_inline_type, related_name
|
|
||||||
self.limit_choices_to = limit_choices_to or {}
|
|
||||||
self.lookup_overrides = lookup_overrides or {}
|
|
||||||
self.raw_id_admin = raw_id_admin
|
|
||||||
|
|
||||||
class Admin:
|
|
||||||
def __init__(self, fields=None, js=None, list_display=None, list_filter=None, date_hierarchy=None,
|
|
||||||
save_as=False, ordering=None, search_fields=None, save_on_top=False):
|
|
||||||
self.fields = fields
|
|
||||||
self.js = js or []
|
|
||||||
self.list_display = list_display or ['__repr__']
|
|
||||||
self.list_filter = list_filter or []
|
|
||||||
self.date_hierarchy = date_hierarchy
|
|
||||||
self.save_as, self.ordering = save_as, ordering
|
|
||||||
self.search_fields = search_fields or []
|
|
||||||
self.save_on_top = save_on_top
|
|
||||||
|
|
||||||
def get_field_objs(self, opts):
|
|
||||||
"""
|
|
||||||
Returns self.fields, except with fields as Field objects instead of
|
|
||||||
field names. If self.fields is None, defaults to putting every
|
|
||||||
non-AutoField field with editable=True in a single fieldset.
|
|
||||||
"""
|
|
||||||
if self.fields is None:
|
|
||||||
field_struct = ((None, {'fields': [f.name for f in opts.fields + opts.many_to_many if f.editable and not isinstance(f, AutoField)]}),)
|
|
||||||
else:
|
|
||||||
field_struct = self.fields
|
|
||||||
new_fieldset_list = []
|
|
||||||
for fieldset in field_struct:
|
|
||||||
new_fieldset = [fieldset[0], {}]
|
|
||||||
new_fieldset[1].update(fieldset[1])
|
|
||||||
admin_fields = []
|
|
||||||
for field_name_or_list in fieldset[1]['fields']:
|
|
||||||
if isinstance(field_name_or_list, basestring):
|
|
||||||
admin_fields.append([opts.get_field(field_name_or_list)])
|
|
||||||
else:
|
|
||||||
admin_fields.append([opts.get_field(field_name) for field_name in field_name_or_list])
|
|
||||||
new_fieldset[1]['fields'] = admin_fields
|
|
||||||
new_fieldset_list.append(new_fieldset)
|
|
||||||
return new_fieldset_list
|
|
|
@ -0,0 +1,667 @@
|
||||||
|
from django.conf import settings
|
||||||
|
from django.core import formfields, validators
|
||||||
|
from django.core.exceptions import ObjectDoesNotExist
|
||||||
|
from django.utils.functional import curry
|
||||||
|
from django.utils.text import capfirst
|
||||||
|
import datetime, os
|
||||||
|
|
||||||
|
# Random entropy string used by "default" param.
|
||||||
|
NOT_PROVIDED = 'oijpwojefiojpanv'
|
||||||
|
|
||||||
|
# Values for filter_interface.
|
||||||
|
HORIZONTAL, VERTICAL = 1, 2
|
||||||
|
|
||||||
|
# The values to use for "blank" in SelectFields. Will be appended to the start of most "choices" lists.
|
||||||
|
BLANK_CHOICE_DASH = [("", "---------")]
|
||||||
|
BLANK_CHOICE_NONE = [("", "None")]
|
||||||
|
|
||||||
|
# Values for Relation.edit_inline_type.
|
||||||
|
TABULAR, STACKED = 1, 2
|
||||||
|
|
||||||
|
RECURSIVE_RELATIONSHIP_CONSTANT = 'self'
|
||||||
|
|
||||||
|
# prepares a value for use in a LIKE query
|
||||||
|
prep_for_like_query = lambda x: str(x).replace("%", "\%").replace("_", "\_")
|
||||||
|
|
||||||
|
# returns the <ul> class for a given radio_admin value
|
||||||
|
get_ul_class = lambda x: 'radiolist%s' % ((x == HORIZONTAL) and ' inline' or '')
|
||||||
|
|
||||||
|
def manipulator_valid_rel_key(f, self, field_data, all_data):
|
||||||
|
"Validates that the value is a valid foreign key"
|
||||||
|
mod = f.rel.to.get_model_module()
|
||||||
|
try:
|
||||||
|
mod.get_object(**{'id__iexact': field_data})
|
||||||
|
except ObjectDoesNotExist:
|
||||||
|
raise validators.ValidationError, "Please enter a valid %s." % f.verbose_name
|
||||||
|
|
||||||
|
def manipulator_validator_unique(f, opts, self, field_data, all_data):
|
||||||
|
"Validates that the value is unique for this field."
|
||||||
|
try:
|
||||||
|
old_obj = opts.get_model_module().get_object(**{'%s__exact' % f.name: field_data})
|
||||||
|
except ObjectDoesNotExist:
|
||||||
|
return
|
||||||
|
if hasattr(self, 'original_object') and getattr(self.original_object, opts.pk.name) == getattr(old_obj, opts.pk.name):
|
||||||
|
return
|
||||||
|
raise validators.ValidationError, "%s with this %s already exists." % (capfirst(opts.verbose_name), f.verbose_name)
|
||||||
|
|
||||||
|
class Field(object):
|
||||||
|
|
||||||
|
# Designates whether empty strings fundamentally are allowed at the
|
||||||
|
# database level.
|
||||||
|
empty_strings_allowed = True
|
||||||
|
|
||||||
|
def __init__(self, name, verbose_name=None, primary_key=False,
|
||||||
|
maxlength=None, unique=False, blank=False, null=False, db_index=None,
|
||||||
|
core=False, rel=None, default=NOT_PROVIDED, editable=True,
|
||||||
|
prepopulate_from=None, unique_for_date=None, unique_for_month=None,
|
||||||
|
unique_for_year=None, validator_list=None, choices=None, radio_admin=None,
|
||||||
|
help_text=''):
|
||||||
|
self.name = name
|
||||||
|
self.verbose_name = verbose_name or name.replace('_', ' ')
|
||||||
|
self.primary_key = primary_key
|
||||||
|
self.maxlength, self.unique = maxlength, unique
|
||||||
|
self.blank, self.null = blank, null
|
||||||
|
self.core, self.rel, self.default = core, rel, default
|
||||||
|
self.editable = editable
|
||||||
|
self.validator_list = validator_list or []
|
||||||
|
self.prepopulate_from = prepopulate_from
|
||||||
|
self.unique_for_date, self.unique_for_month = unique_for_date, unique_for_month
|
||||||
|
self.unique_for_year = unique_for_year
|
||||||
|
self.choices = choices or []
|
||||||
|
self.radio_admin = radio_admin
|
||||||
|
self.help_text = help_text
|
||||||
|
if rel and isinstance(rel, ManyToMany):
|
||||||
|
self.help_text += ' Hold down "Control", or "Command" on a Mac, to select more than one.'
|
||||||
|
|
||||||
|
# Set db_index to True if the field has a relationship and doesn't explicitly set db_index.
|
||||||
|
if db_index is None:
|
||||||
|
if isinstance(rel, OneToOne) or isinstance(rel, ManyToOne):
|
||||||
|
self.db_index = True
|
||||||
|
else:
|
||||||
|
self.db_index = False
|
||||||
|
else:
|
||||||
|
self.db_index = db_index
|
||||||
|
|
||||||
|
def pre_save(self, obj, value, add):
|
||||||
|
"""
|
||||||
|
Hook for altering the object obj based on the value of this field and
|
||||||
|
and on the add/change status.
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
def get_db_prep_save(self, value, add):
|
||||||
|
"Returns field's value prepared for saving into a database."
|
||||||
|
return value
|
||||||
|
|
||||||
|
def get_db_prep_lookup(self, lookup_type, value):
|
||||||
|
"Returns field's value prepared for database lookup."
|
||||||
|
if lookup_type in ('exact', 'gt', 'gte', 'lt', 'lte', 'ne', 'month', 'day'):
|
||||||
|
return [value]
|
||||||
|
elif lookup_type in ('range', 'in'):
|
||||||
|
return value
|
||||||
|
elif lookup_type == 'year':
|
||||||
|
return ['%s-01-01' % value, '%s-12-31' % value]
|
||||||
|
elif lookup_type in ('contains', 'icontains'):
|
||||||
|
return ["%%%s%%" % prep_for_like_query(value)]
|
||||||
|
elif lookup_type == 'iexact':
|
||||||
|
return [prep_for_like_query(value)]
|
||||||
|
elif lookup_type in ('startswith', 'istartswith'):
|
||||||
|
return ["%s%%" % prep_for_like_query(value)]
|
||||||
|
elif lookup_type in ('endswith', 'iendswith'):
|
||||||
|
return ["%%%s" % prep_for_like_query(value)]
|
||||||
|
elif lookup_type == 'isnull':
|
||||||
|
return []
|
||||||
|
raise TypeError, "Field has invalid lookup: %s" % lookup_type
|
||||||
|
|
||||||
|
def has_default(self):
|
||||||
|
"Returns a boolean of whether this field has a default value."
|
||||||
|
return self.default != NOT_PROVIDED
|
||||||
|
|
||||||
|
def get_default(self):
|
||||||
|
"Returns the default value for this field."
|
||||||
|
if self.default != NOT_PROVIDED:
|
||||||
|
if hasattr(self.default, '__get_value__'):
|
||||||
|
return self.default.__get_value__()
|
||||||
|
return self.default
|
||||||
|
if self.null:
|
||||||
|
return None
|
||||||
|
return ""
|
||||||
|
|
||||||
|
def get_manipulator_field_names(self, name_prefix):
|
||||||
|
"""
|
||||||
|
Returns a list of field names that this object adds to the manipulator.
|
||||||
|
"""
|
||||||
|
return [name_prefix + self.name]
|
||||||
|
|
||||||
|
def get_manipulator_fields(self, opts, manipulator, change, name_prefix='', rel=False):
|
||||||
|
"""
|
||||||
|
Returns a list of formfields.FormField instances for this field. It
|
||||||
|
calculates the choices at runtime, not at compile time.
|
||||||
|
|
||||||
|
name_prefix is a prefix to prepend to the "field_name" argument.
|
||||||
|
rel is a boolean specifying whether this field is in a related context.
|
||||||
|
"""
|
||||||
|
params = {'validator_list': self.validator_list[:]}
|
||||||
|
if self.maxlength and not self.choices: # Don't give SelectFields a maxlength parameter.
|
||||||
|
params['maxlength'] = self.maxlength
|
||||||
|
if isinstance(self.rel, ManyToOne):
|
||||||
|
if self.rel.raw_id_admin:
|
||||||
|
field_objs = self.get_manipulator_field_objs()
|
||||||
|
params['validator_list'].append(curry(manipulator_valid_rel_key, self, manipulator))
|
||||||
|
else:
|
||||||
|
if self.radio_admin:
|
||||||
|
field_objs = [formfields.RadioSelectField]
|
||||||
|
params['choices'] = self.get_choices(include_blank=self.blank, blank_choice=BLANK_CHOICE_NONE)
|
||||||
|
params['ul_class'] = get_ul_class(self.radio_admin)
|
||||||
|
else:
|
||||||
|
if self.null:
|
||||||
|
field_objs = [formfields.NullSelectField]
|
||||||
|
else:
|
||||||
|
field_objs = [formfields.SelectField]
|
||||||
|
params['choices'] = self.get_choices()
|
||||||
|
elif self.choices:
|
||||||
|
if self.radio_admin:
|
||||||
|
field_objs = [formfields.RadioSelectField]
|
||||||
|
params['choices'] = self.get_choices(include_blank=self.blank, blank_choice=BLANK_CHOICE_NONE)
|
||||||
|
params['ul_class'] = get_ul_class(self.radio_admin)
|
||||||
|
else:
|
||||||
|
field_objs = [formfields.SelectField]
|
||||||
|
params['choices'] = self.get_choices()
|
||||||
|
else:
|
||||||
|
field_objs = self.get_manipulator_field_objs()
|
||||||
|
|
||||||
|
# Add the "unique" validator(s).
|
||||||
|
for field_name_list in opts.unique_together:
|
||||||
|
if field_name_list[0] == self.name:
|
||||||
|
params['validator_list'].append(getattr(manipulator, 'isUnique%s' % '_'.join(field_name_list)))
|
||||||
|
|
||||||
|
# Add the "unique for..." validator(s).
|
||||||
|
if self.unique_for_date:
|
||||||
|
params['validator_list'].append(getattr(manipulator, 'isUnique%sFor%s' % (self.name, self.unique_for_date)))
|
||||||
|
if self.unique_for_month:
|
||||||
|
params['validator_list'].append(getattr(manipulator, 'isUnique%sFor%s' % (self.name, self.unique_for_month)))
|
||||||
|
if self.unique_for_year:
|
||||||
|
params['validator_list'].append(getattr(manipulator, 'isUnique%sFor%s' % (self.name, self.unique_for_year)))
|
||||||
|
if self.unique:
|
||||||
|
params['validator_list'].append(curry(manipulator_validator_unique, self, opts, manipulator))
|
||||||
|
|
||||||
|
# Only add is_required=True if the field cannot be blank. Primary keys
|
||||||
|
# are a special case, and fields in a related context should set this
|
||||||
|
# as False, because they'll be caught by a separate validator --
|
||||||
|
# RequiredIfOtherFieldGiven.
|
||||||
|
params['is_required'] = not self.blank and not self.primary_key and not rel
|
||||||
|
|
||||||
|
# If this field is in a related context, check whether any other fields
|
||||||
|
# in the related object have core=True. If so, add a validator --
|
||||||
|
# RequiredIfOtherFieldsGiven -- to this FormField.
|
||||||
|
if rel and not self.blank and not isinstance(self, AutoField) and not isinstance(self, FileField):
|
||||||
|
# First, get the core fields, if any.
|
||||||
|
core_field_names = []
|
||||||
|
for f in opts.fields:
|
||||||
|
if f.core and f != self:
|
||||||
|
core_field_names.extend(f.get_manipulator_field_names(name_prefix))
|
||||||
|
# Now, if there are any, add the validator to this FormField.
|
||||||
|
if core_field_names:
|
||||||
|
params['validator_list'].append(validators.RequiredIfOtherFieldsGiven(core_field_names, "This field is required."))
|
||||||
|
|
||||||
|
# BooleanFields (CheckboxFields) are a special case. They don't take
|
||||||
|
# is_required or validator_list.
|
||||||
|
if isinstance(self, BooleanField):
|
||||||
|
del params['validator_list'], params['is_required']
|
||||||
|
|
||||||
|
# Finally, add the field_names.
|
||||||
|
field_names = self.get_manipulator_field_names(name_prefix)
|
||||||
|
return [man(field_name=field_names[i], **params) for i, man in enumerate(field_objs)]
|
||||||
|
|
||||||
|
def get_manipulator_new_data(self, new_data, rel=False):
|
||||||
|
"""
|
||||||
|
Given the full new_data dictionary (from the manipulator), returns this
|
||||||
|
field's data.
|
||||||
|
"""
|
||||||
|
if rel:
|
||||||
|
return new_data.get(self.name, [self.get_default()])[0]
|
||||||
|
else:
|
||||||
|
val = new_data.get(self.name, self.get_default())
|
||||||
|
if not self.empty_strings_allowed and val == '' and self.null:
|
||||||
|
val = None
|
||||||
|
return val
|
||||||
|
|
||||||
|
def get_choices(self, include_blank=True, blank_choice=BLANK_CHOICE_DASH):
|
||||||
|
"Returns a list of tuples used as SelectField choices for this field."
|
||||||
|
first_choice = include_blank and blank_choice or []
|
||||||
|
if self.choices:
|
||||||
|
return first_choice + list(self.choices)
|
||||||
|
rel_obj = self.rel.to
|
||||||
|
return first_choice + [(getattr(x, rel_obj.pk.name), repr(x)) for x in rel_obj.get_model_module().get_list(**self.rel.limit_choices_to)]
|
||||||
|
|
||||||
|
class AutoField(Field):
|
||||||
|
empty_strings_allowed = False
|
||||||
|
def get_manipulator_fields(self, opts, manipulator, change, name_prefix='', rel=False):
|
||||||
|
if not rel:
|
||||||
|
return [] # Don't add a FormField unless it's in a related context.
|
||||||
|
return Field.get_manipulator_fields(self, opts, manipulator, change, name_prefix, rel)
|
||||||
|
|
||||||
|
def get_manipulator_field_objs(self):
|
||||||
|
return [formfields.HiddenField]
|
||||||
|
|
||||||
|
def get_manipulator_new_data(self, new_data, rel=False):
|
||||||
|
if not rel:
|
||||||
|
return None
|
||||||
|
return Field.get_manipulator_new_data(self, new_data, rel)
|
||||||
|
|
||||||
|
class BooleanField(Field):
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
kwargs['blank'] = True
|
||||||
|
Field.__init__(self, *args, **kwargs)
|
||||||
|
|
||||||
|
def get_manipulator_field_objs(self):
|
||||||
|
return [formfields.CheckboxField]
|
||||||
|
|
||||||
|
class CharField(Field):
|
||||||
|
def get_manipulator_field_objs(self):
|
||||||
|
return [formfields.TextField]
|
||||||
|
|
||||||
|
class CommaSeparatedIntegerField(CharField):
|
||||||
|
def get_manipulator_field_objs(self):
|
||||||
|
return [formfields.CommaSeparatedIntegerField]
|
||||||
|
|
||||||
|
class DateField(Field):
|
||||||
|
empty_strings_allowed = False
|
||||||
|
def __init__(self, name, verbose_name=None, auto_now=False, auto_now_add=False, **kwargs):
|
||||||
|
self.auto_now, self.auto_now_add = auto_now, auto_now_add
|
||||||
|
if auto_now or auto_now_add:
|
||||||
|
kwargs['editable'] = False
|
||||||
|
Field.__init__(self, name, verbose_name, **kwargs)
|
||||||
|
|
||||||
|
def get_db_prep_lookup(self, lookup_type, value):
|
||||||
|
if lookup_type == 'range':
|
||||||
|
value = [str(v) for v in value]
|
||||||
|
else:
|
||||||
|
value = str(value)
|
||||||
|
return Field.get_db_prep_lookup(self, lookup_type, value)
|
||||||
|
|
||||||
|
def pre_save(self, obj, value, add):
|
||||||
|
if self.auto_now or (self.auto_now_add and add):
|
||||||
|
setattr(obj, self.name, datetime.datetime.now())
|
||||||
|
|
||||||
|
def get_db_prep_save(self, value, add):
|
||||||
|
# Casts dates into string format for entry into database.
|
||||||
|
if value is not None:
|
||||||
|
value = value.strftime('%Y-%m-%d')
|
||||||
|
return Field.get_db_prep_save(self, value, add)
|
||||||
|
|
||||||
|
def get_manipulator_field_objs(self):
|
||||||
|
return [formfields.DateField]
|
||||||
|
|
||||||
|
class DateTimeField(DateField):
|
||||||
|
def get_db_prep_save(self, value, add):
|
||||||
|
# Casts dates into string format for entry into database.
|
||||||
|
if value is not None:
|
||||||
|
value = value.strftime('%Y-%m-%d %H:%M:%S')
|
||||||
|
return Field.get_db_prep_save(self, value, add)
|
||||||
|
|
||||||
|
def get_manipulator_field_objs(self):
|
||||||
|
return [formfields.DateField, formfields.TimeField]
|
||||||
|
|
||||||
|
def get_manipulator_field_names(self, name_prefix):
|
||||||
|
return [name_prefix + self.name + '_date', name_prefix + self.name + '_time']
|
||||||
|
|
||||||
|
def get_manipulator_new_data(self, new_data, rel=False):
|
||||||
|
date_field, time_field = self.get_manipulator_field_names('')
|
||||||
|
if rel:
|
||||||
|
d = new_data.get(date_field, [None])[0]
|
||||||
|
t = new_data.get(time_field, [None])[0]
|
||||||
|
else:
|
||||||
|
d = new_data.get(date_field, None)
|
||||||
|
t = new_data.get(time_field, None)
|
||||||
|
if d is not None and t is not None:
|
||||||
|
return datetime.datetime.combine(d, t)
|
||||||
|
return self.get_default()
|
||||||
|
|
||||||
|
class EmailField(Field):
|
||||||
|
def get_manipulator_field_objs(self):
|
||||||
|
return [formfields.EmailField]
|
||||||
|
|
||||||
|
class FileField(Field):
|
||||||
|
def __init__(self, name, verbose_name=None, upload_to='', **kwargs):
|
||||||
|
self.upload_to = upload_to
|
||||||
|
Field.__init__(self, name, verbose_name, **kwargs)
|
||||||
|
|
||||||
|
def get_manipulator_fields(self, opts, manipulator, change, name_prefix='', rel=False):
|
||||||
|
field_list = Field.get_manipulator_fields(self, opts, manipulator, change, name_prefix, rel)
|
||||||
|
|
||||||
|
if not self.blank:
|
||||||
|
if rel:
|
||||||
|
# This validator makes sure FileFields work in a related context.
|
||||||
|
class RequiredFileField:
|
||||||
|
def __init__(self, other_field_names, other_file_field_name):
|
||||||
|
self.other_field_names = other_field_names
|
||||||
|
self.other_file_field_name = other_file_field_name
|
||||||
|
self.always_test = True
|
||||||
|
def __call__(self, field_data, all_data):
|
||||||
|
if not all_data.get(self.other_file_field_name, False):
|
||||||
|
c = validators.RequiredIfOtherFieldsGiven(self.other_field_names, "This field is required.")
|
||||||
|
c(field_data, all_data)
|
||||||
|
# First, get the core fields, if any.
|
||||||
|
core_field_names = []
|
||||||
|
for f in opts.fields:
|
||||||
|
if f.core and f != self:
|
||||||
|
core_field_names.extend(f.get_manipulator_field_names(name_prefix))
|
||||||
|
# Now, if there are any, add the validator to this FormField.
|
||||||
|
if core_field_names:
|
||||||
|
field_list[0].validator_list.append(RequiredFileField(core_field_names, field_list[1].field_name))
|
||||||
|
else:
|
||||||
|
v = validators.RequiredIfOtherFieldNotGiven(field_list[1].field_name, "This field is required.")
|
||||||
|
v.always_test = True
|
||||||
|
field_list[0].validator_list.append(v)
|
||||||
|
field_list[0].is_required = field_list[1].is_required = False
|
||||||
|
|
||||||
|
# If the raw path is passed in, validate it's under the MEDIA_ROOT.
|
||||||
|
def isWithinMediaRoot(field_data, all_data):
|
||||||
|
f = os.path.abspath(os.path.join(settings.MEDIA_ROOT, field_data))
|
||||||
|
if not f.startswith(os.path.normpath(settings.MEDIA_ROOT)):
|
||||||
|
raise validators.ValidationError, "Enter a valid filename."
|
||||||
|
field_list[1].validator_list.append(isWithinMediaRoot)
|
||||||
|
return field_list
|
||||||
|
|
||||||
|
def get_manipulator_field_objs(self):
|
||||||
|
return [formfields.FileUploadField, formfields.HiddenField]
|
||||||
|
|
||||||
|
def get_manipulator_field_names(self, name_prefix):
|
||||||
|
return [name_prefix + self.name + '_file', name_prefix + self.name]
|
||||||
|
|
||||||
|
def save_file(self, new_data, new_object, original_object, change, rel):
|
||||||
|
upload_field_name = self.get_manipulator_field_names('')[0]
|
||||||
|
if new_data.get(upload_field_name, False):
|
||||||
|
if rel:
|
||||||
|
getattr(new_object, 'save_%s_file' % self.name)(new_data[upload_field_name][0]["filename"], new_data[upload_field_name][0]["content"])
|
||||||
|
else:
|
||||||
|
getattr(new_object, 'save_%s_file' % self.name)(new_data[upload_field_name]["filename"], new_data[upload_field_name]["content"])
|
||||||
|
|
||||||
|
def get_directory_name(self):
|
||||||
|
return os.path.normpath(datetime.datetime.now().strftime(self.upload_to))
|
||||||
|
|
||||||
|
def get_filename(self, filename):
|
||||||
|
from django.utils.text import get_valid_filename
|
||||||
|
f = os.path.join(self.get_directory_name(), get_valid_filename(os.path.basename(filename)))
|
||||||
|
return os.path.normpath(f)
|
||||||
|
|
||||||
|
class FloatField(Field):
|
||||||
|
empty_strings_allowed = False
|
||||||
|
def __init__(self, name, verbose_name=None, max_digits=None, decimal_places=None, **kwargs):
|
||||||
|
self.max_digits, self.decimal_places = max_digits, decimal_places
|
||||||
|
Field.__init__(self, name, verbose_name, **kwargs)
|
||||||
|
|
||||||
|
def get_manipulator_field_objs(self):
|
||||||
|
return [curry(formfields.FloatField, max_digits=self.max_digits, decimal_places=self.decimal_places)]
|
||||||
|
|
||||||
|
class ImageField(FileField):
|
||||||
|
def __init__(self, name, verbose_name=None, width_field=None, height_field=None, **kwargs):
|
||||||
|
self.width_field, self.height_field = width_field, height_field
|
||||||
|
FileField.__init__(self, name, verbose_name, **kwargs)
|
||||||
|
|
||||||
|
def get_manipulator_field_objs(self):
|
||||||
|
return [formfields.ImageUploadField, formfields.HiddenField]
|
||||||
|
|
||||||
|
def save_file(self, new_data, new_object, original_object, change, rel):
|
||||||
|
FileField.save_file(self, new_data, new_object, original_object, change, rel)
|
||||||
|
# If the image has height and/or width field(s) and they haven't
|
||||||
|
# changed, set the width and/or height field(s) back to their original
|
||||||
|
# values.
|
||||||
|
if change and (self.width_field or self.height_field):
|
||||||
|
if self.width_field:
|
||||||
|
setattr(new_object, self.width_field, getattr(original_object, self.width_field))
|
||||||
|
if self.height_field:
|
||||||
|
setattr(new_object, self.height_field, getattr(original_object, self.height_field))
|
||||||
|
new_object.save()
|
||||||
|
|
||||||
|
class IntegerField(Field):
|
||||||
|
empty_strings_allowed = False
|
||||||
|
def get_manipulator_field_objs(self):
|
||||||
|
return [formfields.IntegerField]
|
||||||
|
|
||||||
|
class IPAddressField(Field):
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
kwargs['maxlength'] = 15
|
||||||
|
Field.__init__(self, *args, **kwargs)
|
||||||
|
|
||||||
|
def get_manipulator_field_objs(self):
|
||||||
|
return [formfields.IPAddressField]
|
||||||
|
|
||||||
|
class NullBooleanField(Field):
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
kwargs['null'] = True
|
||||||
|
Field.__init__(self, *args, **kwargs)
|
||||||
|
|
||||||
|
def get_manipulator_field_objs(self):
|
||||||
|
return [formfields.NullBooleanField]
|
||||||
|
|
||||||
|
class PhoneNumberField(IntegerField):
|
||||||
|
def get_manipulator_field_objs(self):
|
||||||
|
return [formfields.PhoneNumberField]
|
||||||
|
|
||||||
|
class PositiveIntegerField(IntegerField):
|
||||||
|
def get_manipulator_field_objs(self):
|
||||||
|
return [formfields.PositiveIntegerField]
|
||||||
|
|
||||||
|
class PositiveSmallIntegerField(IntegerField):
|
||||||
|
def get_manipulator_field_objs(self):
|
||||||
|
return [formfields.PositiveSmallIntegerField]
|
||||||
|
|
||||||
|
class SlugField(Field):
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
kwargs['maxlength'] = 50
|
||||||
|
kwargs.setdefault('validator_list', []).append(validators.isAlphaNumeric)
|
||||||
|
# Set db_index=True unless it's been set manually.
|
||||||
|
if not kwargs.has_key('db_index'):
|
||||||
|
kwargs['db_index'] = True
|
||||||
|
Field.__init__(self, *args, **kwargs)
|
||||||
|
|
||||||
|
def get_manipulator_field_objs(self):
|
||||||
|
return [formfields.TextField]
|
||||||
|
|
||||||
|
class SmallIntegerField(IntegerField):
|
||||||
|
def get_manipulator_field_objs(self):
|
||||||
|
return [formfields.SmallIntegerField]
|
||||||
|
|
||||||
|
class TextField(Field):
|
||||||
|
def get_manipulator_field_objs(self):
|
||||||
|
return [formfields.LargeTextField]
|
||||||
|
|
||||||
|
class TimeField(Field):
|
||||||
|
empty_strings_allowed = False
|
||||||
|
def __init__(self, name, verbose_name=None, auto_now=False, auto_now_add=False, **kwargs):
|
||||||
|
self.auto_now, self.auto_now_add = auto_now, auto_now_add
|
||||||
|
if auto_now or auto_now_add:
|
||||||
|
kwargs['editable'] = False
|
||||||
|
Field.__init__(self, name, verbose_name, **kwargs)
|
||||||
|
|
||||||
|
def get_db_prep_lookup(self, lookup_type, value):
|
||||||
|
if lookup_type == 'range':
|
||||||
|
value = [str(v) for v in value]
|
||||||
|
else:
|
||||||
|
value = str(value)
|
||||||
|
return Field.get_db_prep_lookup(self, lookup_type, value)
|
||||||
|
|
||||||
|
def pre_save(self, obj, value, add):
|
||||||
|
if self.auto_now or (self.auto_now_add and add):
|
||||||
|
setattr(obj, self.name, datetime.datetime.now().time())
|
||||||
|
|
||||||
|
def get_db_prep_save(self, value, add):
|
||||||
|
# Casts dates into string format for entry into database.
|
||||||
|
if value is not None:
|
||||||
|
value = value.strftime('%H:%M:%S')
|
||||||
|
return Field.get_db_prep_save(self, value, add)
|
||||||
|
|
||||||
|
def get_manipulator_field_objs(self):
|
||||||
|
return [formfields.TimeField]
|
||||||
|
|
||||||
|
class URLField(Field):
|
||||||
|
def __init__(self, name, verbose_name=None, verify_exists=True, **kwargs):
|
||||||
|
if verify_exists:
|
||||||
|
kwargs.setdefault('validator_list', []).append(validators.isExistingURL)
|
||||||
|
Field.__init__(self, name, verbose_name, **kwargs)
|
||||||
|
|
||||||
|
def get_manipulator_field_objs(self):
|
||||||
|
return [formfields.URLField]
|
||||||
|
|
||||||
|
class USStateField(Field):
|
||||||
|
def get_manipulator_field_objs(self):
|
||||||
|
return [formfields.USStateField]
|
||||||
|
|
||||||
|
class XMLField(Field):
|
||||||
|
def __init__(self, name, verbose_name=None, schema_path=None, **kwargs):
|
||||||
|
self.schema_path = schema_path
|
||||||
|
Field.__init__(self, name, verbose_name, **kwargs)
|
||||||
|
|
||||||
|
def get_manipulator_field_objs(self):
|
||||||
|
return [curry(formfields.XMLLargeTextField, schema_path=self.schema_path)]
|
||||||
|
|
||||||
|
class ForeignKey(Field):
|
||||||
|
empty_strings_allowed = False
|
||||||
|
def __init__(self, to, to_field=None, rel_name=None, **kwargs):
|
||||||
|
try:
|
||||||
|
to_name = to._meta.object_name.lower()
|
||||||
|
except AttributeError: # to._meta doesn't exist, so it must be RECURSIVE_RELATIONSHIP_CONSTANT
|
||||||
|
assert to == 'self', "ForeignKey(%r) is invalid. First parameter to ForeignKey must be either a model or the string %r" % (to, RECURSIVE_RELATIONSHIP_CONSTANT)
|
||||||
|
kwargs['name'] = kwargs.get('name', '')
|
||||||
|
kwargs['verbose_name'] = kwargs.get('verbose_name', '')
|
||||||
|
else:
|
||||||
|
to_field = to_field or to._meta.pk.name
|
||||||
|
kwargs['name'] = kwargs.get('name', to_name + '_id')
|
||||||
|
kwargs['verbose_name'] = kwargs.get('verbose_name', to._meta.verbose_name)
|
||||||
|
rel_name = rel_name or to_name
|
||||||
|
kwargs['rel'] = ManyToOne(to, rel_name, to_field,
|
||||||
|
num_in_admin=kwargs.pop('num_in_admin', 0),
|
||||||
|
min_num_in_admin=kwargs.pop('min_num_in_admin', None),
|
||||||
|
max_num_in_admin=kwargs.pop('max_num_in_admin', None),
|
||||||
|
num_extra_on_change=kwargs.pop('num_extra_on_change', 1),
|
||||||
|
edit_inline=kwargs.pop('edit_inline', False),
|
||||||
|
edit_inline_type=kwargs.pop('edit_inline_type', STACKED),
|
||||||
|
related_name=kwargs.pop('related_name', None),
|
||||||
|
limit_choices_to=kwargs.pop('limit_choices_to', None),
|
||||||
|
lookup_overrides=kwargs.pop('lookup_overrides', None),
|
||||||
|
raw_id_admin=kwargs.pop('raw_id_admin', False))
|
||||||
|
Field.__init__(self, **kwargs)
|
||||||
|
|
||||||
|
def get_manipulator_field_objs(self):
|
||||||
|
return [formfields.IntegerField]
|
||||||
|
|
||||||
|
class ManyToManyField(Field):
|
||||||
|
def __init__(self, to, rel_name=None, **kwargs):
|
||||||
|
kwargs['name'] = kwargs.get('name', to._meta.module_name)
|
||||||
|
kwargs['verbose_name'] = kwargs.get('verbose_name', to._meta.verbose_name_plural)
|
||||||
|
rel_name = rel_name or to._meta.object_name.lower()
|
||||||
|
kwargs['rel'] = ManyToMany(to, rel_name,
|
||||||
|
num_in_admin=kwargs.pop('num_in_admin', 0),
|
||||||
|
related_name=kwargs.pop('related_name', None),
|
||||||
|
filter_interface=kwargs.pop('filter_interface', None),
|
||||||
|
limit_choices_to=kwargs.pop('limit_choices_to', None))
|
||||||
|
Field.__init__(self, **kwargs)
|
||||||
|
|
||||||
|
def get_manipulator_field_objs(self):
|
||||||
|
choices = self.get_choices(include_blank=False)
|
||||||
|
return [curry(formfields.SelectMultipleField, size=min(max(len(choices), 5), 15), choices=choices)]
|
||||||
|
|
||||||
|
def get_m2m_db_table(self, original_opts):
|
||||||
|
"Returns the name of the many-to-many 'join' table."
|
||||||
|
return '%s_%s' % (original_opts.db_table, self.name)
|
||||||
|
|
||||||
|
class OneToOneField(IntegerField):
|
||||||
|
def __init__(self, to, to_field=None, rel_name=None, **kwargs):
|
||||||
|
kwargs['name'] = kwargs.get('name', 'id')
|
||||||
|
kwargs['verbose_name'] = kwargs.get('verbose_name', 'ID')
|
||||||
|
to_field = to_field or to._meta.pk.name
|
||||||
|
rel_name = rel_name or to._meta.object_name.lower()
|
||||||
|
kwargs['rel'] = OneToOne(to, rel_name, to_field,
|
||||||
|
num_in_admin=kwargs.pop('num_in_admin', 0),
|
||||||
|
edit_inline=kwargs.pop('edit_inline', False),
|
||||||
|
edit_inline_type=kwargs.pop('edit_inline_type', STACKED),
|
||||||
|
related_name=kwargs.pop('related_name', None),
|
||||||
|
limit_choices_to=kwargs.pop('limit_choices_to', None),
|
||||||
|
lookup_overrides=kwargs.pop('lookup_overrides', None),
|
||||||
|
raw_id_admin=kwargs.pop('raw_id_admin', False))
|
||||||
|
kwargs['primary_key'] = True
|
||||||
|
IntegerField.__init__(self, **kwargs)
|
||||||
|
|
||||||
|
class ManyToOne:
|
||||||
|
def __init__(self, to, name, field_name, num_in_admin=0, min_num_in_admin=None,
|
||||||
|
max_num_in_admin=None, num_extra_on_change=1, edit_inline=False, edit_inline_type=STACKED,
|
||||||
|
related_name=None, limit_choices_to=None, lookup_overrides=None, raw_id_admin=False):
|
||||||
|
try:
|
||||||
|
self.to = to._meta
|
||||||
|
except AttributeError: # to._meta doesn't exist, so it must be RECURSIVE_RELATIONSHIP_CONSTANT
|
||||||
|
assert to == RECURSIVE_RELATIONSHIP_CONSTANT, "'to' must be either a model or the string '%s'" % RECURSIVE_RELATIONSHIP_CONSTANT
|
||||||
|
self.to = to
|
||||||
|
self.name, self.field_name = name, field_name
|
||||||
|
self.num_in_admin, self.edit_inline = num_in_admin, edit_inline
|
||||||
|
self.min_num_in_admin, self.max_num_in_admin = min_num_in_admin, max_num_in_admin
|
||||||
|
self.num_extra_on_change = num_extra_on_change
|
||||||
|
self.edit_inline_type, self.related_name = edit_inline_type, related_name
|
||||||
|
self.limit_choices_to = limit_choices_to or {}
|
||||||
|
self.lookup_overrides = lookup_overrides or {}
|
||||||
|
self.raw_id_admin = raw_id_admin
|
||||||
|
|
||||||
|
def get_cache_name(self):
|
||||||
|
return '_%s_cache' % self.name
|
||||||
|
|
||||||
|
def get_related_field(self):
|
||||||
|
"Returns the Field in the 'to' object to which this relationship is tied."
|
||||||
|
return self.to.get_field(self.field_name)
|
||||||
|
|
||||||
|
class ManyToMany:
|
||||||
|
def __init__(self, to, name, num_in_admin=0, related_name=None,
|
||||||
|
filter_interface=None, limit_choices_to=None):
|
||||||
|
self.to, self.name = to._meta, name
|
||||||
|
self.num_in_admin = num_in_admin
|
||||||
|
self.related_name = related_name
|
||||||
|
self.filter_interface = filter_interface
|
||||||
|
self.limit_choices_to = limit_choices_to or {}
|
||||||
|
self.edit_inline = False
|
||||||
|
|
||||||
|
class OneToOne(ManyToOne):
|
||||||
|
def __init__(self, to, name, field_name, num_in_admin=0, edit_inline=False,
|
||||||
|
edit_inline_type=STACKED, related_name=None, limit_choices_to=None, lookup_overrides=None,
|
||||||
|
raw_id_admin=False):
|
||||||
|
self.to, self.name, self.field_name = to._meta, name, field_name
|
||||||
|
self.num_in_admin, self.edit_inline = num_in_admin, edit_inline
|
||||||
|
self.edit_inline_type, self.related_name = edit_inline_type, related_name
|
||||||
|
self.limit_choices_to = limit_choices_to or {}
|
||||||
|
self.lookup_overrides = lookup_overrides or {}
|
||||||
|
self.raw_id_admin = raw_id_admin
|
||||||
|
|
||||||
|
class Admin:
|
||||||
|
def __init__(self, fields=None, js=None, list_display=None, list_filter=None, date_hierarchy=None,
|
||||||
|
save_as=False, ordering=None, search_fields=None, save_on_top=False):
|
||||||
|
self.fields = fields
|
||||||
|
self.js = js or []
|
||||||
|
self.list_display = list_display or ['__repr__']
|
||||||
|
self.list_filter = list_filter or []
|
||||||
|
self.date_hierarchy = date_hierarchy
|
||||||
|
self.save_as, self.ordering = save_as, ordering
|
||||||
|
self.search_fields = search_fields or []
|
||||||
|
self.save_on_top = save_on_top
|
||||||
|
|
||||||
|
def get_field_objs(self, opts):
|
||||||
|
"""
|
||||||
|
Returns self.fields, except with fields as Field objects instead of
|
||||||
|
field names. If self.fields is None, defaults to putting every
|
||||||
|
non-AutoField field with editable=True in a single fieldset.
|
||||||
|
"""
|
||||||
|
if self.fields is None:
|
||||||
|
field_struct = ((None, {'fields': [f.name for f in opts.fields + opts.many_to_many if f.editable and not isinstance(f, AutoField)]}),)
|
||||||
|
else:
|
||||||
|
field_struct = self.fields
|
||||||
|
new_fieldset_list = []
|
||||||
|
for fieldset in field_struct:
|
||||||
|
new_fieldset = [fieldset[0], {}]
|
||||||
|
new_fieldset[1].update(fieldset[1])
|
||||||
|
admin_fields = []
|
||||||
|
for field_name_or_list in fieldset[1]['fields']:
|
||||||
|
if isinstance(field_name_or_list, basestring):
|
||||||
|
admin_fields.append([opts.get_field(field_name_or_list)])
|
||||||
|
else:
|
||||||
|
admin_fields.append([opts.get_field(field_name) for field_name in field_name_or_list])
|
||||||
|
new_fieldset[1]['fields'] = admin_fields
|
||||||
|
new_fieldset_list.append(new_fieldset)
|
||||||
|
return new_fieldset_list
|
|
@ -1,4 +1,5 @@
|
||||||
from django.core import meta
|
from django.core import meta
|
||||||
|
from django.utils.functional import curry
|
||||||
|
|
||||||
__all__ = ['auth', 'core']
|
__all__ = ['auth', 'core']
|
||||||
|
|
||||||
|
@ -28,30 +29,30 @@ for mod in modules:
|
||||||
if isinstance(rel_field.rel, meta.OneToOne):
|
if isinstance(rel_field.rel, meta.OneToOne):
|
||||||
# Add "get_thingie" methods for one-to-one related objects.
|
# Add "get_thingie" methods for one-to-one related objects.
|
||||||
# EXAMPLE: Place.get_restaurants_restaurant()
|
# EXAMPLE: Place.get_restaurants_restaurant()
|
||||||
func = meta.curry(meta.method_get_related, 'get_object', rel_mod, rel_field)
|
func = curry(meta.method_get_related, 'get_object', rel_mod, rel_field)
|
||||||
func.__doc__ = "Returns the associated `%s.%s` object." % (rel_obj.app_label, rel_obj.module_name)
|
func.__doc__ = "Returns the associated `%s.%s` object." % (rel_obj.app_label, rel_obj.module_name)
|
||||||
setattr(klass, 'get_%s' % rel_obj_name, func)
|
setattr(klass, 'get_%s' % rel_obj_name, func)
|
||||||
elif isinstance(rel_field.rel, meta.ManyToOne):
|
elif isinstance(rel_field.rel, meta.ManyToOne):
|
||||||
# Add "get_thingie" methods for many-to-one related objects.
|
# Add "get_thingie" methods for many-to-one related objects.
|
||||||
# EXAMPLE: Poll.get_choice()
|
# EXAMPLE: Poll.get_choice()
|
||||||
func = meta.curry(meta.method_get_related, 'get_object', rel_mod, rel_field)
|
func = curry(meta.method_get_related, 'get_object', rel_mod, rel_field)
|
||||||
func.__doc__ = "Returns the associated `%s.%s` object matching the given criteria." % (rel_obj.app_label, rel_obj.module_name)
|
func.__doc__ = "Returns the associated `%s.%s` object matching the given criteria." % (rel_obj.app_label, rel_obj.module_name)
|
||||||
setattr(klass, 'get_%s' % rel_obj_name, func)
|
setattr(klass, 'get_%s' % rel_obj_name, func)
|
||||||
# Add "get_thingie_count" methods for many-to-one related objects.
|
# Add "get_thingie_count" methods for many-to-one related objects.
|
||||||
# EXAMPLE: Poll.get_choice_count()
|
# EXAMPLE: Poll.get_choice_count()
|
||||||
func = meta.curry(meta.method_get_related, 'get_count', rel_mod, rel_field)
|
func = curry(meta.method_get_related, 'get_count', rel_mod, rel_field)
|
||||||
func.__doc__ = "Returns the number of associated `%s.%s` objects." % (rel_obj.app_label, rel_obj.module_name)
|
func.__doc__ = "Returns the number of associated `%s.%s` objects." % (rel_obj.app_label, rel_obj.module_name)
|
||||||
setattr(klass, 'get_%s_count' % rel_obj_name, func)
|
setattr(klass, 'get_%s_count' % rel_obj_name, func)
|
||||||
# Add "get_thingie_list" methods for many-to-one related objects.
|
# Add "get_thingie_list" methods for many-to-one related objects.
|
||||||
# EXAMPLE: Poll.get_choice_list()
|
# EXAMPLE: Poll.get_choice_list()
|
||||||
func = meta.curry(meta.method_get_related, 'get_list', rel_mod, rel_field)
|
func = curry(meta.method_get_related, 'get_list', rel_mod, rel_field)
|
||||||
func.__doc__ = "Returns a list of associated `%s.%s` objects." % (rel_obj.app_label, rel_obj.module_name)
|
func.__doc__ = "Returns a list of associated `%s.%s` objects." % (rel_obj.app_label, rel_obj.module_name)
|
||||||
setattr(klass, 'get_%s_list' % rel_obj_name, func)
|
setattr(klass, 'get_%s_list' % rel_obj_name, func)
|
||||||
# Add "add_thingie" methods for many-to-one related objects,
|
# Add "add_thingie" methods for many-to-one related objects,
|
||||||
# but only for related objects that are in the same app.
|
# but only for related objects that are in the same app.
|
||||||
# EXAMPLE: Poll.add_choice()
|
# EXAMPLE: Poll.add_choice()
|
||||||
if rel_obj.app_label == klass._meta.app_label:
|
if rel_obj.app_label == klass._meta.app_label:
|
||||||
func = meta.curry(meta.method_add_related, rel_obj, rel_mod, rel_field)
|
func = curry(meta.method_add_related, rel_obj, rel_mod, rel_field)
|
||||||
func.alters_data = True
|
func.alters_data = True
|
||||||
setattr(klass, 'add_%s' % rel_obj_name, func)
|
setattr(klass, 'add_%s' % rel_obj_name, func)
|
||||||
del func
|
del func
|
||||||
|
@ -61,11 +62,11 @@ for mod in modules:
|
||||||
for rel_opts, rel_field in klass._meta.get_all_related_many_to_many_objects():
|
for rel_opts, rel_field in klass._meta.get_all_related_many_to_many_objects():
|
||||||
rel_mod = rel_opts.get_model_module()
|
rel_mod = rel_opts.get_model_module()
|
||||||
rel_obj_name = klass._meta.get_rel_object_method_name(rel_opts, rel_field)
|
rel_obj_name = klass._meta.get_rel_object_method_name(rel_opts, rel_field)
|
||||||
setattr(klass, 'get_%s' % rel_obj_name, meta.curry(meta.method_get_related_many_to_many, 'get_object', rel_mod, rel_field))
|
setattr(klass, 'get_%s' % rel_obj_name, curry(meta.method_get_related_many_to_many, 'get_object', rel_mod, rel_field))
|
||||||
setattr(klass, 'get_%s_count' % rel_obj_name, meta.curry(meta.method_get_related_many_to_many, 'get_count', rel_mod, rel_field))
|
setattr(klass, 'get_%s_count' % rel_obj_name, curry(meta.method_get_related_many_to_many, 'get_count', rel_mod, rel_field))
|
||||||
setattr(klass, 'get_%s_list' % rel_obj_name, meta.curry(meta.method_get_related_many_to_many, 'get_list', rel_mod, rel_field))
|
setattr(klass, 'get_%s_list' % rel_obj_name, curry(meta.method_get_related_many_to_many, 'get_list', rel_mod, rel_field))
|
||||||
if rel_opts.app_label == klass._meta.app_label:
|
if rel_opts.app_label == klass._meta.app_label:
|
||||||
func = meta.curry(meta.method_set_related_many_to_many, rel_opts, rel_field)
|
func = curry(meta.method_set_related_many_to_many, rel_opts, rel_field)
|
||||||
func.alters_data = True
|
func.alters_data = True
|
||||||
setattr(klass, 'set_%s' % rel_opts.module_name, func)
|
setattr(klass, 'set_%s' % rel_opts.module_name, func)
|
||||||
del func
|
del func
|
||||||
|
@ -74,12 +75,12 @@ for mod in modules:
|
||||||
# Add "set_thingie_order" and "get_thingie_order" methods for objects
|
# Add "set_thingie_order" and "get_thingie_order" methods for objects
|
||||||
# that are ordered with respect to this.
|
# that are ordered with respect to this.
|
||||||
for obj in klass._meta.get_ordered_objects():
|
for obj in klass._meta.get_ordered_objects():
|
||||||
func = meta.curry(meta.method_set_order, obj)
|
func = curry(meta.method_set_order, obj)
|
||||||
func.__doc__ = "Sets the order of associated `%s.%s` objects to the given ID list." % (obj.app_label, obj.module_name)
|
func.__doc__ = "Sets the order of associated `%s.%s` objects to the given ID list." % (obj.app_label, obj.module_name)
|
||||||
func.alters_data = True
|
func.alters_data = True
|
||||||
setattr(klass, 'set_%s_order' % obj.object_name.lower(), func)
|
setattr(klass, 'set_%s_order' % obj.object_name.lower(), func)
|
||||||
|
|
||||||
func = meta.curry(meta.method_get_order, obj)
|
func = curry(meta.method_get_order, obj)
|
||||||
func.__doc__ = "Returns the order of associated `%s.%s` objects as a list of IDs." % (obj.app_label, obj.module_name)
|
func.__doc__ = "Returns the order of associated `%s.%s` objects as a list of IDs." % (obj.app_label, obj.module_name)
|
||||||
setattr(klass, 'get_%s_order' % obj.object_name.lower(), func)
|
setattr(klass, 'get_%s_order' % obj.object_name.lower(), func)
|
||||||
del func, obj # clean up
|
del func, obj # clean up
|
||||||
|
|
|
@ -6,10 +6,11 @@ class AdminApplistNode(template.Node):
|
||||||
|
|
||||||
def render(self, context):
|
def render(self, context):
|
||||||
from django.core import meta
|
from django.core import meta
|
||||||
|
from django.utils.text import capfirst
|
||||||
app_list = []
|
app_list = []
|
||||||
for app in meta.get_installed_model_modules():
|
for app in meta.get_installed_model_modules():
|
||||||
app_label = app.__name__[app.__name__.rindex('.')+1:]
|
app_label = app.__name__[app.__name__.rindex('.')+1:]
|
||||||
model_list = [{'name': meta.capfirst(m._meta.verbose_name_plural),
|
model_list = [{'name': capfirst(m._meta.verbose_name_plural),
|
||||||
'admin_url': '%s/%s/' % (app_label, m._meta.module_name)} \
|
'admin_url': '%s/%s/' % (app_label, m._meta.module_name)} \
|
||||||
for m in app._MODELS if m._meta.admin]
|
for m in app._MODELS if m._meta.admin]
|
||||||
if model_list:
|
if model_list:
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
def curry(*args, **kwargs):
|
||||||
|
def _curried(*moreargs, **morekwargs):
|
||||||
|
return args[0](*(args[1:]+moreargs), **dict(kwargs.items() + morekwargs.items()))
|
||||||
|
return _curried
|
|
@ -1,5 +1,8 @@
|
||||||
import re
|
import re
|
||||||
|
|
||||||
|
# Capitalizes the first letter of a string.
|
||||||
|
capfirst = lambda x: x and x[0].upper() + x[1:]
|
||||||
|
|
||||||
def wrap(text, width):
|
def wrap(text, width):
|
||||||
"""
|
"""
|
||||||
A word-wrap function that preserves existing line breaks and most spaces in
|
A word-wrap function that preserves existing line breaks and most spaces in
|
||||||
|
|
|
@ -6,7 +6,7 @@ from django.core.extensions import DjangoContext as Context
|
||||||
from django.models.auth import log
|
from django.models.auth import log
|
||||||
from django.utils.html import strip_tags
|
from django.utils.html import strip_tags
|
||||||
from django.utils.httpwrappers import HttpResponse, HttpResponseRedirect
|
from django.utils.httpwrappers import HttpResponse, HttpResponseRedirect
|
||||||
from django.utils.text import get_text_list
|
from django.utils.text import capfirst, get_text_list
|
||||||
from django.conf.settings import ADMIN_MEDIA_PREFIX
|
from django.conf.settings import ADMIN_MEDIA_PREFIX
|
||||||
import operator
|
import operator
|
||||||
|
|
||||||
|
@ -266,7 +266,7 @@ def change_list(request, app_label, module_name):
|
||||||
raw_template = ['{% extends "base_site" %}\n']
|
raw_template = ['{% extends "base_site" %}\n']
|
||||||
raw_template.append('{% block bodyclass %}change-list{% endblock %}\n')
|
raw_template.append('{% block bodyclass %}change-list{% endblock %}\n')
|
||||||
if not is_popup:
|
if not is_popup:
|
||||||
raw_template.append('{%% block breadcrumbs %%}<div class="breadcrumbs"><a href="../../">Home</a> › %s</div>{%% endblock %%}\n' % meta.capfirst(opts.verbose_name_plural))
|
raw_template.append('{%% block breadcrumbs %%}<div class="breadcrumbs"><a href="../../">Home</a> › %s</div>{%% endblock %%}\n' % capfirst(opts.verbose_name_plural))
|
||||||
raw_template.append('{% block coltype %}flex{% endblock %}')
|
raw_template.append('{% block coltype %}flex{% endblock %}')
|
||||||
raw_template.append('{% block content %}\n')
|
raw_template.append('{% block content %}\n')
|
||||||
raw_template.append('<div id="content-main">\n')
|
raw_template.append('<div id="content-main">\n')
|
||||||
|
@ -356,10 +356,10 @@ def change_list(request, app_label, module_name):
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
header = func.__name__
|
header = func.__name__
|
||||||
# Non-field list_display values don't get ordering capability.
|
# Non-field list_display values don't get ordering capability.
|
||||||
raw_template.append('<th>%s</th>' % meta.capfirst(header))
|
raw_template.append('<th>%s</th>' % capfirst(header))
|
||||||
else:
|
else:
|
||||||
if isinstance(f.rel, meta.ManyToOne) and f.null:
|
if isinstance(f.rel, meta.ManyToOne) and f.null:
|
||||||
raw_template.append('<th>%s</th>' % meta.capfirst(f.verbose_name))
|
raw_template.append('<th>%s</th>' % capfirst(f.verbose_name))
|
||||||
else:
|
else:
|
||||||
th_classes = []
|
th_classes = []
|
||||||
new_order_type = 'asc'
|
new_order_type = 'asc'
|
||||||
|
@ -369,7 +369,7 @@ def change_list(request, app_label, module_name):
|
||||||
raw_template.append('<th%s><a href="%s">%s</a></th>' % \
|
raw_template.append('<th%s><a href="%s">%s</a></th>' % \
|
||||||
((th_classes and ' class="%s"' % ' '.join(th_classes) or ''),
|
((th_classes and ' class="%s"' % ' '.join(th_classes) or ''),
|
||||||
get_query_string(params, {ORDER_VAR: i, ORDER_TYPE_VAR: new_order_type}),
|
get_query_string(params, {ORDER_VAR: i, ORDER_TYPE_VAR: new_order_type}),
|
||||||
meta.capfirst(f.verbose_name)))
|
capfirst(f.verbose_name)))
|
||||||
raw_template.append('</tr>\n</thead>\n')
|
raw_template.append('</tr>\n</thead>\n')
|
||||||
# Result rows.
|
# Result rows.
|
||||||
pk = lookup_opts.pk.name
|
pk = lookup_opts.pk.name
|
||||||
|
@ -572,7 +572,7 @@ def _get_template(opts, app_label, add=False, change=False, show_delete=False, f
|
||||||
t.append('{%% block bodyclass %%}%s-%s change-form{%% endblock %%}\n' % (app_label, opts.object_name.lower()))
|
t.append('{%% block bodyclass %%}%s-%s change-form{%% endblock %%}\n' % (app_label, opts.object_name.lower()))
|
||||||
breadcrumb_title = add and "Add %s" % opts.verbose_name or '{{ original|striptags|truncatewords:"18" }}'
|
breadcrumb_title = add and "Add %s" % opts.verbose_name or '{{ original|striptags|truncatewords:"18" }}'
|
||||||
t.append('{%% block breadcrumbs %%}{%% if not is_popup %%}<div class="breadcrumbs"><a href="../../../">Home</a> › <a href="../">%s</a> › %s</div>{%% endif %%}{%% endblock %%}\n' % \
|
t.append('{%% block breadcrumbs %%}{%% if not is_popup %%}<div class="breadcrumbs"><a href="../../../">Home</a> › <a href="../">%s</a> › %s</div>{%% endif %%}{%% endblock %%}\n' % \
|
||||||
(meta.capfirst(opts.verbose_name_plural), breadcrumb_title))
|
(capfirst(opts.verbose_name_plural), breadcrumb_title))
|
||||||
t.append('{% block content %}<div id="content-main">\n')
|
t.append('{% block content %}<div id="content-main">\n')
|
||||||
if change:
|
if change:
|
||||||
t.append('{% if not is_popup %}')
|
t.append('{% if not is_popup %}')
|
||||||
|
@ -613,12 +613,12 @@ def _get_template(opts, app_label, add=False, change=False, show_delete=False, f
|
||||||
if change and hasattr(rel_obj, 'get_absolute_url'):
|
if change and hasattr(rel_obj, 'get_absolute_url'):
|
||||||
view_on_site = '{%% if %s.original %%}<a href="/r/{{ %s.content_type_id }}/{{ %s.original.id }}/">View on site</a>{%% endif %%}' % (var_name, var_name, var_name)
|
view_on_site = '{%% if %s.original %%}<a href="/r/{{ %s.content_type_id }}/{{ %s.original.id }}/">View on site</a>{%% endif %%}' % (var_name, var_name, var_name)
|
||||||
if rel_field.rel.edit_inline_type == meta.TABULAR:
|
if rel_field.rel.edit_inline_type == meta.TABULAR:
|
||||||
t.append('<h2>%s</h2>\n<table>\n' % meta.capfirst(rel_obj.verbose_name_plural))
|
t.append('<h2>%s</h2>\n<table>\n' % capfirst(rel_obj.verbose_name_plural))
|
||||||
t.append('<thead><tr>')
|
t.append('<thead><tr>')
|
||||||
for f in field_list:
|
for f in field_list:
|
||||||
if isinstance(f, meta.AutoField):
|
if isinstance(f, meta.AutoField):
|
||||||
continue
|
continue
|
||||||
t.append('<th%s>%s</th>' % (f.blank and ' class="optional"' or '', meta.capfirst(f.verbose_name)))
|
t.append('<th%s>%s</th>' % (f.blank and ' class="optional"' or '', capfirst(f.verbose_name)))
|
||||||
t.append('</tr></thead>\n')
|
t.append('</tr></thead>\n')
|
||||||
t.append('{%% for %s in form.%s %%}\n' % (var_name, rel_obj.module_name))
|
t.append('{%% for %s in form.%s %%}\n' % (var_name, rel_obj.module_name))
|
||||||
if change:
|
if change:
|
||||||
|
@ -656,7 +656,7 @@ def _get_template(opts, app_label, add=False, change=False, show_delete=False, f
|
||||||
t.append('{% endfor %}\n')
|
t.append('{% endfor %}\n')
|
||||||
else: # edit_inline_type == STACKED
|
else: # edit_inline_type == STACKED
|
||||||
t.append('{%% for %s in form.%s %%}' % (var_name, rel_obj.module_name))
|
t.append('{%% for %s in form.%s %%}' % (var_name, rel_obj.module_name))
|
||||||
t.append('<h2>%s #{{ forloop.counter }}</h2>' % meta.capfirst(rel_obj.verbose_name))
|
t.append('<h2>%s #{{ forloop.counter }}</h2>' % capfirst(rel_obj.verbose_name))
|
||||||
if view_on_site:
|
if view_on_site:
|
||||||
t.append('<p>%s</p>' % view_on_site)
|
t.append('<p>%s</p>' % view_on_site)
|
||||||
for f in field_list:
|
for f in field_list:
|
||||||
|
@ -710,14 +710,14 @@ def _get_admin_field(field_list, name_prefix, rel, add, change):
|
||||||
# the *left* of the label.
|
# the *left* of the label.
|
||||||
if isinstance(field, meta.BooleanField):
|
if isinstance(field, meta.BooleanField):
|
||||||
t.append(_get_admin_field_form_widget(field, name_prefix, rel, add, change))
|
t.append(_get_admin_field_form_widget(field, name_prefix, rel, add, change))
|
||||||
t.append(' <label for="%s" class="vCheckboxLabel">%s</label>' % (label_name, meta.capfirst(field.verbose_name)))
|
t.append(' <label for="%s" class="vCheckboxLabel">%s</label>' % (label_name, capfirst(field.verbose_name)))
|
||||||
else:
|
else:
|
||||||
class_names = []
|
class_names = []
|
||||||
if not field.blank:
|
if not field.blank:
|
||||||
class_names.append('required')
|
class_names.append('required')
|
||||||
if i > 0:
|
if i > 0:
|
||||||
class_names.append('inline')
|
class_names.append('inline')
|
||||||
t.append('<label for="%s"%s>%s:</label> ' % (label_name, class_names and ' class="%s"' % ' '.join(class_names) or '', meta.capfirst(field.verbose_name)))
|
t.append('<label for="%s"%s>%s:</label> ' % (label_name, class_names and ' class="%s"' % ' '.join(class_names) or '', capfirst(field.verbose_name)))
|
||||||
t.append(_get_admin_field_form_widget(field, name_prefix, rel, add, change))
|
t.append(_get_admin_field_form_widget(field, name_prefix, rel, add, change))
|
||||||
if change and use_raw_id_admin(field):
|
if change and use_raw_id_admin(field):
|
||||||
obj_repr = '%soriginal.get_%s|truncatewords:"14"' % (rel and name_prefix or '', field.rel.name)
|
obj_repr = '%soriginal.get_%s|truncatewords:"14"' % (rel and name_prefix or '', field.rel.name)
|
||||||
|
@ -991,11 +991,11 @@ def _get_deleted_objects(deleted_objects, perms_needed, user, obj, opts, current
|
||||||
if rel_field.rel.edit_inline or not rel_opts.admin:
|
if rel_field.rel.edit_inline or not rel_opts.admin:
|
||||||
# Don't display link to edit, because it either has no
|
# Don't display link to edit, because it either has no
|
||||||
# admin or is edited inline.
|
# admin or is edited inline.
|
||||||
nh(deleted_objects, current_depth, ['%s: %r' % (meta.capfirst(rel_opts.verbose_name), sub_obj), []])
|
nh(deleted_objects, current_depth, ['%s: %r' % (capfirst(rel_opts.verbose_name), sub_obj), []])
|
||||||
else:
|
else:
|
||||||
# Display a link to the admin page.
|
# Display a link to the admin page.
|
||||||
nh(deleted_objects, current_depth, ['%s: <a href="../../../../%s/%s/%s/">%r</a>' % \
|
nh(deleted_objects, current_depth, ['%s: <a href="../../../../%s/%s/%s/">%r</a>' % \
|
||||||
(meta.capfirst(rel_opts.verbose_name), rel_opts.app_label, rel_opts.module_name,
|
(capfirst(rel_opts.verbose_name), rel_opts.app_label, rel_opts.module_name,
|
||||||
getattr(sub_obj, rel_opts.pk.name), sub_obj), []])
|
getattr(sub_obj, rel_opts.pk.name), sub_obj), []])
|
||||||
_get_deleted_objects(deleted_objects, perms_needed, user, sub_obj, rel_opts, current_depth+2)
|
_get_deleted_objects(deleted_objects, perms_needed, user, sub_obj, rel_opts, current_depth+2)
|
||||||
else:
|
else:
|
||||||
|
@ -1005,11 +1005,11 @@ def _get_deleted_objects(deleted_objects, perms_needed, user, obj, opts, current
|
||||||
if rel_field.rel.edit_inline or not rel_opts.admin:
|
if rel_field.rel.edit_inline or not rel_opts.admin:
|
||||||
# Don't display link to edit, because it either has no
|
# Don't display link to edit, because it either has no
|
||||||
# admin or is edited inline.
|
# admin or is edited inline.
|
||||||
nh(deleted_objects, current_depth, ['%s: %s' % (meta.capfirst(rel_opts.verbose_name), strip_tags(repr(sub_obj))), []])
|
nh(deleted_objects, current_depth, ['%s: %s' % (capfirst(rel_opts.verbose_name), strip_tags(repr(sub_obj))), []])
|
||||||
else:
|
else:
|
||||||
# Display a link to the admin page.
|
# Display a link to the admin page.
|
||||||
nh(deleted_objects, current_depth, ['%s: <a href="../../../../%s/%s/%s/">%s</a>' % \
|
nh(deleted_objects, current_depth, ['%s: <a href="../../../../%s/%s/%s/">%s</a>' % \
|
||||||
(meta.capfirst(rel_opts.verbose_name), rel_opts.app_label, rel_opts.module_name, sub_obj.id, strip_tags(repr(sub_obj))), []])
|
(capfirst(rel_opts.verbose_name), rel_opts.app_label, rel_opts.module_name, sub_obj.id, strip_tags(repr(sub_obj))), []])
|
||||||
_get_deleted_objects(deleted_objects, perms_needed, user, sub_obj, rel_opts, current_depth+2)
|
_get_deleted_objects(deleted_objects, perms_needed, user, sub_obj, rel_opts, current_depth+2)
|
||||||
# If there were related objects, and the user doesn't have
|
# If there were related objects, and the user doesn't have
|
||||||
# permission to delete them, add the missing perm to perms_needed.
|
# permission to delete them, add the missing perm to perms_needed.
|
||||||
|
@ -1053,7 +1053,7 @@ def delete_stage(request, app_label, module_name, object_id):
|
||||||
|
|
||||||
# Populate deleted_objects, a data structure of all related objects that
|
# Populate deleted_objects, a data structure of all related objects that
|
||||||
# will also be deleted.
|
# will also be deleted.
|
||||||
deleted_objects = ['%s: <a href="../../%s/">%s</a>' % (meta.capfirst(opts.verbose_name), object_id, strip_tags(repr(obj))), []]
|
deleted_objects = ['%s: <a href="../../%s/">%s</a>' % (capfirst(opts.verbose_name), object_id, strip_tags(repr(obj))), []]
|
||||||
perms_needed = sets.Set()
|
perms_needed = sets.Set()
|
||||||
_get_deleted_objects(deleted_objects, perms_needed, request.user, obj, opts, 1)
|
_get_deleted_objects(deleted_objects, perms_needed, request.user, obj, opts, 1)
|
||||||
|
|
||||||
|
@ -1088,7 +1088,7 @@ def history(request, app_label, module_name, object_id):
|
||||||
c = Context(request, {
|
c = Context(request, {
|
||||||
'title': 'Change history: %r' % obj,
|
'title': 'Change history: %r' % obj,
|
||||||
'action_list': action_list,
|
'action_list': action_list,
|
||||||
'module_name': meta.capfirst(opts.verbose_name_plural),
|
'module_name': capfirst(opts.verbose_name_plural),
|
||||||
'object': obj,
|
'object': obj,
|
||||||
})
|
})
|
||||||
return HttpResponse(t.render(c), mimetype='text/html; charset=utf-8')
|
return HttpResponse(t.render(c), mimetype='text/html; charset=utf-8')
|
||||||
|
|
Loading…
Reference in New Issue