Refactored metaclass in preparation for descriptor fields
git-svn-id: http://code.djangoproject.com/svn/django/branches/magic-removal@1701 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
43b41a7565
commit
f4dfb99f45
|
@ -17,7 +17,6 @@ from django.db.models.fields.related import *
|
||||||
from django.core.exceptions import ObjectDoesNotExist
|
from django.core.exceptions import ObjectDoesNotExist
|
||||||
from django.db.models.exceptions import FieldDoesNotExist, BadKeywordArguments
|
from django.db.models.exceptions import FieldDoesNotExist, BadKeywordArguments
|
||||||
|
|
||||||
|
|
||||||
# Admin stages.
|
# Admin stages.
|
||||||
ADD, CHANGE, BOTH = 1, 2, 3
|
ADD, CHANGE, BOTH = 1, 2, 3
|
||||||
|
|
||||||
|
@ -28,7 +27,6 @@ ADD, CHANGE, BOTH = 1, 2, 3
|
||||||
#def get_app(app_label):
|
#def get_app(app_label):
|
||||||
# return __import__('%s.%s' % (MODEL_PREFIX, app_label), '', '', [''])
|
# return __import__('%s.%s' % (MODEL_PREFIX, app_label), '', '', [''])
|
||||||
|
|
||||||
|
|
||||||
class LazyDate:
|
class LazyDate:
|
||||||
"""
|
"""
|
||||||
Use in limit_choices_to to compare the field to dates calculated at run time
|
Use in limit_choices_to to compare the field to dates calculated at run time
|
||||||
|
@ -50,11 +48,6 @@ class LazyDate:
|
||||||
def __get_value__(self):
|
def __get_value__(self):
|
||||||
return datetime.datetime.now() + self.delta
|
return datetime.datetime.now() + self.delta
|
||||||
|
|
||||||
################
|
|
||||||
# MAIN CLASSES #
|
|
||||||
################
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
from django.db.models.manipulators import ManipulatorDescriptor, ModelAddManipulator, ModelChangeManipulator
|
from django.db.models.manipulators import ManipulatorDescriptor, ModelAddManipulator, ModelChangeManipulator
|
||||||
from django.db.models.fields import Field, DateField, FileField, ImageField, AutoField
|
from django.db.models.fields import Field, DateField, FileField, ImageField, AutoField
|
||||||
from django.db.models.fields.related import OneToOne, ManyToOne, ManyToMany, RECURSIVE_RELATIONSHIP_CONSTANT
|
from django.db.models.fields.related import RelatedField, OneToOne, ManyToOne, ManyToMany, RECURSIVE_RELATIONSHIP_CONSTANT
|
||||||
from django.db.models.related import RelatedObject
|
from django.db.models.related import RelatedObject
|
||||||
from django.db.models.manager import Manager, ManagerDescriptor
|
from django.db.models.manager import Manager, ManagerDescriptor
|
||||||
from django.db.models.query import orderlist2sql
|
from django.db.models.query import orderlist2sql
|
||||||
|
@ -36,23 +36,9 @@ class ModelBase(type):
|
||||||
except KeyError:
|
except KeyError:
|
||||||
meta_attrs = {}
|
meta_attrs = {}
|
||||||
|
|
||||||
# Gather all attributes that are Field or Manager instances.
|
# Create the class, because we need it to use in currying.
|
||||||
fields, managers = [], []
|
new_class = type.__new__(cls, name, bases, { '__module__' : attrs.pop('__module__') })
|
||||||
for obj_name, obj in attrs.items():
|
|
||||||
if isinstance(obj, Field):
|
|
||||||
obj.set_name(obj_name)
|
|
||||||
fields.append(obj)
|
|
||||||
del attrs[obj_name]
|
|
||||||
elif isinstance(obj, Manager):
|
|
||||||
managers.append((obj_name, obj))
|
|
||||||
del attrs[obj_name]
|
|
||||||
|
|
||||||
# Sort the fields and managers in the order that they were created. The
|
|
||||||
# "creation_counter" is needed because metaclasses don't preserve the
|
|
||||||
# attribute order.
|
|
||||||
fields.sort(lambda x, y: x.creation_counter - y.creation_counter)
|
|
||||||
managers.sort(lambda x, y: x[1].creation_counter - y[1].creation_counter)
|
|
||||||
|
|
||||||
opts = Options(
|
opts = Options(
|
||||||
module_name = meta_attrs.pop('module_name', get_module_name(name)),
|
module_name = meta_attrs.pop('module_name', get_module_name(name)),
|
||||||
# If the verbose_name wasn't given, use the class name,
|
# If the verbose_name wasn't given, use the class name,
|
||||||
|
@ -60,7 +46,6 @@ class ModelBase(type):
|
||||||
verbose_name = meta_attrs.pop('verbose_name', get_verbose_name(name)),
|
verbose_name = meta_attrs.pop('verbose_name', get_verbose_name(name)),
|
||||||
verbose_name_plural = meta_attrs.pop('verbose_name_plural', ''),
|
verbose_name_plural = meta_attrs.pop('verbose_name_plural', ''),
|
||||||
db_table = meta_attrs.pop('db_table', ''),
|
db_table = meta_attrs.pop('db_table', ''),
|
||||||
fields = fields,
|
|
||||||
ordering = meta_attrs.pop('ordering', None),
|
ordering = meta_attrs.pop('ordering', None),
|
||||||
unique_together = meta_attrs.pop('unique_together', None),
|
unique_together = meta_attrs.pop('unique_together', None),
|
||||||
admin = meta_attrs.pop('admin', None),
|
admin = meta_attrs.pop('admin', None),
|
||||||
|
@ -76,38 +61,24 @@ class ModelBase(type):
|
||||||
|
|
||||||
if meta_attrs != {}:
|
if meta_attrs != {}:
|
||||||
raise TypeError, "'class META' got invalid attribute(s): %s" % ','.join(meta_attrs.keys())
|
raise TypeError, "'class META' got invalid attribute(s): %s" % ','.join(meta_attrs.keys())
|
||||||
|
new_class.add_to_class('_meta', opts)
|
||||||
|
|
||||||
# Create the DoesNotExist exception.
|
# Create the DoesNotExist exception.
|
||||||
attrs['DoesNotExist'] = types.ClassType('DoesNotExist', (ObjectDoesNotExist,), {})
|
new_class.DoesNotExist = types.ClassType('DoesNotExist', (ObjectDoesNotExist,), {})
|
||||||
|
|
||||||
# Create the class, because we need it to use in currying.
|
|
||||||
new_class = type.__new__(cls, name, bases, attrs)
|
|
||||||
|
|
||||||
# Give the class a docstring -- its definition.
|
|
||||||
if new_class.__doc__ is None:
|
|
||||||
new_class.__doc__ = "%s.%s(%s)" % (opts.module_name, name, ", ".join([f.name for f in opts.fields]))
|
|
||||||
|
|
||||||
if hasattr(new_class, 'get_absolute_url'):
|
|
||||||
new_class.get_absolute_url = curry(get_absolute_url, opts, new_class.get_absolute_url)
|
|
||||||
|
|
||||||
# Figure out the app_label by looking one level up.
|
# Figure out the app_label by looking one level up.
|
||||||
|
#FIXME: wrong for nested model modules
|
||||||
app_package = sys.modules.get(new_class.__module__)
|
app_package = sys.modules.get(new_class.__module__)
|
||||||
app_label = app_package.__name__.replace('.models', '')
|
app_label = app_package.__name__.replace('.models', '')
|
||||||
app_label = app_label[app_label.rfind('.')+1:]
|
app_label = app_label[app_label.rfind('.')+1:]
|
||||||
|
|
||||||
# Populate the _MODELS member on the module the class is in.
|
|
||||||
app_package.__dict__.setdefault('_MODELS', []).append(new_class)
|
|
||||||
|
|
||||||
# Cache the app label.
|
# Cache the app label.
|
||||||
opts.app_label = app_label
|
opts.app_label = app_label
|
||||||
|
|
||||||
# If the db_table wasn't provided, use the app_label + module_name.
|
#Add all attributes to the class
|
||||||
if not opts.db_table:
|
#fields, managers = [], []
|
||||||
opts.db_table = "%s_%s" % (app_label, opts.module_name)
|
for obj_name, obj in attrs.items():
|
||||||
new_class._meta = opts
|
new_class.add_to_class(obj_name, obj)
|
||||||
|
|
||||||
for m_name, m in managers:
|
|
||||||
new_class.add_to_class(m_name, m)
|
|
||||||
|
|
||||||
if not hasattr(new_class, '_default_manager'):
|
if not hasattr(new_class, '_default_manager'):
|
||||||
# Create the default manager, if needed.
|
# Create the default manager, if needed.
|
||||||
|
@ -115,18 +86,25 @@ class ModelBase(type):
|
||||||
raise ValueError, "Model %s must specify a custom Manager, because it has a field named 'objects'" % name
|
raise ValueError, "Model %s must specify a custom Manager, because it has a field named 'objects'" % name
|
||||||
new_class.add_to_class('objects', Manager())
|
new_class.add_to_class('objects', Manager())
|
||||||
|
|
||||||
new_class._prepare()
|
|
||||||
|
|
||||||
for field in fields:
|
|
||||||
if field.rel:
|
|
||||||
other = field.rel.to
|
|
||||||
if isinstance(other, basestring):
|
|
||||||
print "string lookup"
|
|
||||||
else:
|
|
||||||
related = RelatedObject(other._meta, new_class, field)
|
|
||||||
field.contribute_to_related_class(other, related)
|
|
||||||
|
|
||||||
|
|
||||||
|
# Give the class a docstring -- its definition.
|
||||||
|
if new_class.__doc__ is None:
|
||||||
|
new_class.__doc__ = "%s.%s(%s)" % (opts.module_name, name, ", ".join([f.name for f in opts.fields]))
|
||||||
|
|
||||||
|
if hasattr(new_class, 'get_absolute_url'):
|
||||||
|
new_class.get_absolute_url = curry(get_absolute_url, opts, new_class.get_absolute_url)
|
||||||
|
|
||||||
|
opts._prepare()
|
||||||
|
new_class._prepare()
|
||||||
|
|
||||||
|
# If the db_table wasn't provided, use the app_label + module_name.
|
||||||
|
if not opts.db_table:
|
||||||
|
opts.db_table = "%s_%s" % (app_label, opts.module_name)
|
||||||
|
|
||||||
|
# Populate the _MODELS member on the module the class is in.
|
||||||
|
app_package.__dict__.setdefault('_MODELS', []).append(new_class)
|
||||||
|
|
||||||
|
|
||||||
return new_class
|
return new_class
|
||||||
|
|
||||||
|
|
||||||
|
@ -207,13 +185,6 @@ class Model(object):
|
||||||
if not f.height_field:
|
if not f.height_field:
|
||||||
setattr(cls, 'get_%s_height' % f.name, curry(cls.__get_FIELD_height, field=f))
|
setattr(cls, 'get_%s_height' % f.name, curry(cls.__get_FIELD_height, field=f))
|
||||||
|
|
||||||
# If the object has a relationship to itself, as designated by
|
|
||||||
# RECURSIVE_RELATIONSHIP_CONSTANT, create that relationship formally.
|
|
||||||
if f.rel and f.rel.to == RECURSIVE_RELATIONSHIP_CONSTANT:
|
|
||||||
f.rel.to = cls
|
|
||||||
f.name = f.name or (f.rel.to._meta.object_name.lower() + '_' + f.rel.to._meta.pk.name)
|
|
||||||
f.verbose_name = f.verbose_name or f.rel.to._meta.verbose_name
|
|
||||||
f.rel.field_name = f.rel.field_name or f.rel.to._meta.pk.name
|
|
||||||
|
|
||||||
# Add methods for many-to-one related objects.
|
# Add methods for many-to-one related objects.
|
||||||
# EXAMPLES: Choice.get_poll(), Story.get_dateline()
|
# EXAMPLES: Choice.get_poll(), Story.get_dateline()
|
||||||
|
@ -233,6 +204,8 @@ class Model(object):
|
||||||
if cls._meta.order_with_respect_to:
|
if cls._meta.order_with_respect_to:
|
||||||
cls.get_next_in_order = curry(cls.__get_next_or_previous_in_order, is_next=True)
|
cls.get_next_in_order = curry(cls.__get_next_or_previous_in_order, is_next=True)
|
||||||
cls.get_previous_in_order = curry(cls.__get_next_or_previous_in_order, is_next=False)
|
cls.get_previous_in_order = curry(cls.__get_next_or_previous_in_order, is_next=False)
|
||||||
|
|
||||||
|
RelatedField.do_pending_lookups(cls)
|
||||||
|
|
||||||
_prepare = classmethod(_prepare)
|
_prepare = classmethod(_prepare)
|
||||||
|
|
||||||
|
|
|
@ -88,7 +88,7 @@ class Field(object):
|
||||||
|
|
||||||
# Tracks each time a Field instance is created. Used to retain order.
|
# Tracks each time a Field instance is created. Used to retain order.
|
||||||
creation_counter = 0
|
creation_counter = 0
|
||||||
|
|
||||||
def __init__(self, verbose_name=None, name=None, primary_key=False,
|
def __init__(self, verbose_name=None, name=None, primary_key=False,
|
||||||
maxlength=None, unique=False, blank=False, null=False, db_index=False,
|
maxlength=None, unique=False, blank=False, null=False, db_index=False,
|
||||||
core=False, rel=None, default=NOT_PROVIDED, editable=True,
|
core=False, rel=None, default=NOT_PROVIDED, editable=True,
|
||||||
|
@ -96,7 +96,8 @@ class Field(object):
|
||||||
unique_for_year=None, validator_list=None, choices=None, radio_admin=None,
|
unique_for_year=None, validator_list=None, choices=None, radio_admin=None,
|
||||||
help_text='', db_column=None):
|
help_text='', db_column=None):
|
||||||
self.name = name
|
self.name = name
|
||||||
self.verbose_name = verbose_name or (name and name.replace('_', ' '))
|
self.verbose_name = verbose_name
|
||||||
|
|
||||||
self.primary_key = primary_key
|
self.primary_key = primary_key
|
||||||
self.maxlength, self.unique = maxlength, unique
|
self.maxlength, self.unique = maxlength, unique
|
||||||
self.blank, self.null = blank, null
|
self.blank, self.null = blank, null
|
||||||
|
@ -110,16 +111,23 @@ class Field(object):
|
||||||
self.radio_admin = radio_admin
|
self.radio_admin = radio_admin
|
||||||
self.help_text = help_text
|
self.help_text = help_text
|
||||||
self.db_column = db_column
|
self.db_column = db_column
|
||||||
|
|
||||||
# Set db_index to True if the field has a relationship and doesn't explicitly set db_index.
|
|
||||||
|
|
||||||
|
# Set db_index to True if the field has a relationship and doesn't explicitly set db_index.
|
||||||
self.db_index = db_index
|
self.db_index = db_index
|
||||||
|
|
||||||
# Increase the creation counter, and save our local copy.
|
# Increase the creation counter, and save our local copy.
|
||||||
self.creation_counter = Field.creation_counter
|
self.creation_counter = Field.creation_counter
|
||||||
Field.creation_counter += 1
|
Field.creation_counter += 1
|
||||||
|
|
||||||
|
|
||||||
|
def __cmp__(self,other ):
|
||||||
|
#This is because bisect does not take a comparison function. grrr.
|
||||||
|
return cmp(self.creation_counter, other.creation_counter)
|
||||||
|
|
||||||
|
def contribute_to_class(self, cls, name):
|
||||||
|
self.name = name
|
||||||
self.attname, self.column = self.get_attname_column()
|
self.attname, self.column = self.get_attname_column()
|
||||||
|
self.verbose_name = self.verbose_name or (name and name.replace('_', ' '))
|
||||||
|
cls._meta.add_field(self)
|
||||||
|
|
||||||
def set_name(self, name):
|
def set_name(self, name):
|
||||||
self.name = name
|
self.name = name
|
||||||
|
|
|
@ -1,21 +1,63 @@
|
||||||
from django.db.models.fields import Field, IntegerField
|
from django.db.models.fields import Field, IntegerField
|
||||||
|
from django.db.models.related import RelatedObject
|
||||||
from django.utils.translation import gettext_lazy, string_concat
|
from django.utils.translation import gettext_lazy, string_concat
|
||||||
from django.utils.functional import curry
|
from django.utils.functional import curry
|
||||||
from django.core import formfields
|
from django.core import formfields
|
||||||
|
|
||||||
|
|
||||||
# Values for Relation.edit_inline.
|
# Values for Relation.edit_inline.
|
||||||
TABULAR, STACKED = 1, 2
|
TABULAR, STACKED = 1, 2
|
||||||
|
|
||||||
RECURSIVE_RELATIONSHIP_CONSTANT = 'self'
|
RECURSIVE_RELATIONSHIP_CONSTANT = 'self'
|
||||||
|
|
||||||
|
#HACK
|
||||||
|
class RelatedField(object):
|
||||||
|
pending_lookups = {}
|
||||||
|
|
||||||
|
def add_lookup(cls, rel_cls, field):
|
||||||
|
name = field.rel.to
|
||||||
|
module = rel_cls.__module__
|
||||||
|
key = (module, name)
|
||||||
|
cls.pending_lookups.setdefault(key,[]).append( (rel_cls, field) )
|
||||||
|
add_lookup = classmethod(add_lookup)
|
||||||
|
|
||||||
|
def do_pending_lookups(cls, other_cls):
|
||||||
|
key = (other_cls.__module__, other_cls.__name__)
|
||||||
|
for (rel_cls,field) in cls.pending_lookups.setdefault(key,[]):
|
||||||
|
field.rel.to = other_cls
|
||||||
|
field.do_related_class(other_cls, rel_cls)
|
||||||
|
do_pending_lookups = classmethod(do_pending_lookups)
|
||||||
|
|
||||||
|
def contribute_to_class(self, cls, name):
|
||||||
|
Field.contribute_to_class(self,cls,name)
|
||||||
|
other = self.rel.to
|
||||||
|
if isinstance(other, basestring):
|
||||||
|
if other == RECURSIVE_RELATIONSHIP_CONSTANT:
|
||||||
|
self.rel.to = cls.__name__
|
||||||
|
self.add_lookup(cls, self)
|
||||||
|
else:
|
||||||
|
self.do_related_class(other, cls)
|
||||||
|
|
||||||
|
def set_attributes_from_rel(self):
|
||||||
|
self.name = self.name or (self.rel.to._meta.object_name.lower() + '_' + self.rel.to._meta.pk.name)
|
||||||
|
self.verbose_name = self.verbose_name or self.rel.to._meta.verbose_name
|
||||||
|
self.rel.field_name = self.rel.field_name or self.rel.to._meta.pk.name
|
||||||
|
|
||||||
|
def do_related_class(self, other, cls):
|
||||||
|
self.set_attributes_from_rel()
|
||||||
|
related = RelatedObject(other._meta, cls, self)
|
||||||
|
self.contribute_to_related_class(other, related)
|
||||||
|
|
||||||
|
|
||||||
#HACK
|
#HACK
|
||||||
class SharedMethods(object):
|
class SharedMethods(RelatedField):
|
||||||
def get_attname(self):
|
def get_attname(self):
|
||||||
return '%s_id' % self.name
|
return '%s_id' % self.name
|
||||||
|
|
||||||
def get_validator_unique_lookup_type(self):
|
def get_validator_unique_lookup_type(self):
|
||||||
return '%s__%s__exact' % (self.name, self.rel.get_related_field().name)
|
return '%s__%s__exact' % (self.name, self.rel.get_related_field().name)
|
||||||
|
|
||||||
|
|
||||||
class ForeignKey(SharedMethods,Field):
|
class ForeignKey(SharedMethods,Field):
|
||||||
empty_strings_allowed = False
|
empty_strings_allowed = False
|
||||||
def __init__(self, to, to_field=None, **kwargs):
|
def __init__(self, to, to_field=None, **kwargs):
|
||||||
|
@ -98,7 +140,6 @@ class ForeignKey(SharedMethods,Field):
|
||||||
|
|
||||||
def contribute_to_related_class(self, cls, related):
|
def contribute_to_related_class(self, cls, related):
|
||||||
rel_obj_name = related.get_method_name_part()
|
rel_obj_name = related.get_method_name_part()
|
||||||
|
|
||||||
# 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()
|
||||||
setattr(cls, 'get_%s' % rel_obj_name, curry(cls._get_related, method_name='get_object', rel_class=related.model, rel_field=related.field))
|
setattr(cls, 'get_%s' % rel_obj_name, curry(cls._get_related, method_name='get_object', rel_class=related.model, rel_field=related.field))
|
||||||
|
@ -147,7 +188,7 @@ class OneToOneField(SharedMethods, IntegerField):
|
||||||
rel_class=related.model, rel_field=related.field))
|
rel_class=related.model, rel_field=related.field))
|
||||||
|
|
||||||
|
|
||||||
class ManyToManyField(Field):
|
class ManyToManyField(RelatedField,Field):
|
||||||
def __init__(self, to, **kwargs):
|
def __init__(self, to, **kwargs):
|
||||||
kwargs['verbose_name'] = kwargs.get('verbose_name', to._meta.verbose_name_plural)
|
kwargs['verbose_name'] = kwargs.get('verbose_name', to._meta.verbose_name_plural)
|
||||||
kwargs['rel'] = ManyToMany(to, kwargs.pop('singular', None),
|
kwargs['rel'] = ManyToMany(to, kwargs.pop('singular', None),
|
||||||
|
@ -225,6 +266,9 @@ class ManyToManyField(Field):
|
||||||
func.alters_data = True
|
func.alters_data = True
|
||||||
setattr(cls, 'set_%s' % related.opts.module_name, func)
|
setattr(cls, 'set_%s' % related.opts.module_name, func)
|
||||||
|
|
||||||
|
def set_attributes_from_rel(self):
|
||||||
|
pass
|
||||||
|
|
||||||
class ManyToOne:
|
class ManyToOne:
|
||||||
def __init__(self, to, field_name, num_in_admin=3, min_num_in_admin=None,
|
def __init__(self, to, field_name, num_in_admin=3, min_num_in_admin=None,
|
||||||
max_num_in_admin=None, num_extra_on_change=1, edit_inline=False,
|
max_num_in_admin=None, num_extra_on_change=1, edit_inline=False,
|
||||||
|
|
|
@ -5,19 +5,17 @@ from django.db.models.loading import get_installed_model_modules
|
||||||
from django.db.models.query import orderlist2sql
|
from django.db.models.query import orderlist2sql
|
||||||
from django.db.models.exceptions import FieldDoesNotExist
|
from django.db.models.exceptions import FieldDoesNotExist
|
||||||
|
|
||||||
|
from bisect import bisect
|
||||||
|
|
||||||
class Options:
|
class Options:
|
||||||
def __init__(self, module_name='', verbose_name='', verbose_name_plural='', db_table='',
|
def __init__(self, module_name='', verbose_name='', verbose_name_plural='', db_table='',
|
||||||
fields=None, ordering=None, unique_together=None, admin=None,
|
ordering=None, unique_together=None, admin=None,
|
||||||
where_constraints=None, object_name=None, app_label=None,
|
where_constraints=None, object_name=None, app_label=None,
|
||||||
exceptions=None, permissions=None, get_latest_by=None,
|
exceptions=None, permissions=None, get_latest_by=None,
|
||||||
order_with_respect_to=None, module_constants=None):
|
order_with_respect_to=None, module_constants=None):
|
||||||
# Move many-to-many related fields from self.fields into self.many_to_many.
|
# Move many-to-many related fields from self.fields into self.many_to_many.
|
||||||
self.fields, self.many_to_many = [], []
|
self.fields, self.many_to_many = [], []
|
||||||
for field in (fields or []):
|
|
||||||
if field.rel and isinstance(field.rel, ManyToMany):
|
|
||||||
self.many_to_many.append(field)
|
|
||||||
else:
|
|
||||||
self.fields.append(field)
|
|
||||||
self.module_name, self.verbose_name = module_name, verbose_name
|
self.module_name, self.verbose_name = module_name, verbose_name
|
||||||
self.verbose_name_plural = verbose_name_plural or verbose_name + 's'
|
self.verbose_name_plural = verbose_name_plural or verbose_name + 's'
|
||||||
self.db_table = db_table
|
self.db_table = db_table
|
||||||
|
@ -28,14 +26,22 @@ class Options:
|
||||||
self.permissions = permissions or []
|
self.permissions = permissions or []
|
||||||
self.object_name, self.app_label = object_name, app_label
|
self.object_name, self.app_label = object_name, app_label
|
||||||
self.get_latest_by = get_latest_by
|
self.get_latest_by = get_latest_by
|
||||||
if order_with_respect_to:
|
self.order_with_respect_to = order_with_respect_to
|
||||||
|
|
||||||
|
self.module_constants = module_constants or {}
|
||||||
|
self.admin = admin
|
||||||
|
|
||||||
|
def contribute_to_class(self, cls, name):
|
||||||
|
self.model = cls
|
||||||
|
cls._meta = self
|
||||||
|
|
||||||
|
def _prepare(self):
|
||||||
|
if self.order_with_respect_to:
|
||||||
self.order_with_respect_to = self.get_field(order_with_respect_to)
|
self.order_with_respect_to = self.get_field(order_with_respect_to)
|
||||||
self.ordering = ('_order',)
|
self.ordering = ('_order',)
|
||||||
else:
|
else:
|
||||||
self.order_with_respect_to = None
|
self.order_with_respect_to = None
|
||||||
self.module_constants = module_constants or {}
|
|
||||||
self.admin = admin
|
|
||||||
|
|
||||||
# Calculate one_to_one_field.
|
# Calculate one_to_one_field.
|
||||||
self.one_to_one_field = None
|
self.one_to_one_field = None
|
||||||
for f in self.fields:
|
for f in self.fields:
|
||||||
|
@ -51,7 +57,9 @@ class Options:
|
||||||
# If a primary_key field hasn't been specified, add an
|
# If a primary_key field hasn't been specified, add an
|
||||||
# auto-incrementing primary-key ID field automatically.
|
# auto-incrementing primary-key ID field automatically.
|
||||||
if self.pk is None:
|
if self.pk is None:
|
||||||
self.fields.insert(0, AutoField(name='id', verbose_name='ID', primary_key=True))
|
auto = AutoField(verbose_name='ID', primary_key=True)
|
||||||
|
auto.creation_counter = -1
|
||||||
|
self.model.add_to_class('id', auto)
|
||||||
self.pk = self.fields[0]
|
self.pk = self.fields[0]
|
||||||
# Cache whether this has an AutoField.
|
# Cache whether this has an AutoField.
|
||||||
self.has_auto_field = False
|
self.has_auto_field = False
|
||||||
|
@ -64,6 +72,15 @@ class Options:
|
||||||
#HACK
|
#HACK
|
||||||
self.limit_choices_to = {}
|
self.limit_choices_to = {}
|
||||||
|
|
||||||
|
def add_field(self, field):
|
||||||
|
# Insert the fields in the order that they were created. The
|
||||||
|
# "creation_counter" is needed because metaclasses don't preserve the
|
||||||
|
# attribute order.
|
||||||
|
if field.rel and isinstance(field.rel, ManyToMany):
|
||||||
|
self.many_to_many.insert(bisect(self.many_to_many, field), field)
|
||||||
|
else:
|
||||||
|
self.fields.insert(bisect(self.fields,field),field)
|
||||||
|
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return '<Options for %s>' % self.module_name
|
return '<Options for %s>' % self.module_name
|
||||||
|
|
Loading…
Reference in New Issue