From 4f609faf3f0529655f747ca4aee86c5ae783b845 Mon Sep 17 00:00:00 2001 From: Robert Wittams Date: Sat, 17 Dec 2005 22:31:55 +0000 Subject: [PATCH] magic-removal:Cleanups. Start of revised M2M. git-svn-id: http://code.djangoproject.com/svn/django/branches/magic-removal@1720 bcc190cf-cafb-0310-a4f2-bffc1f526a37 --- django/db/models/base.py | 20 +++++------ django/db/models/fields/related.py | 53 +++++++++++++++++++++++++++--- django/db/models/manipulators.py | 9 +++-- django/db/models/options.py | 4 +++ 4 files changed, 66 insertions(+), 20 deletions(-) diff --git a/django/db/models/base.py b/django/db/models/base.py index c59d119973..e3712f645e 100644 --- a/django/db/models/base.py +++ b/django/db/models/base.py @@ -27,7 +27,6 @@ get_module_name = lambda class_name: class_name.lower() + 's' get_verbose_name = lambda class_name: re.sub('([A-Z])', ' \\1', class_name).lower().strip() - class ModelBase(type): "Metaclass for all models" def __new__(cls, name, bases, attrs): @@ -42,7 +41,7 @@ class ModelBase(type): except KeyError: meta_attrs = {} - # Create the class, because we need it to use in currying. + # Create the class, we need to add the options to it. new_class = type.__new__(cls, name, bases, { '__module__' : attrs.pop('__module__') }) opts = Options( @@ -82,15 +81,10 @@ class ModelBase(type): opts.app_label = app_label #Add all attributes to the class - #fields, managers = [], [] for obj_name, obj in attrs.items(): new_class.add_to_class(obj_name, obj) - if not hasattr(new_class, '_default_manager'): - # Create the default manager, if needed. - if hasattr(new_class, 'objects'): - raise ValueError, "Model %s must specify a custom Manager, because it has a field named 'objects'" % name - new_class.add_to_class('objects', Manager()) + # Give the class a docstring -- its definition. if new_class.__doc__ is None: @@ -102,9 +96,7 @@ class ModelBase(type): 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) @@ -175,6 +167,12 @@ class Model(object): dispatcher.send( signal = Signals.post_init, sender = self.__class__, instance=self) def _prepare(cls): + if not hasattr(cls, '_default_manager'): + # Create the default manager, if needed. + if hasattr(cls, 'objects'): + raise ValueError, "Model %s must specify a custom Manager, because it has a field named 'objects'" % name + cls.add_to_class('objects', Manager()) + cls.add_to_class( 'AddManipulator', ModelAddManipulator) cls.add_to_class( 'ChangeManipulator', ModelChangeManipulator) diff --git a/django/db/models/fields/related.py b/django/db/models/fields/related.py index a57e0041bb..8873cd503a 100644 --- a/django/db/models/fields/related.py +++ b/django/db/models/fields/related.py @@ -37,9 +37,10 @@ class RelatedField(object): do_pending_lookups = classmethod(do_pending_lookups) - def contribute_to_class(self, cls, name): - Field.contribute_to_class(self,cls,name) + sup = super(RelatedField,self) + if hasattr(sup, 'contribute_to_class'): + sup.contribute_to_class(cls,name) other = self.rel.to if isinstance(other, basestring): if other == RECURSIVE_RELATIONSHIP_CONSTANT: @@ -206,7 +207,7 @@ class OneToOneField(SharedMethods, IntegerField): class ManyToManyField(RelatedField,Field): def __init__(self, to, **kwargs): - kwargs['verbose_name'] = kwargs.get('verbose_name', to._meta.verbose_name_plural) + kwargs['verbose_name'] = kwargs.get('verbose_name', None) kwargs['rel'] = ManyToMany(to, kwargs.pop('singular', None), num_in_admin=kwargs.pop('num_in_admin', 0), related_name=kwargs.pop('related_name', None), @@ -292,9 +293,53 @@ class ManyToManyField(RelatedField,Field): func.alters_data = True setattr(cls, 'set_%s' % related.opts.module_name, func) + self.rel.singular = self.rel.singular or self.rel.to._meta.object_name.lower() + def set_attributes_from_rel(self): pass +class ManyToManyFieldNew(RelatedField): + def __init__(self, to, **kwargs): + self.to = to + self.from_ = None + self.rel = self + self.edit_inline = False + + def set_attributes_from_rel(self): + pass + + def contribute_to_class(self, cls, name): + self.from_ = cls + self.name = name + super(ManyToManyFieldNew, self).contribute_to_class(cls, name) + + + def contribute_to_related_class(self, cls, name): + #Now we know both classes exist. + self.to = cls + # We need to wait until the class we were in was fully defined + dispatcher.connect( + self.from_prepared, + signal = Signals.class_prepared, + sender = self.from_ + ) + + def from_prepared(self): + from django.db.models.base import Model + + class M2M(Model): + __module__ = self.from_.__module__ + + id_to = self.from_._meta.db_table + id_from = self.to._meta.db_table + + M2M.add_to_class(id_from, ForeignKey(to=self.from_) ) + M2M.add_to_class(id_to, ForeignKey(to=self.to) ) + M2M._meta.db_table = '%s_%s' % (self.from_._meta.db_table, self.name) + M2M._meta.unique_together = ((id_to, id_from),) + M2M.__name__ = "M2M_%s_%s_%s" % (self.name,self.from_.__name__, self.to.__name__) + + class ManyToOne: 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, @@ -331,7 +376,7 @@ class ManyToMany: def __init__(self, to, singular=None, num_in_admin=0, related_name=None, filter_interface=None, limit_choices_to=None, raw_id_admin=False): self.to = to - self.singular = singular or to._meta.object_name.lower() + self.singular = singular or None self.num_in_admin = num_in_admin self.related_name = related_name self.filter_interface = filter_interface diff --git a/django/db/models/manipulators.py b/django/db/models/manipulators.py index 76120d6621..629736a850 100644 --- a/django/db/models/manipulators.py +++ b/django/db/models/manipulators.py @@ -13,9 +13,11 @@ class ManipulatorDescriptor(object): def __get__(self, instance, type=None): if instance != None: - raise "Manipulator accessed via instance" + raise "Manipulator can not be accessed via instance" else: if not self.man: + # Create a class which inherits from the MANIPULATOR class given in the class, + # and the appropriate automatic manipulator, class Man(self.get_base_manipulator(type), self.base): pass @@ -25,6 +27,7 @@ class ManipulatorDescriptor(object): return self.man def get_base_manipulator(self, type): + if hasattr(type, 'MANIPULATOR'): man = type.MANIPULATOR else: @@ -60,17 +63,13 @@ class AutomaticManipulator(Manipulator): if self.follow.get(f.name, False): self.fields.extend(f.get_manipulator_fields(self.opts, self, self.change)) - # Add fields for related objects. for f in self.opts.get_all_related_objects(): if self.follow.get(f.name, False): - print f.name fol = self.follow[f.name] fields = f.get_manipulator_fields(self.opts, self, self.change, fol) - print fields self.fields.extend(fields) - def save(self, new_data): add, change, opts, klass = self.add, self.change, self.opts, self.model # TODO: big cleanup when core fields go -> use recursive manipulators. diff --git a/django/db/models/options.py b/django/db/models/options.py index 96867923c1..b891ca1be8 100644 --- a/django/db/models/options.py +++ b/django/db/models/options.py @@ -71,6 +71,10 @@ class Options: self.has_auto_field = True #HACK self.limit_choices_to = {} + + # If the db_table wasn't provided, use the app_label + module_name. + if not self.db_table: + self.db_table = "%s_%s" % (self.app_label, self.module_name) def add_field(self, field): # Insert the fields in the order that they were created. The