1 from django
.db
import connection
, transaction
2 from django
.db
.models
import signals
, get_model
3 from django
.db
.models
.fields
import AutoField
, Field
, IntegerField
, PositiveIntegerField
, PositiveSmallIntegerField
, get_ul_class
4 from django
.db
.models
.related
import RelatedObject
5 from django
.db
.models
.query_utils
import QueryWrapper
6 from django
.utils
.text
import capfirst
7 from django
.utils
.translation
import ugettext_lazy
, string_concat
, ungettext
, ugettext
as _
8 from django
.utils
.functional
import curry
9 from django
.utils
.encoding
import smart_unicode
10 from django
.core
import validators
11 from django
import oldforms
12 from django
import newforms
as forms
13 from django
.dispatch
import dispatcher
18 from sets
import Set
as set # Python 2.3 fallback
20 # Values for Relation.edit_inline.
21 TABULAR
, STACKED
= 1, 2
23 RECURSIVE_RELATIONSHIP_CONSTANT
= 'self'
27 def add_lazy_relation(cls
, field
, relation
):
29 Adds a lookup on ``cls`` when a related field is defined using a string,
33 fk = ForeignKey("AnotherModel")
37 * RECURSIVE_RELATIONSHIP_CONSTANT (i.e. "self") to indicate a recursive
40 * The name of a model (i.e "AnotherModel") to indicate another model in
43 * An app-label and model name (i.e. "someapp.AnotherModel") to indicate
44 another model in a different app.
46 If the other model hasn't yet been loaded -- almost a given if you're using
47 lazy relationships -- then the relation won't be set up until the
48 class_prepared signal fires at the end of model initialization.
50 # Check for recursive relations
51 if relation
== RECURSIVE_RELATIONSHIP_CONSTANT
:
52 app_label
= cls
._meta
.app_label
53 model_name
= cls
.__name
__
56 # Look for an "app.Model" relation
58 app_label
, model_name
= relation
.split(".")
60 # If we can't split, assume a model in current app
61 app_label
= cls
._meta
.app_label
64 # Try to look up the related model, and if it's already loaded resolve the
65 # string right away. If get_model returns None, it means that the related
66 # model isn't loaded yet, so we need to pend the relation until the class
68 model
= get_model(app_label
, model_name
, False)
71 field
.do_related_class(model
, cls
)
73 key
= (app_label
, model_name
)
75 pending_lookups
.setdefault(key
, []).append(value
)
77 def do_pending_lookups(sender
):
79 Handle any pending relations to the sending model. Sent from class_prepared.
81 key
= (sender
._meta
.app_label
, sender
.__name
__)
82 for cls
, field
in pending_lookups
.pop(key
, []):
84 field
.do_related_class(sender
, cls
)
86 dispatcher
.connect(do_pending_lookups
, signal
=signals
.class_prepared
)
88 def manipulator_valid_rel_key(f
, self
, field_data
, all_data
):
89 "Validates that the value is a valid foreign key"
92 klass
._default
_manager
.get(**{f
.rel
.field_name
: field_data
})
93 except klass
.DoesNotExist
:
94 raise validators
.ValidationError
, _("Please enter a valid %s.") % f
.verbose_name
97 class RelatedField(object):
98 def contribute_to_class(self
, cls
, name
):
99 sup
= super(RelatedField
, self
)
101 # Add an accessor to allow easy determination of the related query path for this field
102 self
.related_query_name
= curry(self
._get
_related
_query
_name
, cls
._meta
)
104 if hasattr(sup
, 'contribute_to_class'):
105 sup
.contribute_to_class(cls
, name
)
107 if isinstance(other
, basestring
):
108 add_lazy_relation(cls
, self
, other
)
110 self
.do_related_class(other
, cls
)
111 if not cls
._meta
.abstract
and self
.rel
.related_name
:
112 self
.rel
.related_name
= self
.rel
.related_name
% {'class': cls
.__name
__.lower()}
114 def set_attributes_from_rel(self
):
115 self
.name
= self
.name
or (self
.rel
.to
._meta
.object_name
.lower() + '_' + self
.rel
.to
._meta
.pk
.name
)
116 self
.verbose_name
= self
.verbose_name
or self
.rel
.to
._meta
.verbose_name
117 self
.rel
.field_name
= self
.rel
.field_name
or self
.rel
.to
._meta
.pk
.name
119 def do_related_class(self
, other
, cls
):
120 self
.set_attributes_from_rel()
121 related
= RelatedObject(other
, cls
, self
)
122 self
.contribute_to_related_class(other
, related
)
124 def get_db_prep_lookup(self
, lookup_type
, value
):
125 # If we are doing a lookup on a Related Field, we must be
126 # comparing object instances. The value should be the PK of value,
129 # Value may be a primary key, or an object held in a relation.
130 # If it is an object, then we need to get the primary key value for
131 # that object. In certain conditions (especially one-to-one relations),
132 # the primary key may itself be an object - so we need to keep drilling
133 # down until we hit a value that can be used for a comparison.
137 v
= getattr(v
, v
._meta
.pk
.name
)
138 except AttributeError:
142 if hasattr(value
, 'as_sql'):
143 sql
, params
= value
.as_sql()
144 return QueryWrapper(('(%s)' % sql
), params
)
145 if lookup_type
== 'exact':
146 return [pk_trace(value
)]
147 if lookup_type
== 'in':
148 return [pk_trace(v
) for v
in value
]
149 elif lookup_type
== 'isnull':
151 raise TypeError, "Related Field has invalid lookup: %s" % lookup_type
153 def _get_related_query_name(self
, opts
):
154 # This method defines the name that can be used to identify this
155 # related object in a table-spanning query. It uses the lower-cased
156 # object_name by default, but this can be overridden with the
157 # "related_name" option.
158 return self
.rel
.related_name
or opts
.object_name
.lower()
160 class SingleRelatedObjectDescriptor(object):
161 # This class provides the functionality that makes the related-object
162 # managers available as attributes on a model class, for fields that have
163 # a single "remote" value, on the class pointed to by a related field.
164 # In the example "place.restaurant", the restaurant attribute is a
165 # SingleRelatedObjectDescriptor instance.
166 def __init__(self
, related
):
167 self
.related
= related
168 self
.cache_name
= '_%s_cache' % related
.field
.name
170 def __get__(self
, instance
, instance_type
=None):
172 raise AttributeError, "%s must be accessed via instance" % self
.related
.opts
.object_name
175 return getattr(instance
, self
.cache_name
)
176 except AttributeError:
177 params
= {'%s__pk' % self
.related
.field
.name
: instance
._get
_pk
_val
()}
178 rel_obj
= self
.related
.model
._default
_manager
.get(**params
)
179 setattr(instance
, self
.cache_name
, rel_obj
)
182 def __set__(self
, instance
, value
):
184 raise AttributeError, "%s must be accessed via instance" % self
.related
.opts
.object_name
185 # Set the value of the related field
186 setattr(value
, self
.related
.field
.rel
.get_related_field().attname
, instance
)
188 # Clear the cache, if it exists
190 delattr(value
, self
.related
.field
.get_cache_name())
191 except AttributeError:
194 class ReverseSingleRelatedObjectDescriptor(object):
195 # This class provides the functionality that makes the related-object
196 # managers available as attributes on a model class, for fields that have
197 # a single "remote" value, on the class that defines the related field.
198 # In the example "choice.poll", the poll attribute is a
199 # ReverseSingleRelatedObjectDescriptor instance.
200 def __init__(self
, field_with_rel
):
201 self
.field
= field_with_rel
203 def __get__(self
, instance
, instance_type
=None):
205 raise AttributeError, "%s must be accessed via instance" % self
.field
.name
206 cache_name
= self
.field
.get_cache_name()
208 return getattr(instance
, cache_name
)
209 except AttributeError:
210 val
= getattr(instance
, self
.field
.attname
)
212 # If NULL is an allowed value, return it.
215 raise self
.field
.rel
.to
.DoesNotExist
216 other_field
= self
.field
.rel
.get_related_field()
218 params
= {'%s__pk' % self
.field
.rel
.field_name
: val
}
220 params
= {'%s__exact' % self
.field
.rel
.field_name
: val
}
221 rel_obj
= self
.field
.rel
.to
._default
_manager
.get(**params
)
222 setattr(instance
, cache_name
, rel_obj
)
225 def __set__(self
, instance
, value
):
227 raise AttributeError, "%s must be accessed via instance" % self
._field
.name
228 # Set the value of the related field
230 val
= getattr(value
, self
.field
.rel
.get_related_field().attname
)
231 except AttributeError:
233 setattr(instance
, self
.field
.attname
, val
)
235 # Clear the cache, if it exists
237 delattr(instance
, self
.field
.get_cache_name())
238 except AttributeError:
241 class ForeignRelatedObjectsDescriptor(object):
242 # This class provides the functionality that makes the related-object
243 # managers available as attributes on a model class, for fields that have
244 # multiple "remote" values and have a ForeignKey pointed at them by
245 # some other model. In the example "poll.choice_set", the choice_set
246 # attribute is a ForeignRelatedObjectsDescriptor instance.
247 def __init__(self
, related
):
248 self
.related
= related
# RelatedObject instance
250 def __get__(self
, instance
, instance_type
=None):
252 raise AttributeError, "Manager must be accessed via instance"
254 rel_field
= self
.related
.field
255 rel_model
= self
.related
.model
257 # Dynamically create a class that subclasses the related
258 # model's default manager.
259 superclass
= self
.related
.model
._default
_manager
.__class
__
261 class RelatedManager(superclass
):
262 def get_query_set(self
):
263 return superclass
.get_query_set(self
).filter(**(self
.core_filters
))
265 def add(self
, *objs
):
267 setattr(obj
, rel_field
.name
, instance
)
269 add
.alters_data
= True
271 def create(self
, **kwargs
):
272 new_obj
= self
.model(**kwargs
)
275 create
.alters_data
= True
277 # remove() and clear() are only provided if the ForeignKey can have a value of null.
279 def remove(self
, *objs
):
280 val
= getattr(instance
, rel_field
.rel
.get_related_field().attname
)
282 # Is obj actually part of this descriptor set?
283 if getattr(obj
, rel_field
.attname
) == val
:
284 setattr(obj
, rel_field
.name
, None)
287 raise rel_field
.rel
.to
.DoesNotExist
, "%r is not related to %r." % (obj
, instance
)
288 remove
.alters_data
= True
291 for obj
in self
.all():
292 setattr(obj
, rel_field
.name
, None)
294 clear
.alters_data
= True
296 manager
= RelatedManager()
297 manager
.core_filters
= {'%s__pk' % rel_field
.name
: getattr(instance
, rel_field
.rel
.get_related_field().attname
)}
298 manager
.model
= self
.related
.model
302 def __set__(self
, instance
, value
):
304 raise AttributeError, "Manager must be accessed via instance"
306 manager
= self
.__get
__(instance
)
307 # If the foreign key can support nulls, then completely clear the related set.
308 # Otherwise, just move the named objects into the set.
309 if self
.related
.field
.null
:
313 def create_many_related_manager(superclass
):
314 """Creates a manager that subclasses 'superclass' (which is a Manager)
315 and adds behavior for many-to-many related objects."""
316 class ManyRelatedManager(superclass
):
317 def __init__(self
, model
=None, core_filters
=None, instance
=None, symmetrical
=None,
318 join_table
=None, source_col_name
=None, target_col_name
=None):
319 super(ManyRelatedManager
, self
).__init
__()
320 self
.core_filters
= core_filters
322 self
.symmetrical
= symmetrical
323 self
.instance
= instance
324 self
.join_table
= join_table
325 self
.source_col_name
= source_col_name
326 self
.target_col_name
= target_col_name
327 self
._pk
_val
= self
.instance
._get
_pk
_val
()
328 if self
._pk
_val
is None:
329 raise ValueError("%r instance needs to have a primary key value before a many-to-many relationship can be used." % model
)
331 def get_query_set(self
):
332 return superclass
.get_query_set(self
).filter(**(self
.core_filters
))
334 def add(self
, *objs
):
335 self
._add
_items
(self
.source_col_name
, self
.target_col_name
, *objs
)
337 # If this is a symmetrical m2m relation to self, add the mirror entry in the m2m table
339 self
._add
_items
(self
.target_col_name
, self
.source_col_name
, *objs
)
340 add
.alters_data
= True
342 def remove(self
, *objs
):
343 self
._remove
_items
(self
.source_col_name
, self
.target_col_name
, *objs
)
345 # If this is a symmetrical m2m relation to self, remove the mirror entry in the m2m table
347 self
._remove
_items
(self
.target_col_name
, self
.source_col_name
, *objs
)
348 remove
.alters_data
= True
351 self
._clear
_items
(self
.source_col_name
)
353 # If this is a symmetrical m2m relation to self, clear the mirror entry in the m2m table
355 self
._clear
_items
(self
.target_col_name
)
356 clear
.alters_data
= True
358 def create(self
, **kwargs
):
359 new_obj
= self
.model(**kwargs
)
363 create
.alters_data
= True
365 def _add_items(self
, source_col_name
, target_col_name
, *objs
):
366 # join_table: name of the m2m link table
367 # source_col_name: the PK colname in join_table for the source object
368 # target_col_name: the PK colname in join_table for the target object
369 # *objs - objects to add. Either object instances, or primary keys of object instances.
371 # If there aren't any objects, there is nothing to do.
373 # Check that all the objects are of the right type
376 if isinstance(obj
, self
.model
):
377 new_ids
.add(obj
._get
_pk
_val
())
380 # Add the newly created or already existing objects to the join table.
381 # First find out which items are already added, to avoid adding them twice
382 cursor
= connection
.cursor()
383 cursor
.execute("SELECT %s FROM %s WHERE %s = %%s AND %s IN (%s)" % \
384 (target_col_name
, self
.join_table
, source_col_name
,
385 target_col_name
, ",".join(['%s'] * len(new_ids
))),
386 [self
._pk
_val
] + list(new_ids
))
387 existing_ids
= set([row
[0] for row
in cursor
.fetchall()])
389 # Add the ones that aren't there already
390 for obj_id
in (new_ids
- existing_ids
):
391 cursor
.execute("INSERT INTO %s (%s, %s) VALUES (%%s, %%s)" % \
392 (self
.join_table
, source_col_name
, target_col_name
),
393 [self
._pk
_val
, obj_id
])
394 transaction
.commit_unless_managed()
396 def _remove_items(self
, source_col_name
, target_col_name
, *objs
):
397 # source_col_name: the PK colname in join_table for the source object
398 # target_col_name: the PK colname in join_table for the target object
399 # *objs - objects to remove
401 # If there aren't any objects, there is nothing to do.
403 # Check that all the objects are of the right type
406 if isinstance(obj
, self
.model
):
407 old_ids
.add(obj
._get
_pk
_val
())
410 # Remove the specified objects from the join table
411 cursor
= connection
.cursor()
412 cursor
.execute("DELETE FROM %s WHERE %s = %%s AND %s IN (%s)" % \
413 (self
.join_table
, source_col_name
,
414 target_col_name
, ",".join(['%s'] * len(old_ids
))),
415 [self
._pk
_val
] + list(old_ids
))
416 transaction
.commit_unless_managed()
418 def _clear_items(self
, source_col_name
):
419 # source_col_name: the PK colname in join_table for the source object
420 cursor
= connection
.cursor()
421 cursor
.execute("DELETE FROM %s WHERE %s = %%s" % \
422 (self
.join_table
, source_col_name
),
424 transaction
.commit_unless_managed()
426 return ManyRelatedManager
428 class ManyRelatedObjectsDescriptor(object):
429 # This class provides the functionality that makes the related-object
430 # managers available as attributes on a model class, for fields that have
431 # multiple "remote" values and have a ManyToManyField pointed at them by
432 # some other model (rather than having a ManyToManyField themselves).
433 # In the example "publication.article_set", the article_set attribute is a
434 # ManyRelatedObjectsDescriptor instance.
435 def __init__(self
, related
):
436 self
.related
= related
# RelatedObject instance
438 def __get__(self
, instance
, instance_type
=None):
440 raise AttributeError, "Manager must be accessed via instance"
442 # Dynamically create a class that subclasses the related
443 # model's default manager.
444 rel_model
= self
.related
.model
445 superclass
= rel_model
._default
_manager
.__class
__
446 RelatedManager
= create_many_related_manager(superclass
)
448 qn
= connection
.ops
.quote_name
449 manager
= RelatedManager(
451 core_filters
={'%s__pk' % self
.related
.field
.name
: instance
._get
_pk
_val
()},
454 join_table
=qn(self
.related
.field
.m2m_db_table()),
455 source_col_name
=qn(self
.related
.field
.m2m_reverse_name()),
456 target_col_name
=qn(self
.related
.field
.m2m_column_name())
461 def __set__(self
, instance
, value
):
463 raise AttributeError, "Manager must be accessed via instance"
465 manager
= self
.__get
__(instance
)
469 class ReverseManyRelatedObjectsDescriptor(object):
470 # This class provides the functionality that makes the related-object
471 # managers available as attributes on a model class, for fields that have
472 # multiple "remote" values and have a ManyToManyField defined in their
473 # model (rather than having another model pointed *at* them).
474 # In the example "article.publications", the publications attribute is a
475 # ReverseManyRelatedObjectsDescriptor instance.
476 def __init__(self
, m2m_field
):
477 self
.field
= m2m_field
479 def __get__(self
, instance
, instance_type
=None):
481 raise AttributeError, "Manager must be accessed via instance"
483 # Dynamically create a class that subclasses the related
484 # model's default manager.
485 rel_model
=self
.field
.rel
.to
486 superclass
= rel_model
._default
_manager
.__class
__
487 RelatedManager
= create_many_related_manager(superclass
)
489 qn
= connection
.ops
.quote_name
490 manager
= RelatedManager(
492 core_filters
={'%s__pk' % self
.field
.related_query_name(): instance
._get
_pk
_val
()},
494 symmetrical
=(self
.field
.rel
.symmetrical
and instance
.__class
__ == rel_model
),
495 join_table
=qn(self
.field
.m2m_db_table()),
496 source_col_name
=qn(self
.field
.m2m_column_name()),
497 target_col_name
=qn(self
.field
.m2m_reverse_name())
502 def __set__(self
, instance
, value
):
504 raise AttributeError, "Manager must be accessed via instance"
506 manager
= self
.__get
__(instance
)
510 class ManyToOneRel(object):
511 def __init__(self
, to
, field_name
, num_in_admin
=3, min_num_in_admin
=None,
512 max_num_in_admin
=None, num_extra_on_change
=1, edit_inline
=False,
513 related_name
=None, limit_choices_to
=None, lookup_overrides
=None,
514 raw_id_admin
=False, parent_link
=False):
517 except AttributeError: # to._meta doesn't exist, so it must be RECURSIVE_RELATIONSHIP_CONSTANT
518 assert isinstance(to
, basestring
), "'to' must be either a model, a model name or the string %r" % RECURSIVE_RELATIONSHIP_CONSTANT
519 self
.to
, self
.field_name
= to
, field_name
520 self
.num_in_admin
, self
.edit_inline
= num_in_admin
, edit_inline
521 self
.min_num_in_admin
, self
.max_num_in_admin
= min_num_in_admin
, max_num_in_admin
522 self
.num_extra_on_change
, self
.related_name
= num_extra_on_change
, related_name
523 if limit_choices_to
is None:
524 limit_choices_to
= {}
525 self
.limit_choices_to
= limit_choices_to
526 self
.lookup_overrides
= lookup_overrides
or {}
527 self
.raw_id_admin
= raw_id_admin
529 self
.parent_link
= parent_link
531 def get_related_field(self
):
533 Returns the Field in the 'to' object to which this relationship is
536 data
= self
.to
._meta
.get_field_by_name(self
.field_name
)
538 raise FieldDoesNotExist("No related field named '%s'" %
542 class OneToOneRel(ManyToOneRel
):
543 def __init__(self
, to
, field_name
, num_in_admin
=0, min_num_in_admin
=None,
544 max_num_in_admin
=None, num_extra_on_change
=None, edit_inline
=False,
545 related_name
=None, limit_choices_to
=None, lookup_overrides
=None,
546 raw_id_admin
=False, parent_link
=False):
547 # NOTE: *_num_in_admin and num_extra_on_change are intentionally
548 # ignored here. We accept them as parameters only to match the calling
549 # signature of ManyToOneRel.__init__().
550 super(OneToOneRel
, self
).__init
__(to
, field_name
, num_in_admin
,
551 edit_inline
=edit_inline
, related_name
=related_name
,
552 limit_choices_to
=limit_choices_to
,
553 lookup_overrides
=lookup_overrides
, raw_id_admin
=raw_id_admin
,
554 parent_link
=parent_link
)
555 self
.multiple
= False
557 class ManyToManyRel(object):
558 def __init__(self
, to
, num_in_admin
=0, related_name
=None,
559 filter_interface
=None, limit_choices_to
=None, raw_id_admin
=False, symmetrical
=True):
561 self
.num_in_admin
= num_in_admin
562 self
.related_name
= related_name
563 self
.filter_interface
= filter_interface
564 if limit_choices_to
is None:
565 limit_choices_to
= {}
566 self
.limit_choices_to
= limit_choices_to
567 self
.edit_inline
= False
568 self
.raw_id_admin
= raw_id_admin
569 self
.symmetrical
= symmetrical
572 assert not (self
.raw_id_admin
and self
.filter_interface
), "ManyToManyRels may not use both raw_id_admin and filter_interface"
574 class ForeignKey(RelatedField
, Field
):
575 empty_strings_allowed
= False
576 def __init__(self
, to
, to_field
=None, rel_class
=ManyToOneRel
, **kwargs
):
578 to_name
= to
._meta
.object_name
.lower()
579 except AttributeError: # to._meta doesn't exist, so it must be RECURSIVE_RELATIONSHIP_CONSTANT
580 assert isinstance(to
, basestring
), "%s(%r) is invalid. First parameter to ForeignKey must be either a model, a model name, or the string %r" % (self
.__class
__.__name
__, to
, RECURSIVE_RELATIONSHIP_CONSTANT
)
582 to_field
= to_field
or to
._meta
.pk
.name
583 kwargs
['verbose_name'] = kwargs
.get('verbose_name', '')
585 if 'edit_inline_type' in kwargs
:
587 warnings
.warn("edit_inline_type is deprecated. Use edit_inline instead.", DeprecationWarning)
588 kwargs
['edit_inline'] = kwargs
.pop('edit_inline_type')
590 kwargs
['rel'] = rel_class(to
, to_field
,
591 num_in_admin
=kwargs
.pop('num_in_admin', 3),
592 min_num_in_admin
=kwargs
.pop('min_num_in_admin', None),
593 max_num_in_admin
=kwargs
.pop('max_num_in_admin', None),
594 num_extra_on_change
=kwargs
.pop('num_extra_on_change', 1),
595 edit_inline
=kwargs
.pop('edit_inline', False),
596 related_name
=kwargs
.pop('related_name', None),
597 limit_choices_to
=kwargs
.pop('limit_choices_to', None),
598 lookup_overrides
=kwargs
.pop('lookup_overrides', None),
599 raw_id_admin
=kwargs
.pop('raw_id_admin', False),
600 parent_link
=kwargs
.pop('parent_link', False))
601 Field
.__init
__(self
, **kwargs
)
605 def get_attname(self
):
606 return '%s_id' % self
.name
608 def get_validator_unique_lookup_type(self
):
609 return '%s__%s__exact' % (self
.name
, self
.rel
.get_related_field().name
)
611 def prepare_field_objs_and_params(self
, manipulator
, name_prefix
):
612 params
= {'validator_list': self
.validator_list
[:], 'member_name': name_prefix
+ self
.attname
}
613 if self
.rel
.raw_id_admin
:
614 field_objs
= self
.get_manipulator_field_objs()
615 params
['validator_list'].append(curry(manipulator_valid_rel_key
, self
, manipulator
))
618 field_objs
= [oldforms
.RadioSelectField
]
619 params
['ul_class'] = get_ul_class(self
.radio_admin
)
622 field_objs
= [oldforms
.NullSelectField
]
624 field_objs
= [oldforms
.SelectField
]
625 params
['choices'] = self
.get_choices_default()
626 return field_objs
, params
628 def get_default(self
):
629 "Here we check if the default value is an object and return the to_field if so."
630 field_default
= super(ForeignKey
, self
).get_default()
631 if isinstance(field_default
, self
.rel
.to
):
632 return getattr(field_default
, self
.rel
.get_related_field().attname
)
635 def get_manipulator_field_objs(self
):
636 rel_field
= self
.rel
.get_related_field()
637 if self
.rel
.raw_id_admin
and not isinstance(rel_field
, AutoField
):
638 return rel_field
.get_manipulator_field_objs()
640 return [oldforms
.IntegerField
]
642 def get_db_prep_save(self
, value
):
643 if value
== '' or value
== None:
646 return self
.rel
.get_related_field().get_db_prep_save(value
)
648 def flatten_data(self
, follow
, obj
=None):
650 # In required many-to-one fields with only one available choice,
651 # select that one available choice. Note: For SelectFields
652 # (radio_admin=False), we have to check that the length of choices
653 # is *2*, not 1, because SelectFields always have an initial
654 # "blank" value. Otherwise (radio_admin=True), we check that the
656 if not self
.blank
and (not self
.rel
.raw_id_admin
or self
.choices
):
657 choice_list
= self
.get_choices_default()
658 if self
.radio_admin
and len(choice_list
) == 1:
659 return {self
.attname
: choice_list
[0][0]}
660 if not self
.radio_admin
and len(choice_list
) == 2:
661 return {self
.attname
: choice_list
[1][0]}
662 return Field
.flatten_data(self
, follow
, obj
)
664 def contribute_to_class(self
, cls
, name
):
665 super(ForeignKey
, self
).contribute_to_class(cls
, name
)
666 setattr(cls
, self
.name
, ReverseSingleRelatedObjectDescriptor(self
))
668 def contribute_to_related_class(self
, cls
, related
):
669 setattr(cls
, related
.get_accessor_name(), ForeignRelatedObjectsDescriptor(related
))
671 def formfield(self
, **kwargs
):
672 defaults
= {'form_class': forms
.ModelChoiceField
, 'queryset': self
.rel
.to
._default
_manager
.all()}
673 defaults
.update(kwargs
)
674 return super(ForeignKey
, self
).formfield(**defaults
)
677 # The database column type of a ForeignKey is the column type
678 # of the field to which it points. An exception is if the ForeignKey
679 # points to an AutoField/PositiveIntegerField/PositiveSmallIntegerField,
680 # in which case the column type is simply that of an IntegerField.
681 rel_field
= self
.rel
.get_related_field()
682 if isinstance(rel_field
, (AutoField
, PositiveIntegerField
, PositiveSmallIntegerField
)):
683 return IntegerField().db_type()
684 return rel_field
.db_type()
686 class OneToOneField(ForeignKey
):
688 A OneToOneField is essentially the same as a ForeignKey, with the exception
689 that always carries a "unique" constraint with it and the reverse relation
690 always returns the object pointed to (since there will only ever be one),
691 rather than returning a list.
693 def __init__(self
, to
, to_field
=None, **kwargs
):
694 kwargs
['unique'] = True
695 if 'num_in_admin' not in kwargs
:
696 kwargs
['num_in_admin'] = 0
697 super(OneToOneField
, self
).__init
__(to
, to_field
, OneToOneRel
, **kwargs
)
699 def contribute_to_related_class(self
, cls
, related
):
700 setattr(cls
, related
.get_accessor_name(),
701 SingleRelatedObjectDescriptor(related
))
702 if not cls
._meta
.one_to_one_field
:
703 cls
._meta
.one_to_one_field
= self
705 class ManyToManyField(RelatedField
, Field
):
706 def __init__(self
, to
, **kwargs
):
707 kwargs
['verbose_name'] = kwargs
.get('verbose_name', None)
708 kwargs
['rel'] = ManyToManyRel(to
,
709 num_in_admin
=kwargs
.pop('num_in_admin', 0),
710 related_name
=kwargs
.pop('related_name', None),
711 filter_interface
=kwargs
.pop('filter_interface', None),
712 limit_choices_to
=kwargs
.pop('limit_choices_to', None),
713 raw_id_admin
=kwargs
.pop('raw_id_admin', False),
714 symmetrical
=kwargs
.pop('symmetrical', True))
715 self
.db_table
= kwargs
.pop('db_table', None)
716 if kwargs
["rel"].raw_id_admin
:
717 kwargs
.setdefault("validator_list", []).append(self
.isValidIDList
)
718 Field
.__init
__(self
, **kwargs
)
720 if self
.rel
.raw_id_admin
:
721 msg
= ugettext_lazy('Separate multiple IDs with commas.')
723 msg
= ugettext_lazy('Hold down "Control", or "Command" on a Mac, to select more than one.')
724 self
.help_text
= string_concat(self
.help_text
, ' ', msg
)
726 def get_manipulator_field_objs(self
):
727 if self
.rel
.raw_id_admin
:
728 return [oldforms
.RawIdAdminField
]
730 choices
= self
.get_choices_default()
731 return [curry(oldforms
.SelectMultipleField
, size
=min(max(len(choices
), 5), 15), choices
=choices
)]
733 def get_choices_default(self
):
734 return Field
.get_choices(self
, include_blank
=False)
736 def _get_m2m_db_table(self
, opts
):
737 "Function that can be curried to provide the m2m table name for this relation"
741 return '%s_%s' % (opts
.db_table
, self
.name
)
743 def _get_m2m_column_name(self
, related
):
744 "Function that can be curried to provide the source column name for the m2m table"
745 # If this is an m2m relation to self, avoid the inevitable name clash
746 if related
.model
== related
.parent_model
:
747 return 'from_' + related
.model
._meta
.object_name
.lower() + '_id'
749 return related
.model
._meta
.object_name
.lower() + '_id'
751 def _get_m2m_reverse_name(self
, related
):
752 "Function that can be curried to provide the related column name for the m2m table"
753 # If this is an m2m relation to self, avoid the inevitable name clash
754 if related
.model
== related
.parent_model
:
755 return 'to_' + related
.parent_model
._meta
.object_name
.lower() + '_id'
757 return related
.parent_model
._meta
.object_name
.lower() + '_id'
759 def isValidIDList(self
, field_data
, all_data
):
760 "Validates that the value is a valid list of foreign keys"
763 pks
= map(int, field_data
.split(','))
765 # the CommaSeparatedIntegerField validator will catch this error
767 objects
= mod
._default
_manager
.in_bulk(pks
)
768 if len(objects
) != len(pks
):
769 badkeys
= [k
for k
in pks
if k
not in objects
]
770 raise validators
.ValidationError
, ungettext("Please enter valid %(self)s IDs. The value %(value)r is invalid.",
771 "Please enter valid %(self)s IDs. The values %(value)r are invalid.", len(badkeys
)) % {
772 'self': self
.verbose_name
,
773 'value': len(badkeys
) == 1 and badkeys
[0] or tuple(badkeys
),
776 def flatten_data(self
, follow
, obj
= None):
779 instance_ids
= [instance
._get
_pk
_val
() for instance
in getattr(obj
, self
.name
).all()]
780 if self
.rel
.raw_id_admin
:
781 new_data
[self
.name
] = u
",".join([smart_unicode(id) for id in instance_ids
])
783 new_data
[self
.name
] = instance_ids
785 # In required many-to-many fields with only one available choice,
786 # select that one available choice.
787 if not self
.blank
and not self
.rel
.edit_inline
and not self
.rel
.raw_id_admin
:
788 choices_list
= self
.get_choices_default()
789 if len(choices_list
) == 1:
790 new_data
[self
.name
] = [choices_list
[0][0]]
793 def contribute_to_class(self
, cls
, name
):
794 super(ManyToManyField
, self
).contribute_to_class(cls
, name
)
795 # Add the descriptor for the m2m relation
796 setattr(cls
, self
.name
, ReverseManyRelatedObjectsDescriptor(self
))
798 # Set up the accessor for the m2m table name for the relation
799 self
.m2m_db_table
= curry(self
._get
_m
2m
_db
_table
, cls
._meta
)
801 def contribute_to_related_class(self
, cls
, related
):
802 # m2m relations to self do not have a ManyRelatedObjectsDescriptor,
803 # as it would be redundant - unless the field is non-symmetrical.
804 if related
.model
!= related
.parent_model
or not self
.rel
.symmetrical
:
805 # Add the descriptor for the m2m relation
806 setattr(cls
, related
.get_accessor_name(), ManyRelatedObjectsDescriptor(related
))
808 # Set up the accessors for the column names on the m2m table
809 self
.m2m_column_name
= curry(self
._get
_m
2m
_column
_name
, related
)
810 self
.m2m_reverse_name
= curry(self
._get
_m
2m
_reverse
_name
, related
)
812 def set_attributes_from_rel(self
):
815 def value_from_object(self
, obj
):
816 "Returns the value of this field in the given model instance."
817 return getattr(obj
, self
.attname
).all()
819 def save_form_data(self
, instance
, data
):
820 setattr(instance
, self
.attname
, data
)
822 def formfield(self
, **kwargs
):
823 defaults
= {'form_class': forms
.ModelMultipleChoiceField
, 'queryset': self
.rel
.to
._default
_manager
.all()}
824 defaults
.update(kwargs
)
825 # If initial is passed in, it's a list of related objects, but the
826 # MultipleChoiceField takes a list of IDs.
827 if defaults
.get('initial') is not None:
828 defaults
['initial'] = [i
._get
_pk
_val
() for i
in defaults
['initial']]
829 return super(ManyToManyField
, self
).formfield(**defaults
)
832 # A ManyToManyField is not represented by a single column,