2011-10-08 00:05:53 +08:00
from operator import attrgetter
2011-07-13 17:35:51 +08:00
from django . db import connection , router
2008-12-03 00:58:06 +08:00
from django . db . backends import util
2006-06-23 12:37:00 +08:00
from django . db . models import signals , get_model
2009-12-22 23:18:51 +08:00
from django . db . models . fields import ( AutoField , Field , IntegerField ,
PositiveIntegerField , PositiveSmallIntegerField , FieldDoesNotExist )
2006-05-02 09:31:56 +08:00
from django . db . models . related import RelatedObject
2008-07-21 23:41:21 +08:00
from django . db . models . query import QuerySet
Merged the queryset-refactor branch into trunk.
This is a big internal change, but mostly backwards compatible with existing
code. Also adds a couple of new features.
Fixed #245, #1050, #1656, #1801, #2076, #2091, #2150, #2253, #2306, #2400, #2430, #2482, #2496, #2676, #2737, #2874, #2902, #2939, #3037, #3141, #3288, #3440, #3592, #3739, #4088, #4260, #4289, #4306, #4358, #4464, #4510, #4858, #5012, #5020, #5261, #5295, #5321, #5324, #5325, #5555, #5707, #5796, #5817, #5987, #6018, #6074, #6088, #6154, #6177, #6180, #6203, #6658
git-svn-id: http://code.djangoproject.com/svn/django/trunk@7477 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2008-04-27 10:50:16 +08:00
from django . db . models . query_utils import QueryWrapper
2010-11-10 00:46:42 +08:00
from django . db . models . deletion import CASCADE
Removed oldforms, validators, and related code:
* Removed `Manipulator`, `AutomaticManipulator`, and related classes.
* Removed oldforms specific bits from model fields:
* Removed `validator_list` and `core` arguments from constructors.
* Removed the methods:
* `get_manipulator_field_names`
* `get_manipulator_field_objs`
* `get_manipulator_fields`
* `get_manipulator_new_data`
* `prepare_field_objs_and_params`
* `get_follow`
* Renamed `flatten_data` method to `value_to_string` for better alignment with its use by the serialization framework, which was the only remaining code using `flatten_data`.
* Removed oldforms methods from `django.db.models.Options` class: `get_followed_related_objects`, `get_data_holders`, `get_follow`, and `has_field_type`.
* Removed oldforms-admin specific options from `django.db.models.fields.related` classes: `num_in_admin`, `min_num_in_admin`, `max_num_in_admin`, `num_extra_on_change`, and `edit_inline`.
* Serialization framework
* `Serializer.get_string_value` now calls the model fields' renamed `value_to_string` methods.
* Removed a special-casing of `models.DateTimeField` in `core.serializers.base.Serializer.get_string_value` that's handled by `django.db.models.fields.DateTimeField.value_to_string`.
* Removed `django.core.validators`:
* Moved `ValidationError` exception to `django.core.exceptions`.
* For the couple places that were using validators, brought over the necessary code to maintain the same functionality.
* Introduced a SlugField form field for validation and to compliment the SlugField model field (refs #8040).
* Removed an oldforms-style model creation hack (refs #2160).
git-svn-id: http://code.djangoproject.com/svn/django/trunk@8616 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2008-08-27 15:19:44 +08:00
from django . utils . encoding import smart_unicode
2011-07-13 17:35:51 +08:00
from django . utils . translation import ugettext_lazy as _ , string_concat
2011-10-06 19:08:11 +08:00
from django . utils . functional import curry , cached_property
Removed oldforms, validators, and related code:
* Removed `Manipulator`, `AutomaticManipulator`, and related classes.
* Removed oldforms specific bits from model fields:
* Removed `validator_list` and `core` arguments from constructors.
* Removed the methods:
* `get_manipulator_field_names`
* `get_manipulator_field_objs`
* `get_manipulator_fields`
* `get_manipulator_new_data`
* `prepare_field_objs_and_params`
* `get_follow`
* Renamed `flatten_data` method to `value_to_string` for better alignment with its use by the serialization framework, which was the only remaining code using `flatten_data`.
* Removed oldforms methods from `django.db.models.Options` class: `get_followed_related_objects`, `get_data_holders`, `get_follow`, and `has_field_type`.
* Removed oldforms-admin specific options from `django.db.models.fields.related` classes: `num_in_admin`, `min_num_in_admin`, `max_num_in_admin`, `num_extra_on_change`, and `edit_inline`.
* Serialization framework
* `Serializer.get_string_value` now calls the model fields' renamed `value_to_string` methods.
* Removed a special-casing of `models.DateTimeField` in `core.serializers.base.Serializer.get_string_value` that's handled by `django.db.models.fields.DateTimeField.value_to_string`.
* Removed `django.core.validators`:
* Moved `ValidationError` exception to `django.core.exceptions`.
* For the couple places that were using validators, brought over the necessary code to maintain the same functionality.
* Introduced a SlugField form field for validation and to compliment the SlugField model field (refs #8040).
* Removed an oldforms-style model creation hack (refs #2160).
git-svn-id: http://code.djangoproject.com/svn/django/trunk@8616 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2008-08-27 15:19:44 +08:00
from django . core import exceptions
2008-07-19 09:22:26 +08:00
from django import forms
2006-05-02 09:31:56 +08:00
RECURSIVE_RELATIONSHIP_CONSTANT = ' self '
pending_lookups = { }
2008-07-29 20:41:08 +08:00
def add_lazy_relation ( cls , field , relation , operation ) :
2008-02-27 05:13:16 +08:00
"""
Adds a lookup on ` ` cls ` ` when a related field is defined using a string ,
i . e . : :
Merged the queryset-refactor branch into trunk.
This is a big internal change, but mostly backwards compatible with existing
code. Also adds a couple of new features.
Fixed #245, #1050, #1656, #1801, #2076, #2091, #2150, #2253, #2306, #2400, #2430, #2482, #2496, #2676, #2737, #2874, #2902, #2939, #3037, #3141, #3288, #3440, #3592, #3739, #4088, #4260, #4289, #4306, #4358, #4464, #4510, #4858, #5012, #5020, #5261, #5295, #5321, #5324, #5325, #5555, #5707, #5796, #5817, #5987, #6018, #6074, #6088, #6154, #6177, #6180, #6203, #6658
git-svn-id: http://code.djangoproject.com/svn/django/trunk@7477 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2008-04-27 10:50:16 +08:00
2008-02-27 05:13:16 +08:00
class MyModel ( Model ) :
fk = ForeignKey ( " AnotherModel " )
Merged the queryset-refactor branch into trunk.
This is a big internal change, but mostly backwards compatible with existing
code. Also adds a couple of new features.
Fixed #245, #1050, #1656, #1801, #2076, #2091, #2150, #2253, #2306, #2400, #2430, #2482, #2496, #2676, #2737, #2874, #2902, #2939, #3037, #3141, #3288, #3440, #3592, #3739, #4088, #4260, #4289, #4306, #4358, #4464, #4510, #4858, #5012, #5020, #5261, #5295, #5321, #5324, #5325, #5555, #5707, #5796, #5817, #5987, #6018, #6074, #6088, #6154, #6177, #6180, #6203, #6658
git-svn-id: http://code.djangoproject.com/svn/django/trunk@7477 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2008-04-27 10:50:16 +08:00
2008-02-27 05:13:16 +08:00
This string can be :
Merged the queryset-refactor branch into trunk.
This is a big internal change, but mostly backwards compatible with existing
code. Also adds a couple of new features.
Fixed #245, #1050, #1656, #1801, #2076, #2091, #2150, #2253, #2306, #2400, #2430, #2482, #2496, #2676, #2737, #2874, #2902, #2939, #3037, #3141, #3288, #3440, #3592, #3739, #4088, #4260, #4289, #4306, #4358, #4464, #4510, #4858, #5012, #5020, #5261, #5295, #5321, #5324, #5325, #5555, #5707, #5796, #5817, #5987, #6018, #6074, #6088, #6154, #6177, #6180, #6203, #6658
git-svn-id: http://code.djangoproject.com/svn/django/trunk@7477 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2008-04-27 10:50:16 +08:00
2008-02-27 05:13:16 +08:00
* RECURSIVE_RELATIONSHIP_CONSTANT ( i . e . " self " ) to indicate a recursive
relation .
Merged the queryset-refactor branch into trunk.
This is a big internal change, but mostly backwards compatible with existing
code. Also adds a couple of new features.
Fixed #245, #1050, #1656, #1801, #2076, #2091, #2150, #2253, #2306, #2400, #2430, #2482, #2496, #2676, #2737, #2874, #2902, #2939, #3037, #3141, #3288, #3440, #3592, #3739, #4088, #4260, #4289, #4306, #4358, #4464, #4510, #4858, #5012, #5020, #5261, #5295, #5321, #5324, #5325, #5555, #5707, #5796, #5817, #5987, #6018, #6074, #6088, #6154, #6177, #6180, #6203, #6658
git-svn-id: http://code.djangoproject.com/svn/django/trunk@7477 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2008-04-27 10:50:16 +08:00
2008-02-27 05:13:16 +08:00
* The name of a model ( i . e " AnotherModel " ) to indicate another model in
the same app .
Merged the queryset-refactor branch into trunk.
This is a big internal change, but mostly backwards compatible with existing
code. Also adds a couple of new features.
Fixed #245, #1050, #1656, #1801, #2076, #2091, #2150, #2253, #2306, #2400, #2430, #2482, #2496, #2676, #2737, #2874, #2902, #2939, #3037, #3141, #3288, #3440, #3592, #3739, #4088, #4260, #4289, #4306, #4358, #4464, #4510, #4858, #5012, #5020, #5261, #5295, #5321, #5324, #5325, #5555, #5707, #5796, #5817, #5987, #6018, #6074, #6088, #6154, #6177, #6180, #6203, #6658
git-svn-id: http://code.djangoproject.com/svn/django/trunk@7477 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2008-04-27 10:50:16 +08:00
2008-02-27 05:13:16 +08:00
* An app - label and model name ( i . e . " someapp.AnotherModel " ) to indicate
another model in a different app .
Merged the queryset-refactor branch into trunk.
This is a big internal change, but mostly backwards compatible with existing
code. Also adds a couple of new features.
Fixed #245, #1050, #1656, #1801, #2076, #2091, #2150, #2253, #2306, #2400, #2430, #2482, #2496, #2676, #2737, #2874, #2902, #2939, #3037, #3141, #3288, #3440, #3592, #3739, #4088, #4260, #4289, #4306, #4358, #4464, #4510, #4858, #5012, #5020, #5261, #5295, #5321, #5324, #5325, #5555, #5707, #5796, #5817, #5987, #6018, #6074, #6088, #6154, #6177, #6180, #6203, #6658
git-svn-id: http://code.djangoproject.com/svn/django/trunk@7477 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2008-04-27 10:50:16 +08:00
2008-02-27 05:13:16 +08:00
If the other model hasn ' t yet been loaded -- almost a given if you ' re using
lazy relationships - - then the relation won ' t be set up until the
class_prepared signal fires at the end of model initialization .
2008-08-26 12:55:56 +08:00
2008-07-29 20:41:08 +08:00
operation is the work that must be performed once the relation can be resolved .
2008-02-27 05:13:16 +08:00
"""
# Check for recursive relations
if relation == RECURSIVE_RELATIONSHIP_CONSTANT :
app_label = cls . _meta . app_label
model_name = cls . __name__
Merged the queryset-refactor branch into trunk.
This is a big internal change, but mostly backwards compatible with existing
code. Also adds a couple of new features.
Fixed #245, #1050, #1656, #1801, #2076, #2091, #2150, #2253, #2306, #2400, #2430, #2482, #2496, #2676, #2737, #2874, #2902, #2939, #3037, #3141, #3288, #3440, #3592, #3739, #4088, #4260, #4289, #4306, #4358, #4464, #4510, #4858, #5012, #5020, #5261, #5295, #5321, #5324, #5325, #5555, #5707, #5796, #5817, #5987, #6018, #6074, #6088, #6154, #6177, #6180, #6203, #6658
git-svn-id: http://code.djangoproject.com/svn/django/trunk@7477 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2008-04-27 10:50:16 +08:00
2008-02-27 05:13:16 +08:00
else :
# Look for an "app.Model" relation
try :
app_label , model_name = relation . split ( " . " )
except ValueError :
# If we can't split, assume a model in current app
app_label = cls . _meta . app_label
model_name = relation
2009-11-03 22:02:49 +08:00
except AttributeError :
# If it doesn't have a split it's actually a model class
app_label = relation . _meta . app_label
model_name = relation . _meta . object_name
Merged the queryset-refactor branch into trunk.
This is a big internal change, but mostly backwards compatible with existing
code. Also adds a couple of new features.
Fixed #245, #1050, #1656, #1801, #2076, #2091, #2150, #2253, #2306, #2400, #2430, #2482, #2496, #2676, #2737, #2874, #2902, #2939, #3037, #3141, #3288, #3440, #3592, #3739, #4088, #4260, #4289, #4306, #4358, #4464, #4510, #4858, #5012, #5020, #5261, #5295, #5321, #5324, #5325, #5555, #5707, #5796, #5817, #5987, #6018, #6074, #6088, #6154, #6177, #6180, #6203, #6658
git-svn-id: http://code.djangoproject.com/svn/django/trunk@7477 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2008-04-27 10:50:16 +08:00
2008-02-27 05:13:16 +08:00
# Try to look up the related model, and if it's already loaded resolve the
# string right away. If get_model returns None, it means that the related
Merged the queryset-refactor branch into trunk.
This is a big internal change, but mostly backwards compatible with existing
code. Also adds a couple of new features.
Fixed #245, #1050, #1656, #1801, #2076, #2091, #2150, #2253, #2306, #2400, #2430, #2482, #2496, #2676, #2737, #2874, #2902, #2939, #3037, #3141, #3288, #3440, #3592, #3739, #4088, #4260, #4289, #4306, #4358, #4464, #4510, #4858, #5012, #5020, #5261, #5295, #5321, #5324, #5325, #5555, #5707, #5796, #5817, #5987, #6018, #6074, #6088, #6154, #6177, #6180, #6203, #6658
git-svn-id: http://code.djangoproject.com/svn/django/trunk@7477 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2008-04-27 10:50:16 +08:00
# model isn't loaded yet, so we need to pend the relation until the class
2008-02-27 05:13:16 +08:00
# is prepared.
2011-04-21 01:58:37 +08:00
model = get_model ( app_label , model_name ,
seed_cache = False , only_installed = False )
2006-06-23 12:37:00 +08:00
if model :
2008-07-29 20:41:08 +08:00
operation ( field , model , cls )
2006-06-23 12:37:00 +08:00
else :
2008-02-27 05:13:16 +08:00
key = ( app_label , model_name )
2008-07-29 20:41:08 +08:00
value = ( cls , field , operation )
2008-02-27 05:13:16 +08:00
pending_lookups . setdefault ( key , [ ] ) . append ( value )
Merged the queryset-refactor branch into trunk.
This is a big internal change, but mostly backwards compatible with existing
code. Also adds a couple of new features.
Fixed #245, #1050, #1656, #1801, #2076, #2091, #2150, #2253, #2306, #2400, #2430, #2482, #2496, #2676, #2737, #2874, #2902, #2939, #3037, #3141, #3288, #3440, #3592, #3739, #4088, #4260, #4289, #4306, #4358, #4464, #4510, #4858, #5012, #5020, #5261, #5295, #5321, #5324, #5325, #5555, #5707, #5796, #5817, #5987, #6018, #6074, #6088, #6154, #6177, #6180, #6203, #6658
git-svn-id: http://code.djangoproject.com/svn/django/trunk@7477 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2008-04-27 10:50:16 +08:00
2008-08-06 23:32:46 +08:00
def do_pending_lookups ( sender , * * kwargs ) :
2008-02-27 05:13:16 +08:00
"""
Handle any pending relations to the sending model . Sent from class_prepared .
"""
key = ( sender . _meta . app_label , sender . __name__ )
2008-07-29 20:41:08 +08:00
for cls , field , operation in pending_lookups . pop ( key , [ ] ) :
operation ( field , sender , cls )
2006-05-02 09:31:56 +08:00
2008-08-06 23:32:46 +08:00
signals . class_prepared . connect ( do_pending_lookups )
2006-05-02 09:31:56 +08:00
#HACK
class RelatedField ( object ) :
def contribute_to_class ( self , cls , name ) :
sup = super ( RelatedField , self )
2010-03-27 23:54:31 +08:00
# Store the opts for related_query_name()
self . opts = cls . _meta
2006-05-02 09:31:56 +08:00
if hasattr ( sup , ' contribute_to_class ' ) :
sup . contribute_to_class ( cls , name )
2008-06-26 15:04:18 +08:00
if not cls . _meta . abstract and self . rel . related_name :
2010-01-10 04:03:52 +08:00
self . rel . related_name = self . rel . related_name % {
' class ' : cls . __name__ . lower ( ) ,
' app_label ' : cls . _meta . app_label . lower ( ) ,
}
2008-06-26 15:04:18 +08:00
2006-05-02 09:31:56 +08:00
other = self . rel . to
2009-11-03 22:02:49 +08:00
if isinstance ( other , basestring ) or other . _meta . pk is None :
2008-07-29 20:41:08 +08:00
def resolve_related_class ( field , model , cls ) :
field . rel . to = model
field . do_related_class ( model , cls )
add_lazy_relation ( cls , self , other , resolve_related_class )
2006-05-02 09:31:56 +08:00
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 )
2008-07-29 13:17:47 +08:00
if self . verbose_name is None :
self . verbose_name = self . rel . to . _meta . verbose_name
2006-05-02 09:31:56 +08:00
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 ( )
2009-06-15 22:30:51 +08:00
self . related = RelatedObject ( other , cls , self )
2008-06-26 15:04:18 +08:00
if not cls . _meta . abstract :
2009-06-15 22:30:51 +08:00
self . contribute_to_related_class ( other , self . related )
2006-05-02 09:31:56 +08:00
2010-03-27 23:16:27 +08:00
def get_prep_lookup ( self , lookup_type , value ) :
if hasattr ( value , ' prepare ' ) :
return value . prepare ( )
if hasattr ( value , ' _prepare ' ) :
return value . _prepare ( )
# FIXME: lt and gt are explicitly allowed to make
# get_(next/prev)_by_date work; other lookups are not allowed since that
# gets messy pretty quick. This is a good candidate for some refactoring
# in the future.
if lookup_type in [ ' exact ' , ' gt ' , ' lt ' , ' gte ' , ' lte ' ] :
return self . _pk_trace ( value , ' get_prep_lookup ' , lookup_type )
if lookup_type in ( ' range ' , ' in ' ) :
return [ self . _pk_trace ( v , ' get_prep_lookup ' , lookup_type ) for v in value ]
elif lookup_type == ' isnull ' :
return [ ]
raise TypeError ( " Related Field has invalid lookup: %s " % lookup_type )
2006-07-14 05:31:53 +08:00
2010-03-27 23:16:27 +08:00
def get_db_prep_lookup ( self , lookup_type , value , connection , prepared = False ) :
2009-12-22 23:18:51 +08:00
if not prepared :
value = self . get_prep_lookup ( lookup_type , value )
if hasattr ( value , ' get_compiler ' ) :
value = value . get_compiler ( connection = connection )
2009-03-01 12:12:30 +08:00
if hasattr ( value , ' as_sql ' ) or hasattr ( value , ' _as_sql ' ) :
2009-01-29 18:46:36 +08:00
# If the value has a relabel_aliases method, it will need to
# be invoked before the final SQL is evaluated
if hasattr ( value , ' relabel_aliases ' ) :
return value
2009-03-04 12:56:20 +08:00
if hasattr ( value , ' as_sql ' ) :
2009-03-01 12:12:30 +08:00
sql , params = value . as_sql ( )
2009-03-04 12:56:20 +08:00
else :
2009-12-22 23:18:51 +08:00
sql , params = value . _as_sql ( connection = connection )
Merged the queryset-refactor branch into trunk.
This is a big internal change, but mostly backwards compatible with existing
code. Also adds a couple of new features.
Fixed #245, #1050, #1656, #1801, #2076, #2091, #2150, #2253, #2306, #2400, #2430, #2482, #2496, #2676, #2737, #2874, #2902, #2939, #3037, #3141, #3288, #3440, #3592, #3739, #4088, #4260, #4289, #4306, #4358, #4464, #4510, #4858, #5012, #5020, #5261, #5295, #5321, #5324, #5325, #5555, #5707, #5796, #5817, #5987, #6018, #6074, #6088, #6154, #6177, #6180, #6203, #6658
git-svn-id: http://code.djangoproject.com/svn/django/trunk@7477 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2008-04-27 10:50:16 +08:00
return QueryWrapper ( ( ' ( %s ) ' % sql ) , params )
2008-09-02 05:04:01 +08:00
2010-03-27 23:16:27 +08:00
# FIXME: lt and gt are explicitly allowed to make
2008-09-02 05:04:01 +08:00
# get_(next/prev)_by_date work; other lookups are not allowed since that
# gets messy pretty quick. This is a good candidate for some refactoring
# in the future.
2009-05-08 00:12:08 +08:00
if lookup_type in [ ' exact ' , ' gt ' , ' lt ' , ' gte ' , ' lte ' ] :
2010-03-27 23:16:27 +08:00
return [ self . _pk_trace ( value , ' get_db_prep_lookup ' , lookup_type ,
connection = connection , prepared = prepared ) ]
2008-08-29 10:40:50 +08:00
if lookup_type in ( ' range ' , ' in ' ) :
2010-03-27 23:16:27 +08:00
return [ self . _pk_trace ( v , ' get_db_prep_lookup ' , lookup_type ,
connection = connection , prepared = prepared )
for v in value ]
2006-07-01 09:14:41 +08:00
elif lookup_type == ' isnull ' :
return [ ]
2010-01-11 02:36:20 +08:00
raise TypeError ( " Related Field has invalid lookup: %s " % lookup_type )
2006-07-14 05:31:53 +08:00
2010-03-27 23:16:27 +08:00
def _pk_trace ( self , value , prep_func , lookup_type , * * kwargs ) :
# Value may be a primary key, or an object held in a relation.
# If it is an object, then we need to get the primary key value for
# that object. In certain conditions (especially one-to-one relations),
# the primary key may itself be an object - so we need to keep drilling
# down until we hit a value that can be used for a comparison.
v = value
2011-01-25 11:14:28 +08:00
# In the case of an FK to 'self', this check allows to_field to be used
# for both forwards and reverse lookups across the FK. (For normal FKs,
# it's only relevant for forward lookups).
if isinstance ( v , self . rel . to ) :
field_name = getattr ( self . rel , " field_name " , None )
else :
field_name = None
2010-03-27 23:16:27 +08:00
try :
while True :
2011-01-25 11:14:28 +08:00
if field_name is None :
field_name = v . _meta . pk . name
v = getattr ( v , field_name )
field_name = None
2010-03-27 23:16:27 +08:00
except AttributeError :
pass
except exceptions . ObjectDoesNotExist :
v = None
field = self
while field . rel :
if hasattr ( field . rel , ' field_name ' ) :
field = field . rel . to . _meta . get_field ( field . rel . field_name )
else :
field = field . rel . to . _meta . pk
if lookup_type in ( ' range ' , ' in ' ) :
v = [ v ]
v = getattr ( field , prep_func ) ( lookup_type , v , * * kwargs )
if isinstance ( v , list ) :
v = v [ 0 ]
return v
2010-03-27 23:54:31 +08:00
def related_query_name ( self ) :
Merged the queryset-refactor branch into trunk.
This is a big internal change, but mostly backwards compatible with existing
code. Also adds a couple of new features.
Fixed #245, #1050, #1656, #1801, #2076, #2091, #2150, #2253, #2306, #2400, #2430, #2482, #2496, #2676, #2737, #2874, #2902, #2939, #3037, #3141, #3288, #3440, #3592, #3739, #4088, #4260, #4289, #4306, #4358, #4464, #4510, #4858, #5012, #5020, #5261, #5295, #5321, #5324, #5325, #5555, #5707, #5796, #5817, #5987, #6018, #6074, #6088, #6154, #6177, #6180, #6203, #6658
git-svn-id: http://code.djangoproject.com/svn/django/trunk@7477 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2008-04-27 10:50:16 +08:00
# This method defines the name that can be used to identify this
# related object in a table-spanning query. It uses the lower-cased
# object_name by default, but this can be overridden with the
# "related_name" option.
2010-03-27 23:54:31 +08:00
return self . rel . related_name or self . opts . object_name . lower ( )
2006-05-02 09:31:56 +08:00
class SingleRelatedObjectDescriptor ( object ) :
# This class provides the functionality that makes the related-object
# managers available as attributes on a model class, for fields that have
# a single "remote" value, on the class pointed to by a related field.
# In the example "place.restaurant", the restaurant attribute is a
# SingleRelatedObjectDescriptor instance.
def __init__ ( self , related ) :
self . related = related
2010-01-27 21:30:29 +08:00
self . cache_name = related . get_cache_name ( )
2006-05-02 09:31:56 +08:00
2011-10-08 00:05:53 +08:00
def is_cached ( self , instance ) :
return hasattr ( instance , self . cache_name )
def get_query_set ( self , * * db_hints ) :
db = router . db_for_read ( self . related . model , * * db_hints )
return self . related . model . _base_manager . using ( db )
def get_prefetch_query_set ( self , instances ) :
2011-10-08 21:50:29 +08:00
vals = set ( instance . _get_pk_val ( ) for instance in instances )
2011-10-08 00:05:53 +08:00
params = { ' %s __pk__in ' % self . related . field . name : vals }
return ( self . get_query_set ( ) ,
attrgetter ( self . related . field . attname ) ,
lambda obj : obj . _get_pk_val ( ) ,
True ,
self . cache_name )
2006-05-02 09:31:56 +08:00
def __get__ ( self , instance , instance_type = None ) :
if instance is None :
2008-12-03 06:09:51 +08:00
return self
Merged the queryset-refactor branch into trunk.
This is a big internal change, but mostly backwards compatible with existing
code. Also adds a couple of new features.
Fixed #245, #1050, #1656, #1801, #2076, #2091, #2150, #2253, #2306, #2400, #2430, #2482, #2496, #2676, #2737, #2874, #2902, #2939, #3037, #3141, #3288, #3440, #3592, #3739, #4088, #4260, #4289, #4306, #4358, #4464, #4510, #4858, #5012, #5020, #5261, #5295, #5321, #5324, #5325, #5555, #5707, #5796, #5817, #5987, #6018, #6074, #6088, #6154, #6177, #6180, #6203, #6658
git-svn-id: http://code.djangoproject.com/svn/django/trunk@7477 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2008-04-27 10:50:16 +08:00
try :
return getattr ( instance , self . cache_name )
except AttributeError :
params = { ' %s __pk ' % self . related . field . name : instance . _get_pk_val ( ) }
2011-10-08 00:05:53 +08:00
rel_obj = self . get_query_set ( instance = instance ) . get ( * * params )
Merged the queryset-refactor branch into trunk.
This is a big internal change, but mostly backwards compatible with existing
code. Also adds a couple of new features.
Fixed #245, #1050, #1656, #1801, #2076, #2091, #2150, #2253, #2306, #2400, #2430, #2482, #2496, #2676, #2737, #2874, #2902, #2939, #3037, #3141, #3288, #3440, #3592, #3739, #4088, #4260, #4289, #4306, #4358, #4464, #4510, #4858, #5012, #5020, #5261, #5295, #5321, #5324, #5325, #5555, #5707, #5796, #5817, #5987, #6018, #6074, #6088, #6154, #6177, #6180, #6203, #6658
git-svn-id: http://code.djangoproject.com/svn/django/trunk@7477 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2008-04-27 10:50:16 +08:00
setattr ( instance , self . cache_name , rel_obj )
return rel_obj
2006-05-02 09:31:56 +08:00
def __set__ ( self , instance , value ) :
if instance is None :
2010-01-11 02:36:20 +08:00
raise AttributeError ( " %s must be accessed via instance " % self . related . opts . object_name )
2008-06-29 18:35:35 +08:00
# The similarity of the code below to the code in
2008-06-05 08:39:32 +08:00
# ReverseSingleRelatedObjectDescriptor is annoying, but there's a bunch
# of small differences that would make a common base class convoluted.
2008-06-29 18:35:35 +08:00
2008-06-05 08:39:32 +08:00
# If null=True, we can assign null here, but otherwise the value needs
# to be an instance of the related class.
if value is None and self . related . field . null == False :
raise ValueError ( ' Cannot assign None: " %s . %s " does not allow null values. ' %
( instance . _meta . object_name , self . related . get_accessor_name ( ) ) )
elif value is not None and not isinstance ( value , self . related . model ) :
raise ValueError ( ' Cannot assign " %r " : " %s . %s " must be a " %s " instance. ' %
2008-06-29 18:35:35 +08:00
( value , instance . _meta . object_name ,
2008-06-05 08:39:32 +08:00
self . related . get_accessor_name ( ) , self . related . opts . object_name ) )
2010-01-22 22:30:06 +08:00
elif value is not None :
if instance . _state . db is None :
instance . _state . db = router . db_for_write ( instance . __class__ , instance = value )
elif value . _state . db is None :
value . _state . db = router . db_for_write ( value . __class__ , instance = instance )
elif value . _state . db is not None and instance . _state . db is not None :
if not router . allow_relation ( value , instance ) :
2010-02-24 00:09:39 +08:00
raise ValueError ( ' Cannot assign " %r " : instance is on database " %s " , value is on database " %s " ' %
2010-01-22 22:30:06 +08:00
( value , instance . _state . db , value . _state . db ) )
2008-06-29 18:35:35 +08:00
2009-03-31 06:38:19 +08:00
# Set the value of the related field to the value of the related object's related field
setattr ( value , self . related . field . attname , getattr ( instance , self . related . field . rel . get_related_field ( ) . attname ) )
2006-05-02 09:31:56 +08:00
2008-06-05 08:39:32 +08:00
# Since we already know what the related object is, seed the related
2008-06-29 18:35:35 +08:00
# object caches now, too. This avoids another db hit if you get the
2008-06-05 08:39:32 +08:00
# object you just set.
setattr ( instance , self . cache_name , value )
setattr ( value , self . related . field . get_cache_name ( ) , instance )
2006-05-02 09:31:56 +08:00
class ReverseSingleRelatedObjectDescriptor ( object ) :
# This class provides the functionality that makes the related-object
# managers available as attributes on a model class, for fields that have
# a single "remote" value, on the class that defines the related field.
# In the example "choice.poll", the poll attribute is a
# ReverseSingleRelatedObjectDescriptor instance.
def __init__ ( self , field_with_rel ) :
self . field = field_with_rel
2011-10-08 00:05:53 +08:00
self . cache_name = self . field . get_cache_name ( )
def is_cached ( self , instance ) :
return hasattr ( instance , self . cache_name )
def get_query_set ( self , * * db_hints ) :
db = router . db_for_read ( self . field . rel . to , * * db_hints )
rel_mgr = self . field . rel . to . _default_manager
# If the related manager indicates that it should be used for
# related fields, respect that.
if getattr ( rel_mgr , ' use_for_related_fields ' , False ) :
return rel_mgr . using ( db )
else :
return QuerySet ( self . field . rel . to ) . using ( db )
def get_prefetch_query_set ( self , instances ) :
2011-10-08 21:50:29 +08:00
vals = set ( getattr ( instance , self . field . attname ) for instance in instances )
2011-10-08 00:05:53 +08:00
other_field = self . field . rel . get_related_field ( )
if other_field . rel :
params = { ' %s __pk__in ' % self . field . rel . field_name : vals }
else :
params = { ' %s __in ' % self . field . rel . field_name : vals }
return ( self . get_query_set ( ) . filter ( * * params ) ,
attrgetter ( self . field . rel . field_name ) ,
attrgetter ( self . field . attname ) ,
True ,
self . cache_name )
2006-05-02 09:31:56 +08:00
def __get__ ( self , instance , instance_type = None ) :
if instance is None :
2008-12-03 06:09:51 +08:00
return self
2009-06-15 22:30:51 +08:00
2006-05-02 09:31:56 +08:00
try :
2011-10-08 00:05:53 +08:00
return getattr ( instance , self . cache_name )
2006-05-02 09:31:56 +08:00
except AttributeError :
val = getattr ( instance , self . field . attname )
if val is None :
# If NULL is an allowed value, return it.
if self . field . null :
return None
raise self . field . rel . to . DoesNotExist
other_field = self . field . rel . get_related_field ( )
if other_field . rel :
params = { ' %s __pk ' % self . field . rel . field_name : val }
else :
params = { ' %s __exact ' % self . field . rel . field_name : val }
2011-10-08 00:05:53 +08:00
qs = self . get_query_set ( instance = instance )
rel_obj = qs . get ( * * params )
setattr ( instance , self . cache_name , rel_obj )
2006-05-02 09:31:56 +08:00
return rel_obj
def __set__ ( self , instance , value ) :
if instance is None :
2010-01-11 02:36:20 +08:00
raise AttributeError ( " %s must be accessed via instance " % self . _field . name )
2008-06-29 18:35:35 +08:00
2008-06-05 08:39:32 +08:00
# If null=True, we can assign null here, but otherwise the value needs
# to be an instance of the related class.
if value is None and self . field . null == False :
raise ValueError ( ' Cannot assign None: " %s . %s " does not allow null values. ' %
( instance . _meta . object_name , self . field . name ) )
elif value is not None and not isinstance ( value , self . field . rel . to ) :
raise ValueError ( ' Cannot assign " %r " : " %s . %s " must be a " %s " instance. ' %
2008-06-29 18:35:35 +08:00
( value , instance . _meta . object_name ,
2008-06-05 08:39:32 +08:00
self . field . name , self . field . rel . to . _meta . object_name ) )
2010-01-22 22:30:06 +08:00
elif value is not None :
2009-12-22 23:18:51 +08:00
if instance . _state . db is None :
2010-01-22 22:30:06 +08:00
instance . _state . db = router . db_for_write ( instance . __class__ , instance = value )
elif value . _state . db is None :
value . _state . db = router . db_for_write ( value . __class__ , instance = instance )
elif value . _state . db is not None and instance . _state . db is not None :
if not router . allow_relation ( value , instance ) :
2010-02-24 00:09:39 +08:00
raise ValueError ( ' Cannot assign " %r " : instance is on database " %s " , value is on database " %s " ' %
2010-01-22 22:30:06 +08:00
( value , instance . _state . db , value . _state . db ) )
2008-06-29 18:35:35 +08:00
2009-06-15 22:30:51 +08:00
# If we're setting the value of a OneToOneField to None, we need to clear
# out the cache on any old related object. Otherwise, deleting the
# previously-related object will also cause this object to be deleted,
# which is wrong.
if value is None :
# Look up the previously-related object, which may still be available
# since we've not yet cleared out the related field.
# Use the cache directly, instead of the accessor; if we haven't
# populated the cache, then we don't care - we're only accessing
# the object to invalidate the accessor cache, so there's no
# need to populate the cache just to expire it again.
related = getattr ( instance , self . field . get_cache_name ( ) , None )
# If we've got an old related object, we need to clear out its
# cache. This cache also might not exist if the related object
# hasn't been accessed yet.
if related :
2010-01-27 21:30:29 +08:00
cache_name = self . field . related . get_cache_name ( )
2009-06-15 22:30:51 +08:00
try :
delattr ( related , cache_name )
except AttributeError :
pass
2006-05-02 09:31:56 +08:00
# Set the value of the related field
try :
val = getattr ( value , self . field . rel . get_related_field ( ) . attname )
except AttributeError :
val = None
setattr ( instance , self . field . attname , val )
2008-06-05 08:39:32 +08:00
# Since we already know what the related object is, seed the related
2008-06-29 18:35:35 +08:00
# object cache now, too. This avoids another db hit if you get the
2008-06-05 08:39:32 +08:00
# object you just set.
setattr ( instance , self . field . get_cache_name ( ) , value )
2006-05-02 09:31:56 +08:00
class ForeignRelatedObjectsDescriptor ( object ) :
# This class provides the functionality that makes the related-object
# managers available as attributes on a model class, for fields that have
# multiple "remote" values and have a ForeignKey pointed at them by
# some other model. In the example "poll.choice_set", the choice_set
# attribute is a ForeignRelatedObjectsDescriptor instance.
def __init__ ( self , related ) :
self . related = related # RelatedObject instance
def __get__ ( self , instance , instance_type = None ) :
if instance is None :
2008-12-03 06:09:51 +08:00
return self
2006-05-02 09:31:56 +08:00
2011-10-06 19:08:11 +08:00
return self . related_manager_cls ( instance )
2009-03-20 11:57:12 +08:00
def __set__ ( self , instance , value ) :
if instance is None :
2010-01-11 02:36:20 +08:00
raise AttributeError ( " Manager must be accessed via instance " )
2009-03-20 11:57:12 +08:00
manager = self . __get__ ( instance )
# If the foreign key can support nulls, then completely clear the related set.
# Otherwise, just move the named objects into the set.
if self . related . field . null :
manager . clear ( )
manager . add ( * value )
2011-10-06 19:08:11 +08:00
@cached_property
def related_manager_cls ( self ) :
# Dynamically create a class that subclasses the related model's default
# manager.
superclass = self . related . model . _default_manager . __class__
2006-05-02 09:31:56 +08:00
rel_field = self . related . field
2011-09-30 18:41:25 +08:00
rel_model = self . related . model
attname = rel_field . rel . get_related_field ( ) . attname
2006-05-02 09:31:56 +08:00
class RelatedManager ( superclass ) :
2011-09-30 18:41:25 +08:00
def __init__ ( self , instance ) :
2011-09-29 23:30:19 +08:00
super ( RelatedManager , self ) . __init__ ( )
self . instance = instance
2011-09-30 18:41:25 +08:00
self . core_filters = {
' %s __ %s ' % ( rel_field . name , attname ) : getattr ( instance , attname )
}
self . model = rel_model
2011-09-29 23:30:19 +08:00
2006-05-02 09:31:56 +08:00
def get_query_set ( self ) :
2011-10-06 07:14:52 +08:00
try :
return self . instance . _prefetched_objects_cache [ rel_field . related_query_name ( ) ]
except ( AttributeError , KeyError ) :
db = self . _db or router . db_for_read ( self . model , instance = self . instance )
return super ( RelatedManager , self ) . get_query_set ( ) . using ( db ) . filter ( * * self . core_filters )
def get_prefetch_query_set ( self , instances ) :
db = self . _db or router . db_for_read ( self . model )
query = { ' %s __ %s __in ' % ( rel_field . name , attname ) :
2011-10-08 21:50:29 +08:00
set ( getattr ( obj , attname ) for obj in instances ) }
2011-10-06 07:14:52 +08:00
qs = super ( RelatedManager , self ) . get_query_set ( ) . using ( db ) . filter ( * * query )
2011-10-08 00:05:53 +08:00
return ( qs ,
attrgetter ( rel_field . get_attname ( ) ) ,
attrgetter ( attname ) ,
False ,
rel_field . related_query_name ( ) )
2006-05-02 09:31:56 +08:00
def add ( self , * objs ) :
for obj in objs :
2009-03-31 06:41:49 +08:00
if not isinstance ( obj , self . model ) :
2010-01-11 02:36:20 +08:00
raise TypeError ( " ' %s ' instance expected " % self . model . _meta . object_name )
2011-09-30 18:41:25 +08:00
setattr ( obj , rel_field . name , self . instance )
2010-01-22 22:30:06 +08:00
obj . save ( )
2006-05-02 09:31:56 +08:00
add . alters_data = True
def create ( self , * * kwargs ) :
2011-09-30 18:41:25 +08:00
kwargs [ rel_field . name ] = self . instance
2011-09-29 23:30:29 +08:00
db = router . db_for_write ( self . model , instance = self . instance )
2010-10-28 20:57:04 +08:00
return super ( RelatedManager , self . db_manager ( db ) ) . create ( * * kwargs )
2006-05-02 09:31:56 +08:00
create . alters_data = True
2008-08-17 04:59:06 +08:00
def get_or_create ( self , * * kwargs ) :
# Update kwargs with the related object that this
# ForeignRelatedObjectsDescriptor knows about.
2011-09-30 18:41:25 +08:00
kwargs [ rel_field . name ] = self . instance
2011-09-29 23:30:29 +08:00
db = router . db_for_write ( self . model , instance = self . instance )
2010-10-28 20:57:04 +08:00
return super ( RelatedManager , self . db_manager ( db ) ) . get_or_create ( * * kwargs )
2008-08-17 04:59:06 +08:00
get_or_create . alters_data = True
2006-05-02 09:31:56 +08:00
# remove() and clear() are only provided if the ForeignKey can have a value of null.
if rel_field . null :
def remove ( self , * objs ) :
2011-09-30 18:41:25 +08:00
val = getattr ( self . instance , attname )
2006-05-02 09:31:56 +08:00
for obj in objs :
# Is obj actually part of this descriptor set?
2011-09-30 18:41:25 +08:00
if getattr ( obj , rel_field . attname ) == val :
setattr ( obj , rel_field . name , None )
2010-01-22 22:30:06 +08:00
obj . save ( )
2006-05-02 09:31:56 +08:00
else :
2011-09-30 18:41:25 +08:00
raise rel_field . rel . to . DoesNotExist ( " %r is not related to %r . " % ( obj , self . instance ) )
2006-05-02 09:31:56 +08:00
remove . alters_data = True
def clear ( self ) :
2011-09-30 18:41:25 +08:00
self . update ( * * { rel_field . name : None } )
2006-05-02 09:31:56 +08:00
clear . alters_data = True
2011-09-30 18:41:25 +08:00
return RelatedManager
2006-05-02 09:31:56 +08:00
2011-09-29 23:30:29 +08:00
2011-09-29 23:30:19 +08:00
def create_many_related_manager ( superclass , rel ) :
2006-05-02 09:31:56 +08:00
""" Creates a manager that subclasses ' superclass ' (which is a Manager)
and adds behavior for many - to - many related objects . """
class ManyRelatedManager ( superclass ) :
2011-10-06 07:14:52 +08:00
def __init__ ( self , model = None , query_field_name = None , instance = None , symmetrical = None ,
2011-09-29 23:30:29 +08:00
source_field_name = None , target_field_name = None , reverse = False ,
2011-10-06 07:14:52 +08:00
through = None , prefetch_cache_name = None ) :
2006-05-02 09:31:56 +08:00
super ( ManyRelatedManager , self ) . __init__ ( )
self . model = model
2011-10-06 07:14:52 +08:00
self . query_field_name = query_field_name
self . core_filters = { ' %s __pk ' % query_field_name : instance . _get_pk_val ( ) }
2006-05-02 09:31:56 +08:00
self . instance = instance
2011-09-29 23:30:29 +08:00
self . symmetrical = symmetrical
2009-11-03 22:02:49 +08:00
self . source_field_name = source_field_name
self . target_field_name = target_field_name
2011-09-29 23:30:29 +08:00
self . reverse = reverse
2008-07-29 20:41:08 +08:00
self . through = through
2011-10-06 07:14:52 +08:00
self . prefetch_cache_name = prefetch_cache_name
2009-11-03 22:02:49 +08:00
self . _pk_val = self . instance . pk
2006-05-03 03:51:41 +08:00
if self . _pk_val is None :
2008-06-12 12:13:16 +08:00
raise ValueError ( " %r instance needs to have a primary key value before a many-to-many relationship can be used. " % instance . __class__ . __name__ )
2006-05-02 09:31:56 +08:00
def get_query_set ( self ) :
2011-10-06 07:14:52 +08:00
try :
return self . instance . _prefetched_objects_cache [ self . prefetch_cache_name ]
except ( AttributeError , KeyError ) :
db = self . _db or router . db_for_read ( self . instance . __class__ , instance = self . instance )
return super ( ManyRelatedManager , self ) . get_query_set ( ) . using ( db ) . _next_is_sticky ( ) . filter ( * * self . core_filters )
def get_prefetch_query_set ( self , instances ) :
from django . db import connections
db = self . _db or router . db_for_read ( self . model )
query = { ' %s __pk__in ' % self . query_field_name :
2011-10-08 21:50:29 +08:00
set ( obj . _get_pk_val ( ) for obj in instances ) }
2011-10-06 07:14:52 +08:00
qs = super ( ManyRelatedManager , self ) . get_query_set ( ) . using ( db ) . _next_is_sticky ( ) . filter ( * * query )
# M2M: need to annotate the query in order to get the primary model
# that the secondary model was actually related to. We know that
# there will already be a join on the join table, so we can just add
# the select.
# For non-autocreated 'through' models, can't assume we are
# dealing with PK values.
fk = self . through . _meta . get_field ( self . source_field_name )
source_col = fk . column
join_table = self . through . _meta . db_table
connection = connections [ db ]
qn = connection . ops . quote_name
qs = qs . extra ( select = { ' _prefetch_related_val ' :
' %s . %s ' % ( qn ( join_table ) , qn ( source_col ) ) } )
select_attname = fk . rel . get_related_field ( ) . get_attname ( )
2011-10-08 00:05:53 +08:00
return ( qs ,
attrgetter ( ' _prefetch_related_val ' ) ,
attrgetter ( select_attname ) ,
False ,
self . prefetch_cache_name )
2006-05-02 09:31:56 +08:00
2008-08-26 12:55:56 +08:00
# If the ManyToMany relation has an intermediary model,
2008-07-29 20:41:08 +08:00
# the add and remove methods do not exist.
2009-11-03 22:02:49 +08:00
if rel . through . _meta . auto_created :
2008-07-29 20:41:08 +08:00
def add ( self , * objs ) :
2009-11-03 22:02:49 +08:00
self . _add_items ( self . source_field_name , self . target_field_name , * objs )
2006-05-02 09:31:56 +08:00
2008-07-29 20:41:08 +08:00
# If this is a symmetrical m2m relation to self, add the mirror entry in the m2m table
if self . symmetrical :
2009-11-03 22:02:49 +08:00
self . _add_items ( self . target_field_name , self . source_field_name , * objs )
2008-07-29 20:41:08 +08:00
add . alters_data = True
2006-05-02 09:31:56 +08:00
2008-07-29 20:41:08 +08:00
def remove ( self , * objs ) :
2009-11-03 22:02:49 +08:00
self . _remove_items ( self . source_field_name , self . target_field_name , * objs )
2006-05-02 09:31:56 +08:00
2008-07-29 20:41:08 +08:00
# If this is a symmetrical m2m relation to self, remove the mirror entry in the m2m table
if self . symmetrical :
2009-11-03 22:02:49 +08:00
self . _remove_items ( self . target_field_name , self . source_field_name , * objs )
2008-07-29 20:41:08 +08:00
remove . alters_data = True
2006-05-02 09:31:56 +08:00
def clear ( self ) :
2009-11-03 22:02:49 +08:00
self . _clear_items ( self . source_field_name )
2006-05-02 09:31:56 +08:00
# If this is a symmetrical m2m relation to self, clear the mirror entry in the m2m table
if self . symmetrical :
2009-11-03 22:02:49 +08:00
self . _clear_items ( self . target_field_name )
2006-05-02 09:31:56 +08:00
clear . alters_data = True
def create ( self , * * kwargs ) :
2008-07-29 20:41:08 +08:00
# This check needs to be done here, since we can't later remove this
# from the method lookup table, as we do with add and remove.
2011-09-29 23:30:29 +08:00
if not self . through . _meta . auto_created :
opts = self . through . _meta
2010-01-11 02:36:20 +08:00
raise AttributeError ( " Cannot use create() on a ManyToManyField which specifies an intermediary model. Use %s . %s ' s Manager instead. " % ( opts . app_label , opts . object_name ) )
2010-01-22 22:30:06 +08:00
db = router . db_for_write ( self . instance . __class__ , instance = self . instance )
2010-10-28 20:57:04 +08:00
new_obj = super ( ManyRelatedManager , self . db_manager ( db ) ) . create ( * * kwargs )
2006-05-02 09:31:56 +08:00
self . add ( new_obj )
return new_obj
create . alters_data = True
2008-08-17 04:59:06 +08:00
def get_or_create ( self , * * kwargs ) :
2010-01-22 22:30:06 +08:00
db = router . db_for_write ( self . instance . __class__ , instance = self . instance )
2008-08-17 04:59:06 +08:00
obj , created = \
2010-10-28 20:57:04 +08:00
super ( ManyRelatedManager , self . db_manager ( db ) ) . get_or_create ( * * kwargs )
2008-08-17 04:59:06 +08:00
# We only need to add() if created because if we got an object back
# from get() then the relationship already exists.
if created :
self . add ( obj )
return obj , created
get_or_create . alters_data = True
2009-11-03 22:02:49 +08:00
def _add_items ( self , source_field_name , target_field_name , * objs ) :
2011-09-27 01:20:20 +08:00
# source_field_name: the PK fieldname in join table for the source object
# target_field_name: the PK fieldname in join table for the target object
2007-01-30 00:09:25 +08:00
# *objs - objects to add. Either object instances, or primary keys of object instances.
2006-05-02 09:31:56 +08:00
2006-12-20 21:57:17 +08:00
# If there aren't any objects, there is nothing to do.
2009-11-03 22:02:49 +08:00
from django . db . models import Model
2006-12-20 21:57:17 +08:00
if objs :
2007-01-30 00:09:25 +08:00
new_ids = set ( )
2006-12-20 22:06:27 +08:00
for obj in objs :
2007-01-30 00:09:25 +08:00
if isinstance ( obj , self . model ) :
2010-01-22 22:30:06 +08:00
if not router . allow_relation ( obj , self . instance ) :
2010-02-24 00:09:39 +08:00
raise ValueError ( ' Cannot add " %r " : instance is on database " %s " , value is on database " %s " ' %
2010-01-22 22:30:06 +08:00
( obj , self . instance . _state . db , obj . _state . db ) )
2009-11-03 22:02:49 +08:00
new_ids . add ( obj . pk )
2009-03-31 06:41:49 +08:00
elif isinstance ( obj , Model ) :
2010-01-11 02:36:20 +08:00
raise TypeError ( " ' %s ' instance expected " % self . model . _meta . object_name )
2007-01-30 00:09:25 +08:00
else :
new_ids . add ( obj )
2011-01-13 12:11:41 +08:00
db = router . db_for_write ( self . through , instance = self . instance )
2010-01-22 22:30:06 +08:00
vals = self . through . _default_manager . using ( db ) . values_list ( target_field_name , flat = True )
2009-11-03 22:02:49 +08:00
vals = vals . filter ( * * {
source_field_name : self . _pk_val ,
' %s __in ' % target_field_name : new_ids ,
} )
2010-01-13 19:07:16 +08:00
new_ids = new_ids - set ( vals )
2010-03-30 19:54:56 +08:00
if self . reverse or source_field_name == self . source_field_name :
# Don't send the signal when we are inserting the
# duplicate data row for symmetrical reverse entries.
2011-09-29 23:30:29 +08:00
signals . m2m_changed . send ( sender = self . through , action = ' pre_add ' ,
2010-03-30 19:54:56 +08:00
instance = self . instance , reverse = self . reverse ,
2010-08-07 14:27:52 +08:00
model = self . model , pk_set = new_ids , using = db )
2006-12-20 21:57:17 +08:00
# Add the ones that aren't there already
2011-09-10 03:22:28 +08:00
self . through . _default_manager . using ( db ) . bulk_create ( [
self . through ( * * {
2009-11-03 22:02:49 +08:00
' %s _id ' % source_field_name : self . _pk_val ,
' %s _id ' % target_field_name : obj_id ,
} )
2011-09-10 03:22:28 +08:00
for obj_id in new_ids
] )
2010-01-13 19:07:16 +08:00
if self . reverse or source_field_name == self . source_field_name :
# Don't send the signal when we are inserting the
# duplicate data row for symmetrical reverse entries.
2011-09-29 23:30:29 +08:00
signals . m2m_changed . send ( sender = self . through , action = ' post_add ' ,
2010-01-13 19:07:16 +08:00
instance = self . instance , reverse = self . reverse ,
2010-08-07 14:27:52 +08:00
model = self . model , pk_set = new_ids , using = db )
2006-05-02 09:31:56 +08:00
2009-11-03 22:02:49 +08:00
def _remove_items ( self , source_field_name , target_field_name , * objs ) :
2011-09-27 01:20:20 +08:00
# source_field_name: the PK colname in join table for the source object
# target_field_name: the PK colname in join table for the target object
2006-05-02 09:31:56 +08:00
# *objs - objects to remove
2006-12-20 22:06:27 +08:00
# If there aren't any objects, there is nothing to do.
if objs :
# Check that all the objects are of the right type
2007-01-30 00:09:25 +08:00
old_ids = set ( )
2006-12-20 22:06:27 +08:00
for obj in objs :
2007-01-30 00:09:25 +08:00
if isinstance ( obj , self . model ) :
2009-11-03 22:02:49 +08:00
old_ids . add ( obj . pk )
2007-01-30 00:09:25 +08:00
else :
old_ids . add ( obj )
2010-08-07 14:27:52 +08:00
# Work out what DB we're operating on
2011-01-13 12:11:41 +08:00
db = router . db_for_write ( self . through , instance = self . instance )
2010-08-07 14:27:52 +08:00
# Send a signal to the other end if need be.
2010-03-30 19:54:56 +08:00
if self . reverse or source_field_name == self . source_field_name :
# Don't send the signal when we are deleting the
# duplicate data row for symmetrical reverse entries.
2011-09-29 23:30:29 +08:00
signals . m2m_changed . send ( sender = self . through , action = " pre_remove " ,
2010-03-30 19:54:56 +08:00
instance = self . instance , reverse = self . reverse ,
2010-08-07 14:27:52 +08:00
model = self . model , pk_set = old_ids , using = db )
2006-12-20 22:06:27 +08:00
# Remove the specified objects from the join table
2010-01-22 22:30:06 +08:00
self . through . _default_manager . using ( db ) . filter ( * * {
2009-11-03 22:02:49 +08:00
source_field_name : self . _pk_val ,
' %s __in ' % target_field_name : old_ids
} ) . delete ( )
2010-01-13 19:07:16 +08:00
if self . reverse or source_field_name == self . source_field_name :
# Don't send the signal when we are deleting the
# duplicate data row for symmetrical reverse entries.
2011-09-29 23:30:29 +08:00
signals . m2m_changed . send ( sender = self . through , action = " post_remove " ,
2010-01-13 19:07:16 +08:00
instance = self . instance , reverse = self . reverse ,
2010-08-07 14:27:52 +08:00
model = self . model , pk_set = old_ids , using = db )
2009-11-03 22:02:49 +08:00
def _clear_items ( self , source_field_name ) :
2011-01-13 12:11:41 +08:00
db = router . db_for_write ( self . through , instance = self . instance )
2011-09-27 01:20:20 +08:00
# source_field_name: the PK colname in join table for the source object
2010-01-13 19:07:16 +08:00
if self . reverse or source_field_name == self . source_field_name :
# Don't send the signal when we are clearing the
# duplicate data rows for symmetrical reverse entries.
2011-09-29 23:30:29 +08:00
signals . m2m_changed . send ( sender = self . through , action = " pre_clear " ,
2010-01-13 19:07:16 +08:00
instance = self . instance , reverse = self . reverse ,
2010-08-07 14:27:52 +08:00
model = self . model , pk_set = None , using = db )
2010-01-22 22:30:06 +08:00
self . through . _default_manager . using ( db ) . filter ( * * {
2009-11-03 22:02:49 +08:00
source_field_name : self . _pk_val
} ) . delete ( )
2010-03-30 19:54:56 +08:00
if self . reverse or source_field_name == self . source_field_name :
# Don't send the signal when we are clearing the
# duplicate data rows for symmetrical reverse entries.
2011-09-29 23:30:29 +08:00
signals . m2m_changed . send ( sender = self . through , action = " post_clear " ,
2010-03-30 19:54:56 +08:00
instance = self . instance , reverse = self . reverse ,
2010-08-07 14:27:52 +08:00
model = self . model , pk_set = None , using = db )
2006-05-02 09:31:56 +08:00
return ManyRelatedManager
class ManyRelatedObjectsDescriptor ( object ) :
# This class provides the functionality that makes the related-object
# managers available as attributes on a model class, for fields that have
# multiple "remote" values and have a ManyToManyField pointed at them by
# some other model (rather than having a ManyToManyField themselves).
# In the example "publication.article_set", the article_set attribute is a
# ManyRelatedObjectsDescriptor instance.
def __init__ ( self , related ) :
self . related = related # RelatedObject instance
2011-09-30 18:41:25 +08:00
@cached_property
def related_manager_cls ( self ) :
# Dynamically create a class that subclasses the related
# model's default manager.
return create_many_related_manager (
self . related . model . _default_manager . __class__ ,
self . related . field . rel
)
2006-05-02 09:31:56 +08:00
def __get__ ( self , instance , instance_type = None ) :
if instance is None :
2008-12-03 06:09:51 +08:00
return self
2006-05-02 09:31:56 +08:00
rel_model = self . related . model
2011-09-30 18:41:25 +08:00
manager = self . related_manager_cls (
2006-05-02 09:31:56 +08:00
model = rel_model ,
2011-10-06 07:14:52 +08:00
query_field_name = self . related . field . name ,
prefetch_cache_name = self . related . field . related_query_name ( ) ,
2006-05-02 09:31:56 +08:00
instance = instance ,
symmetrical = False ,
2009-11-03 22:02:49 +08:00
source_field_name = self . related . field . m2m_reverse_field_name ( ) ,
2010-01-13 19:07:16 +08:00
target_field_name = self . related . field . m2m_field_name ( ) ,
2011-09-29 23:30:29 +08:00
reverse = True ,
through = self . related . field . rel . through ,
2006-05-02 09:31:56 +08:00
)
return manager
def __set__ ( self , instance , value ) :
if instance is None :
2010-01-11 02:36:20 +08:00
raise AttributeError ( " Manager must be accessed via instance " )
2006-05-02 09:31:56 +08:00
2009-11-03 22:02:49 +08:00
if not self . related . field . rel . through . _meta . auto_created :
opts = self . related . field . rel . through . _meta
2010-01-11 02:36:20 +08:00
raise AttributeError ( " Cannot set values on a ManyToManyField which specifies an intermediary model. Use %s . %s ' s Manager instead. " % ( opts . app_label , opts . object_name ) )
2008-07-29 20:41:08 +08:00
2006-05-02 09:31:56 +08:00
manager = self . __get__ ( instance )
manager . clear ( )
2006-12-20 17:59:03 +08:00
manager . add ( * value )
2006-05-02 09:31:56 +08:00
2010-01-13 19:07:16 +08:00
2006-05-02 09:31:56 +08:00
class ReverseManyRelatedObjectsDescriptor ( object ) :
# This class provides the functionality that makes the related-object
# managers available as attributes on a model class, for fields that have
# multiple "remote" values and have a ManyToManyField defined in their
# model (rather than having another model pointed *at* them).
# In the example "article.publications", the publications attribute is a
# ReverseManyRelatedObjectsDescriptor instance.
def __init__ ( self , m2m_field ) :
self . field = m2m_field
2009-11-13 20:34:41 +08:00
2011-09-10 03:22:28 +08:00
@property
def through ( self ) :
2009-11-03 23:02:16 +08:00
# through is provided so that you have easy access to the through
2009-11-13 20:34:41 +08:00
# model (Book.authors.through) for inlines, etc. This is done as
# a property to ensure that the fully resolved value is returned.
return self . field . rel . through
2006-05-02 09:31:56 +08:00
2011-09-30 18:41:25 +08:00
@cached_property
def related_manager_cls ( self ) :
# Dynamically create a class that subclasses the related model's
# default manager.
return create_many_related_manager (
self . field . rel . to . _default_manager . __class__ ,
self . field . rel
)
2006-05-02 09:31:56 +08:00
def __get__ ( self , instance , instance_type = None ) :
if instance is None :
2008-12-03 06:09:51 +08:00
return self
2006-05-02 09:31:56 +08:00
2011-09-30 18:41:25 +08:00
manager = self . related_manager_cls (
model = self . field . rel . to ,
2011-10-06 07:14:52 +08:00
query_field_name = self . field . related_query_name ( ) ,
prefetch_cache_name = self . field . name ,
2006-05-02 09:31:56 +08:00
instance = instance ,
2010-04-02 23:44:48 +08:00
symmetrical = self . field . rel . symmetrical ,
2009-11-03 22:02:49 +08:00
source_field_name = self . field . m2m_field_name ( ) ,
2010-01-13 19:07:16 +08:00
target_field_name = self . field . m2m_reverse_field_name ( ) ,
2011-09-29 23:30:29 +08:00
reverse = False ,
through = self . field . rel . through ,
2006-05-02 09:31:56 +08:00
)
return manager
def __set__ ( self , instance , value ) :
if instance is None :
2010-01-11 02:36:20 +08:00
raise AttributeError ( " Manager must be accessed via instance " )
2006-05-02 09:31:56 +08:00
2009-11-03 22:02:49 +08:00
if not self . field . rel . through . _meta . auto_created :
opts = self . field . rel . through . _meta
2010-01-11 02:36:20 +08:00
raise AttributeError ( " Cannot set values on a ManyToManyField which specifies an intermediary model. Use %s . %s ' s Manager instead. " % ( opts . app_label , opts . object_name ) )
2008-07-29 20:41:08 +08:00
2006-05-02 09:31:56 +08:00
manager = self . __get__ ( instance )
manager . clear ( )
2006-12-20 17:59:03 +08:00
manager . add ( * value )
2006-05-02 09:31:56 +08:00
Merged the queryset-refactor branch into trunk.
This is a big internal change, but mostly backwards compatible with existing
code. Also adds a couple of new features.
Fixed #245, #1050, #1656, #1801, #2076, #2091, #2150, #2253, #2306, #2400, #2430, #2482, #2496, #2676, #2737, #2874, #2902, #2939, #3037, #3141, #3288, #3440, #3592, #3739, #4088, #4260, #4289, #4306, #4358, #4464, #4510, #4858, #5012, #5020, #5261, #5295, #5321, #5324, #5325, #5555, #5707, #5796, #5817, #5987, #6018, #6074, #6088, #6154, #6177, #6180, #6203, #6658
git-svn-id: http://code.djangoproject.com/svn/django/trunk@7477 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2008-04-27 10:50:16 +08:00
class ManyToOneRel ( object ) :
2010-11-10 00:46:42 +08:00
def __init__ ( self , to , field_name , related_name = None , limit_choices_to = None ,
parent_link = False , on_delete = None ) :
Merged the queryset-refactor branch into trunk.
This is a big internal change, but mostly backwards compatible with existing
code. Also adds a couple of new features.
Fixed #245, #1050, #1656, #1801, #2076, #2091, #2150, #2253, #2306, #2400, #2430, #2482, #2496, #2676, #2737, #2874, #2902, #2939, #3037, #3141, #3288, #3440, #3592, #3739, #4088, #4260, #4289, #4306, #4358, #4464, #4510, #4858, #5012, #5020, #5261, #5295, #5321, #5324, #5325, #5555, #5707, #5796, #5817, #5987, #6018, #6074, #6088, #6154, #6177, #6180, #6203, #6658
git-svn-id: http://code.djangoproject.com/svn/django/trunk@7477 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2008-04-27 10:50:16 +08:00
try :
to . _meta
except AttributeError : # to._meta doesn't exist, so it must be RECURSIVE_RELATIONSHIP_CONSTANT
assert isinstance ( to , basestring ) , " ' to ' must be either a model, a model name or the string %r " % RECURSIVE_RELATIONSHIP_CONSTANT
self . to , self . field_name = to , field_name
Removed oldforms, validators, and related code:
* Removed `Manipulator`, `AutomaticManipulator`, and related classes.
* Removed oldforms specific bits from model fields:
* Removed `validator_list` and `core` arguments from constructors.
* Removed the methods:
* `get_manipulator_field_names`
* `get_manipulator_field_objs`
* `get_manipulator_fields`
* `get_manipulator_new_data`
* `prepare_field_objs_and_params`
* `get_follow`
* Renamed `flatten_data` method to `value_to_string` for better alignment with its use by the serialization framework, which was the only remaining code using `flatten_data`.
* Removed oldforms methods from `django.db.models.Options` class: `get_followed_related_objects`, `get_data_holders`, `get_follow`, and `has_field_type`.
* Removed oldforms-admin specific options from `django.db.models.fields.related` classes: `num_in_admin`, `min_num_in_admin`, `max_num_in_admin`, `num_extra_on_change`, and `edit_inline`.
* Serialization framework
* `Serializer.get_string_value` now calls the model fields' renamed `value_to_string` methods.
* Removed a special-casing of `models.DateTimeField` in `core.serializers.base.Serializer.get_string_value` that's handled by `django.db.models.fields.DateTimeField.value_to_string`.
* Removed `django.core.validators`:
* Moved `ValidationError` exception to `django.core.exceptions`.
* For the couple places that were using validators, brought over the necessary code to maintain the same functionality.
* Introduced a SlugField form field for validation and to compliment the SlugField model field (refs #8040).
* Removed an oldforms-style model creation hack (refs #2160).
git-svn-id: http://code.djangoproject.com/svn/django/trunk@8616 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2008-08-27 15:19:44 +08:00
self . related_name = related_name
Merged the queryset-refactor branch into trunk.
This is a big internal change, but mostly backwards compatible with existing
code. Also adds a couple of new features.
Fixed #245, #1050, #1656, #1801, #2076, #2091, #2150, #2253, #2306, #2400, #2430, #2482, #2496, #2676, #2737, #2874, #2902, #2939, #3037, #3141, #3288, #3440, #3592, #3739, #4088, #4260, #4289, #4306, #4358, #4464, #4510, #4858, #5012, #5020, #5261, #5295, #5321, #5324, #5325, #5555, #5707, #5796, #5817, #5987, #6018, #6074, #6088, #6154, #6177, #6180, #6203, #6658
git-svn-id: http://code.djangoproject.com/svn/django/trunk@7477 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2008-04-27 10:50:16 +08:00
if limit_choices_to is None :
limit_choices_to = { }
self . limit_choices_to = limit_choices_to
self . multiple = True
self . parent_link = parent_link
2010-11-10 00:46:42 +08:00
self . on_delete = on_delete
Merged the queryset-refactor branch into trunk.
This is a big internal change, but mostly backwards compatible with existing
code. Also adds a couple of new features.
Fixed #245, #1050, #1656, #1801, #2076, #2091, #2150, #2253, #2306, #2400, #2430, #2482, #2496, #2676, #2737, #2874, #2902, #2939, #3037, #3141, #3288, #3440, #3592, #3739, #4088, #4260, #4289, #4306, #4358, #4464, #4510, #4858, #5012, #5020, #5261, #5295, #5321, #5324, #5325, #5555, #5707, #5796, #5817, #5987, #6018, #6074, #6088, #6154, #6177, #6180, #6203, #6658
git-svn-id: http://code.djangoproject.com/svn/django/trunk@7477 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2008-04-27 10:50:16 +08:00
2009-11-03 22:02:49 +08:00
def is_hidden ( self ) :
" Should the related object be hidden? "
return self . related_name and self . related_name [ - 1 ] == ' + '
Merged the queryset-refactor branch into trunk.
This is a big internal change, but mostly backwards compatible with existing
code. Also adds a couple of new features.
Fixed #245, #1050, #1656, #1801, #2076, #2091, #2150, #2253, #2306, #2400, #2430, #2482, #2496, #2676, #2737, #2874, #2902, #2939, #3037, #3141, #3288, #3440, #3592, #3739, #4088, #4260, #4289, #4306, #4358, #4464, #4510, #4858, #5012, #5020, #5261, #5295, #5321, #5324, #5325, #5555, #5707, #5796, #5817, #5987, #6018, #6074, #6088, #6154, #6177, #6180, #6203, #6658
git-svn-id: http://code.djangoproject.com/svn/django/trunk@7477 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2008-04-27 10:50:16 +08:00
def get_related_field ( self ) :
"""
Returns the Field in the ' to ' object to which this relationship is
tied .
"""
data = self . to . _meta . get_field_by_name ( self . field_name )
if not data [ 2 ] :
raise FieldDoesNotExist ( " No related field named ' %s ' " %
self . field_name )
return data [ 0 ]
class OneToOneRel ( ManyToOneRel ) :
2010-11-10 00:46:42 +08:00
def __init__ ( self , to , field_name , related_name = None , limit_choices_to = None ,
parent_link = False , on_delete = None ) :
Removed oldforms, validators, and related code:
* Removed `Manipulator`, `AutomaticManipulator`, and related classes.
* Removed oldforms specific bits from model fields:
* Removed `validator_list` and `core` arguments from constructors.
* Removed the methods:
* `get_manipulator_field_names`
* `get_manipulator_field_objs`
* `get_manipulator_fields`
* `get_manipulator_new_data`
* `prepare_field_objs_and_params`
* `get_follow`
* Renamed `flatten_data` method to `value_to_string` for better alignment with its use by the serialization framework, which was the only remaining code using `flatten_data`.
* Removed oldforms methods from `django.db.models.Options` class: `get_followed_related_objects`, `get_data_holders`, `get_follow`, and `has_field_type`.
* Removed oldforms-admin specific options from `django.db.models.fields.related` classes: `num_in_admin`, `min_num_in_admin`, `max_num_in_admin`, `num_extra_on_change`, and `edit_inline`.
* Serialization framework
* `Serializer.get_string_value` now calls the model fields' renamed `value_to_string` methods.
* Removed a special-casing of `models.DateTimeField` in `core.serializers.base.Serializer.get_string_value` that's handled by `django.db.models.fields.DateTimeField.value_to_string`.
* Removed `django.core.validators`:
* Moved `ValidationError` exception to `django.core.exceptions`.
* For the couple places that were using validators, brought over the necessary code to maintain the same functionality.
* Introduced a SlugField form field for validation and to compliment the SlugField model field (refs #8040).
* Removed an oldforms-style model creation hack (refs #2160).
git-svn-id: http://code.djangoproject.com/svn/django/trunk@8616 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2008-08-27 15:19:44 +08:00
super ( OneToOneRel , self ) . __init__ ( to , field_name ,
related_name = related_name , limit_choices_to = limit_choices_to ,
2010-11-10 00:46:42 +08:00
parent_link = parent_link , on_delete = on_delete
)
Merged the queryset-refactor branch into trunk.
This is a big internal change, but mostly backwards compatible with existing
code. Also adds a couple of new features.
Fixed #245, #1050, #1656, #1801, #2076, #2091, #2150, #2253, #2306, #2400, #2430, #2482, #2496, #2676, #2737, #2874, #2902, #2939, #3037, #3141, #3288, #3440, #3592, #3739, #4088, #4260, #4289, #4306, #4358, #4464, #4510, #4858, #5012, #5020, #5261, #5295, #5321, #5324, #5325, #5555, #5707, #5796, #5817, #5987, #6018, #6074, #6088, #6154, #6177, #6180, #6203, #6658
git-svn-id: http://code.djangoproject.com/svn/django/trunk@7477 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2008-04-27 10:50:16 +08:00
self . multiple = False
class ManyToManyRel ( object ) :
Removed oldforms, validators, and related code:
* Removed `Manipulator`, `AutomaticManipulator`, and related classes.
* Removed oldforms specific bits from model fields:
* Removed `validator_list` and `core` arguments from constructors.
* Removed the methods:
* `get_manipulator_field_names`
* `get_manipulator_field_objs`
* `get_manipulator_fields`
* `get_manipulator_new_data`
* `prepare_field_objs_and_params`
* `get_follow`
* Renamed `flatten_data` method to `value_to_string` for better alignment with its use by the serialization framework, which was the only remaining code using `flatten_data`.
* Removed oldforms methods from `django.db.models.Options` class: `get_followed_related_objects`, `get_data_holders`, `get_follow`, and `has_field_type`.
* Removed oldforms-admin specific options from `django.db.models.fields.related` classes: `num_in_admin`, `min_num_in_admin`, `max_num_in_admin`, `num_extra_on_change`, and `edit_inline`.
* Serialization framework
* `Serializer.get_string_value` now calls the model fields' renamed `value_to_string` methods.
* Removed a special-casing of `models.DateTimeField` in `core.serializers.base.Serializer.get_string_value` that's handled by `django.db.models.fields.DateTimeField.value_to_string`.
* Removed `django.core.validators`:
* Moved `ValidationError` exception to `django.core.exceptions`.
* For the couple places that were using validators, brought over the necessary code to maintain the same functionality.
* Introduced a SlugField form field for validation and to compliment the SlugField model field (refs #8040).
* Removed an oldforms-style model creation hack (refs #2160).
git-svn-id: http://code.djangoproject.com/svn/django/trunk@8616 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2008-08-27 15:19:44 +08:00
def __init__ ( self , to , related_name = None , limit_choices_to = None ,
symmetrical = True , through = None ) :
Merged the queryset-refactor branch into trunk.
This is a big internal change, but mostly backwards compatible with existing
code. Also adds a couple of new features.
Fixed #245, #1050, #1656, #1801, #2076, #2091, #2150, #2253, #2306, #2400, #2430, #2482, #2496, #2676, #2737, #2874, #2902, #2939, #3037, #3141, #3288, #3440, #3592, #3739, #4088, #4260, #4289, #4306, #4358, #4464, #4510, #4858, #5012, #5020, #5261, #5295, #5321, #5324, #5325, #5555, #5707, #5796, #5817, #5987, #6018, #6074, #6088, #6154, #6177, #6180, #6203, #6658
git-svn-id: http://code.djangoproject.com/svn/django/trunk@7477 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2008-04-27 10:50:16 +08:00
self . to = to
self . related_name = related_name
if limit_choices_to is None :
limit_choices_to = { }
self . limit_choices_to = limit_choices_to
self . symmetrical = symmetrical
self . multiple = True
2008-07-29 20:41:08 +08:00
self . through = through
Merged the queryset-refactor branch into trunk.
This is a big internal change, but mostly backwards compatible with existing
code. Also adds a couple of new features.
Fixed #245, #1050, #1656, #1801, #2076, #2091, #2150, #2253, #2306, #2400, #2430, #2482, #2496, #2676, #2737, #2874, #2902, #2939, #3037, #3141, #3288, #3440, #3592, #3739, #4088, #4260, #4289, #4306, #4358, #4464, #4510, #4858, #5012, #5020, #5261, #5295, #5321, #5324, #5325, #5555, #5707, #5796, #5817, #5987, #6018, #6074, #6088, #6154, #6177, #6180, #6203, #6658
git-svn-id: http://code.djangoproject.com/svn/django/trunk@7477 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2008-04-27 10:50:16 +08:00
2009-11-03 22:02:49 +08:00
def is_hidden ( self ) :
" Should the related object be hidden? "
return self . related_name and self . related_name [ - 1 ] == ' + '
2009-03-25 12:41:40 +08:00
def get_related_field ( self ) :
"""
Returns the field in the to ' object to which this relationship is tied
( this is always the primary key on the target model ) . Provided for
symmetry with ManyToOneRel .
"""
return self . to . _meta . pk
2006-05-02 09:31:56 +08:00
class ForeignKey ( RelatedField , Field ) :
empty_strings_allowed = False
2010-01-05 11:56:19 +08:00
default_error_messages = {
' invalid ' : _ ( ' Model %(model)s with pk %(pk)r does not exist. ' )
}
description = _ ( " Foreign Key (type determined by related field) " )
Merged the queryset-refactor branch into trunk.
This is a big internal change, but mostly backwards compatible with existing
code. Also adds a couple of new features.
Fixed #245, #1050, #1656, #1801, #2076, #2091, #2150, #2253, #2306, #2400, #2430, #2482, #2496, #2676, #2737, #2874, #2902, #2939, #3037, #3141, #3288, #3440, #3592, #3739, #4088, #4260, #4289, #4306, #4358, #4464, #4510, #4858, #5012, #5020, #5261, #5295, #5321, #5324, #5325, #5555, #5707, #5796, #5817, #5987, #6018, #6074, #6088, #6154, #6177, #6180, #6203, #6658
git-svn-id: http://code.djangoproject.com/svn/django/trunk@7477 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2008-04-27 10:50:16 +08:00
def __init__ ( self , to , to_field = None , rel_class = ManyToOneRel , * * kwargs ) :
2006-05-02 09:31:56 +08:00
try :
to_name = to . _meta . object_name . lower ( )
except AttributeError : # to._meta doesn't exist, so it must be RECURSIVE_RELATIONSHIP_CONSTANT
Merged the queryset-refactor branch into trunk.
This is a big internal change, but mostly backwards compatible with existing
code. Also adds a couple of new features.
Fixed #245, #1050, #1656, #1801, #2076, #2091, #2150, #2253, #2306, #2400, #2430, #2482, #2496, #2676, #2737, #2874, #2902, #2939, #3037, #3141, #3288, #3440, #3592, #3739, #4088, #4260, #4289, #4306, #4358, #4464, #4510, #4858, #5012, #5020, #5261, #5295, #5321, #5324, #5325, #5555, #5707, #5796, #5817, #5987, #6018, #6074, #6088, #6154, #6177, #6180, #6203, #6658
git-svn-id: http://code.djangoproject.com/svn/django/trunk@7477 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2008-04-27 10:50:16 +08:00
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 )
2006-05-02 09:31:56 +08:00
else :
2008-08-19 22:17:24 +08:00
assert not to . _meta . abstract , " %s cannot define a relation with abstract class %s " % ( self . __class__ . __name__ , to . _meta . object_name )
2009-11-10 23:21:12 +08:00
# For backwards compatibility purposes, we need to *try* and set
# the to_field during FK construction. It won't be guaranteed to
# be correct until contribute_to_class is called. Refs #12190.
to_field = to_field or ( to . _meta . pk and to . _meta . pk . name )
2008-07-30 02:31:27 +08:00
kwargs [ ' verbose_name ' ] = kwargs . get ( ' verbose_name ' , None )
2006-05-02 09:31:56 +08:00
2010-07-30 10:55:20 +08:00
if ' db_index ' not in kwargs :
kwargs [ ' db_index ' ] = True
Merged the queryset-refactor branch into trunk.
This is a big internal change, but mostly backwards compatible with existing
code. Also adds a couple of new features.
Fixed #245, #1050, #1656, #1801, #2076, #2091, #2150, #2253, #2306, #2400, #2430, #2482, #2496, #2676, #2737, #2874, #2902, #2939, #3037, #3141, #3288, #3440, #3592, #3739, #4088, #4260, #4289, #4306, #4358, #4464, #4510, #4858, #5012, #5020, #5261, #5295, #5321, #5324, #5325, #5555, #5707, #5796, #5817, #5987, #6018, #6074, #6088, #6154, #6177, #6180, #6203, #6658
git-svn-id: http://code.djangoproject.com/svn/django/trunk@7477 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2008-04-27 10:50:16 +08:00
kwargs [ ' rel ' ] = rel_class ( to , to_field ,
2006-05-02 09:31:56 +08:00
related_name = kwargs . pop ( ' related_name ' , None ) ,
limit_choices_to = kwargs . pop ( ' limit_choices_to ' , None ) ,
2010-11-10 00:46:42 +08:00
parent_link = kwargs . pop ( ' parent_link ' , False ) ,
on_delete = kwargs . pop ( ' on_delete ' , CASCADE ) ,
)
2006-05-02 09:31:56 +08:00
Field . __init__ ( self , * * kwargs )
2010-01-05 11:56:19 +08:00
def validate ( self , value , model_instance ) :
if self . rel . parent_link :
return
super ( ForeignKey , self ) . validate ( value , model_instance )
2010-04-27 23:05:38 +08:00
if value is None :
2010-01-05 11:56:19 +08:00
return
2010-01-21 11:26:14 +08:00
2010-11-17 06:09:13 +08:00
using = router . db_for_read ( model_instance . __class__ , instance = model_instance )
qs = self . rel . to . _default_manager . using ( using ) . filter (
* * { self . rel . field_name : value }
)
2010-01-21 11:26:14 +08:00
qs = qs . complex_filter ( self . rel . limit_choices_to )
if not qs . exists ( ) :
raise exceptions . ValidationError ( self . error_messages [ ' invalid ' ] % {
' model ' : self . rel . to . _meta . verbose_name , ' pk ' : value } )
2010-01-05 11:56:19 +08:00
2006-05-02 09:31:56 +08:00
def get_attname ( self ) :
return ' %s _id ' % self . name
def get_validator_unique_lookup_type ( self ) :
return ' %s __ %s __exact ' % ( self . name , self . rel . get_related_field ( ) . name )
2008-03-20 14:56:23 +08:00
def get_default ( self ) :
" Here we check if the default value is an object and return the to_field if so. "
field_default = super ( ForeignKey , self ) . get_default ( )
if isinstance ( field_default , self . rel . to ) :
return getattr ( field_default , self . rel . get_related_field ( ) . attname )
return field_default
2009-12-22 23:18:51 +08:00
def get_db_prep_save ( self , value , connection ) :
2006-05-02 09:31:56 +08:00
if value == ' ' or value == None :
return None
else :
2009-12-22 23:18:51 +08:00
return self . rel . get_related_field ( ) . get_db_prep_save ( value ,
connection = connection )
2006-05-02 09:31:56 +08:00
Removed oldforms, validators, and related code:
* Removed `Manipulator`, `AutomaticManipulator`, and related classes.
* Removed oldforms specific bits from model fields:
* Removed `validator_list` and `core` arguments from constructors.
* Removed the methods:
* `get_manipulator_field_names`
* `get_manipulator_field_objs`
* `get_manipulator_fields`
* `get_manipulator_new_data`
* `prepare_field_objs_and_params`
* `get_follow`
* Renamed `flatten_data` method to `value_to_string` for better alignment with its use by the serialization framework, which was the only remaining code using `flatten_data`.
* Removed oldforms methods from `django.db.models.Options` class: `get_followed_related_objects`, `get_data_holders`, `get_follow`, and `has_field_type`.
* Removed oldforms-admin specific options from `django.db.models.fields.related` classes: `num_in_admin`, `min_num_in_admin`, `max_num_in_admin`, `num_extra_on_change`, and `edit_inline`.
* Serialization framework
* `Serializer.get_string_value` now calls the model fields' renamed `value_to_string` methods.
* Removed a special-casing of `models.DateTimeField` in `core.serializers.base.Serializer.get_string_value` that's handled by `django.db.models.fields.DateTimeField.value_to_string`.
* Removed `django.core.validators`:
* Moved `ValidationError` exception to `django.core.exceptions`.
* For the couple places that were using validators, brought over the necessary code to maintain the same functionality.
* Introduced a SlugField form field for validation and to compliment the SlugField model field (refs #8040).
* Removed an oldforms-style model creation hack (refs #2160).
git-svn-id: http://code.djangoproject.com/svn/django/trunk@8616 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2008-08-27 15:19:44 +08:00
def value_to_string ( self , obj ) :
2006-05-02 09:31:56 +08:00
if not obj :
# In required many-to-one fields with only one available choice,
# select that one available choice. Note: For SelectFields
2008-07-19 07:54:34 +08:00
# we have to check that the length of choices is *2*, not 1,
# because SelectFields always have an initial "blank" value.
if not self . blank and self . choices :
2006-05-02 09:31:56 +08:00
choice_list = self . get_choices_default ( )
2008-07-19 07:54:34 +08:00
if len ( choice_list ) == 2 :
Removed oldforms, validators, and related code:
* Removed `Manipulator`, `AutomaticManipulator`, and related classes.
* Removed oldforms specific bits from model fields:
* Removed `validator_list` and `core` arguments from constructors.
* Removed the methods:
* `get_manipulator_field_names`
* `get_manipulator_field_objs`
* `get_manipulator_fields`
* `get_manipulator_new_data`
* `prepare_field_objs_and_params`
* `get_follow`
* Renamed `flatten_data` method to `value_to_string` for better alignment with its use by the serialization framework, which was the only remaining code using `flatten_data`.
* Removed oldforms methods from `django.db.models.Options` class: `get_followed_related_objects`, `get_data_holders`, `get_follow`, and `has_field_type`.
* Removed oldforms-admin specific options from `django.db.models.fields.related` classes: `num_in_admin`, `min_num_in_admin`, `max_num_in_admin`, `num_extra_on_change`, and `edit_inline`.
* Serialization framework
* `Serializer.get_string_value` now calls the model fields' renamed `value_to_string` methods.
* Removed a special-casing of `models.DateTimeField` in `core.serializers.base.Serializer.get_string_value` that's handled by `django.db.models.fields.DateTimeField.value_to_string`.
* Removed `django.core.validators`:
* Moved `ValidationError` exception to `django.core.exceptions`.
* For the couple places that were using validators, brought over the necessary code to maintain the same functionality.
* Introduced a SlugField form field for validation and to compliment the SlugField model field (refs #8040).
* Removed an oldforms-style model creation hack (refs #2160).
git-svn-id: http://code.djangoproject.com/svn/django/trunk@8616 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2008-08-27 15:19:44 +08:00
return smart_unicode ( choice_list [ 1 ] [ 0 ] )
return Field . value_to_string ( self , obj )
2006-05-02 09:31:56 +08:00
def contribute_to_class ( self , cls , name ) :
super ( ForeignKey , self ) . contribute_to_class ( cls , name )
setattr ( cls , self . name , ReverseSingleRelatedObjectDescriptor ( self ) )
2008-06-29 10:36:18 +08:00
if isinstance ( self . rel . to , basestring ) :
target = self . rel . to
else :
target = self . rel . to . _meta . db_table
cls . _meta . duplicate_targets [ self . column ] = ( target , " o2m " )
2006-05-02 09:31:56 +08:00
def contribute_to_related_class ( self , cls , related ) :
2009-11-03 22:02:49 +08:00
# Internal FK's - i.e., those with a related name ending with '+' -
# don't get a related descriptor.
if not self . rel . is_hidden ( ) :
setattr ( cls , related . get_accessor_name ( ) , ForeignRelatedObjectsDescriptor ( related ) )
2011-01-28 22:08:25 +08:00
if self . rel . limit_choices_to :
cls . _meta . related_fkey_lookups . append ( self . rel . limit_choices_to )
2009-11-03 22:02:49 +08:00
if self . rel . field_name is None :
self . rel . field_name = cls . _meta . pk . name
2008-09-01 08:49:03 +08:00
2007-01-22 14:32:14 +08:00
def formfield ( self , * * kwargs ) :
2009-12-22 23:18:51 +08:00
db = kwargs . pop ( ' using ' , None )
2011-08-12 22:15:08 +08:00
if isinstance ( self . rel . to , basestring ) :
raise ValueError ( " Cannot create form field for %r yet, because "
" its related model %r has not been loaded yet " %
( self . name , self . rel . to ) )
2008-09-02 06:43:38 +08:00
defaults = {
' form_class ' : forms . ModelChoiceField ,
2011-03-10 09:15:19 +08:00
' queryset ' : self . rel . to . _default_manager . using ( db ) . complex_filter ( self . rel . limit_choices_to ) ,
2008-09-02 06:43:38 +08:00
' to_field_name ' : self . rel . field_name ,
}
2007-01-22 14:32:14 +08:00
defaults . update ( kwargs )
2007-04-28 21:55:24 +08:00
return super ( ForeignKey , self ) . formfield ( * * defaults )
2006-12-27 13:23:21 +08:00
2009-12-22 23:18:51 +08:00
def db_type ( self , connection ) :
2007-07-20 14:28:56 +08:00
# The database column type of a ForeignKey is the column type
# of the field to which it points. An exception is if the ForeignKey
# points to an AutoField/PositiveIntegerField/PositiveSmallIntegerField,
# in which case the column type is simply that of an IntegerField.
2008-09-01 08:49:03 +08:00
# If the database needs similar types for key fields however, the only
# thing we can do is making AutoField an IntegerField.
2007-07-20 14:28:56 +08:00
rel_field = self . rel . get_related_field ( )
2008-09-01 08:49:03 +08:00
if ( isinstance ( rel_field , AutoField ) or
( not connection . features . related_fields_match_type and
isinstance ( rel_field , ( PositiveIntegerField ,
PositiveSmallIntegerField ) ) ) ) :
2009-12-22 23:18:51 +08:00
return IntegerField ( ) . db_type ( connection = connection )
return rel_field . db_type ( connection = connection )
2007-07-20 14:28:56 +08:00
Merged the queryset-refactor branch into trunk.
This is a big internal change, but mostly backwards compatible with existing
code. Also adds a couple of new features.
Fixed #245, #1050, #1656, #1801, #2076, #2091, #2150, #2253, #2306, #2400, #2430, #2482, #2496, #2676, #2737, #2874, #2902, #2939, #3037, #3141, #3288, #3440, #3592, #3739, #4088, #4260, #4289, #4306, #4358, #4464, #4510, #4858, #5012, #5020, #5261, #5295, #5321, #5324, #5325, #5555, #5707, #5796, #5817, #5987, #6018, #6074, #6088, #6154, #6177, #6180, #6203, #6658
git-svn-id: http://code.djangoproject.com/svn/django/trunk@7477 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2008-04-27 10:50:16 +08:00
class OneToOneField ( ForeignKey ) :
2009-12-17 02:13:34 +08:00
"""
Merged the queryset-refactor branch into trunk.
This is a big internal change, but mostly backwards compatible with existing
code. Also adds a couple of new features.
Fixed #245, #1050, #1656, #1801, #2076, #2091, #2150, #2253, #2306, #2400, #2430, #2482, #2496, #2676, #2737, #2874, #2902, #2939, #3037, #3141, #3288, #3440, #3592, #3739, #4088, #4260, #4289, #4306, #4358, #4464, #4510, #4858, #5012, #5020, #5261, #5295, #5321, #5324, #5325, #5555, #5707, #5796, #5817, #5987, #6018, #6074, #6088, #6154, #6177, #6180, #6203, #6658
git-svn-id: http://code.djangoproject.com/svn/django/trunk@7477 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2008-04-27 10:50:16 +08:00
A OneToOneField is essentially the same as a ForeignKey , with the exception
that always carries a " unique " constraint with it and the reverse relation
always returns the object pointed to ( since there will only ever be one ) ,
2009-12-17 02:13:34 +08:00
rather than returning a list .
"""
2010-01-05 11:56:19 +08:00
description = _ ( " One-to-one relationship " )
2006-05-02 09:31:56 +08:00
def __init__ ( self , to , to_field = None , * * kwargs ) :
Merged the queryset-refactor branch into trunk.
This is a big internal change, but mostly backwards compatible with existing
code. Also adds a couple of new features.
Fixed #245, #1050, #1656, #1801, #2076, #2091, #2150, #2253, #2306, #2400, #2430, #2482, #2496, #2676, #2737, #2874, #2902, #2939, #3037, #3141, #3288, #3440, #3592, #3739, #4088, #4260, #4289, #4306, #4358, #4464, #4510, #4858, #5012, #5020, #5261, #5295, #5321, #5324, #5325, #5555, #5707, #5796, #5817, #5987, #6018, #6074, #6088, #6154, #6177, #6180, #6203, #6658
git-svn-id: http://code.djangoproject.com/svn/django/trunk@7477 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2008-04-27 10:50:16 +08:00
kwargs [ ' unique ' ] = True
super ( OneToOneField , self ) . __init__ ( to , to_field , OneToOneRel , * * kwargs )
2006-05-02 09:31:56 +08:00
def contribute_to_related_class ( self , cls , related ) :
Merged the queryset-refactor branch into trunk.
This is a big internal change, but mostly backwards compatible with existing
code. Also adds a couple of new features.
Fixed #245, #1050, #1656, #1801, #2076, #2091, #2150, #2253, #2306, #2400, #2430, #2482, #2496, #2676, #2737, #2874, #2902, #2939, #3037, #3141, #3288, #3440, #3592, #3739, #4088, #4260, #4289, #4306, #4358, #4464, #4510, #4858, #5012, #5020, #5261, #5295, #5321, #5324, #5325, #5555, #5707, #5796, #5817, #5987, #6018, #6074, #6088, #6154, #6177, #6180, #6203, #6658
git-svn-id: http://code.djangoproject.com/svn/django/trunk@7477 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2008-04-27 10:50:16 +08:00
setattr ( cls , related . get_accessor_name ( ) ,
SingleRelatedObjectDescriptor ( related ) )
2008-08-30 05:24:00 +08:00
2008-08-23 03:27:26 +08:00
def formfield ( self , * * kwargs ) :
if self . rel . parent_link :
return None
return super ( OneToOneField , self ) . formfield ( * * kwargs )
2006-05-02 09:31:56 +08:00
2010-01-05 11:56:19 +08:00
def save_form_data ( self , instance , data ) :
if isinstance ( data , self . rel . to ) :
setattr ( instance , self . name , data )
else :
setattr ( instance , self . attname , data )
2009-11-03 22:02:49 +08:00
def create_many_to_many_intermediary_model ( field , klass ) :
from django . db import models
managed = True
if isinstance ( field . rel . to , basestring ) and field . rel . to != RECURSIVE_RELATIONSHIP_CONSTANT :
to_model = field . rel . to
2010-01-14 22:55:36 +08:00
to = to_model . split ( ' . ' ) [ - 1 ]
2009-11-03 22:02:49 +08:00
def set_managed ( field , model , cls ) :
field . rel . through . _meta . managed = model . _meta . managed or cls . _meta . managed
add_lazy_relation ( klass , field , to_model , set_managed )
elif isinstance ( field . rel . to , basestring ) :
to = klass . _meta . object_name
to_model = klass
managed = klass . _meta . managed
else :
to = field . rel . to . _meta . object_name
to_model = field . rel . to
managed = klass . _meta . managed or to_model . _meta . managed
name = ' %s _ %s ' % ( klass . _meta . object_name , field . name )
2010-02-22 22:04:13 +08:00
if field . rel . to == RECURSIVE_RELATIONSHIP_CONSTANT or to == klass . _meta . object_name :
2009-11-03 22:02:49 +08:00
from_ = ' from_ %s ' % to . lower ( )
2009-11-04 07:34:58 +08:00
to = ' to_ %s ' % to . lower ( )
2009-11-03 22:02:49 +08:00
else :
from_ = klass . _meta . object_name . lower ( )
to = to . lower ( )
meta = type ( ' Meta ' , ( object , ) , {
' db_table ' : field . _get_m2m_db_table ( klass . _meta ) ,
' managed ' : managed ,
' auto_created ' : klass ,
2009-11-20 08:59:38 +08:00
' app_label ' : klass . _meta . app_label ,
2011-10-15 05:49:43 +08:00
' db_tablespace ' : klass . _meta . db_tablespace ,
2010-04-27 20:35:49 +08:00
' unique_together ' : ( from_ , to ) ,
2010-04-27 22:42:55 +08:00
' verbose_name ' : ' %(from)s - %(to)s relationship ' % { ' from ' : from_ , ' to ' : to } ,
' verbose_name_plural ' : ' %(from)s - %(to)s relationships ' % { ' from ' : from_ , ' to ' : to } ,
2009-11-03 22:02:49 +08:00
} )
2009-11-05 19:57:28 +08:00
# Construct and return the new class.
2009-11-03 22:02:49 +08:00
return type ( name , ( models . Model , ) , {
' Meta ' : meta ,
2009-11-20 08:59:38 +08:00
' __module__ ' : klass . __module__ ,
2011-10-15 05:49:43 +08:00
from_ : models . ForeignKey ( klass , related_name = ' %s + ' % name , db_tablespace = field . db_tablespace ) ,
to : models . ForeignKey ( to_model , related_name = ' %s + ' % name , db_tablespace = field . db_tablespace )
2009-11-03 22:02:49 +08:00
} )
2006-05-02 09:31:56 +08:00
class ManyToManyField ( RelatedField , Field ) :
2010-01-05 11:56:19 +08:00
description = _ ( " Many-to-many relationship " )
2006-05-02 09:31:56 +08:00
def __init__ ( self , to , * * kwargs ) :
2008-08-19 22:17:24 +08:00
try :
assert not to . _meta . abstract , " %s cannot define a relation with abstract class %s " % ( self . __class__ . __name__ , to . _meta . object_name )
except AttributeError : # to._meta doesn't exist, so it must be RECURSIVE_RELATIONSHIP_CONSTANT
assert isinstance ( to , basestring ) , " %s ( %r ) is invalid. First parameter to ManyToManyField must be either a model, a model name, or the string %r " % ( self . __class__ . __name__ , to , RECURSIVE_RELATIONSHIP_CONSTANT )
2011-08-25 14:07:28 +08:00
# Python 2.6 and earlier require dictionary keys to be of str type,
# not unicode and class names must be ASCII (in Python 2.x), so we
# forcibly coerce it here (breaks early if there's a problem).
to = str ( to )
2008-08-19 22:17:24 +08:00
2006-05-02 09:31:56 +08:00
kwargs [ ' verbose_name ' ] = kwargs . get ( ' verbose_name ' , None )
2006-05-04 12:59:22 +08:00
kwargs [ ' rel ' ] = ManyToManyRel ( to ,
2006-05-02 09:31:56 +08:00
related_name = kwargs . pop ( ' related_name ' , None ) ,
limit_choices_to = kwargs . pop ( ' limit_choices_to ' , None ) ,
2010-04-02 23:44:48 +08:00
symmetrical = kwargs . pop ( ' symmetrical ' , to == RECURSIVE_RELATIONSHIP_CONSTANT ) ,
2008-07-29 20:41:08 +08:00
through = kwargs . pop ( ' through ' , None ) )
2008-08-26 12:55:56 +08:00
2007-01-25 21:47:55 +08:00
self . db_table = kwargs . pop ( ' db_table ' , None )
2008-07-29 20:41:08 +08:00
if kwargs [ ' rel ' ] . through is not None :
assert self . db_table is None , " Cannot specify a db_table if an intermediary model is used. "
2006-05-02 09:31:56 +08:00
Field . __init__ ( self , * * kwargs )
2010-01-05 11:56:19 +08:00
msg = _ ( ' Hold down " Control " , or " Command " on a Mac, to select more than one. ' )
2006-09-26 11:46:33 +08:00
self . help_text = string_concat ( self . help_text , ' ' , msg )
2006-05-02 09:31:56 +08:00
def get_choices_default ( self ) :
return Field . get_choices ( self , include_blank = False )
def _get_m2m_db_table ( self , opts ) :
" Function that can be curried to provide the m2m table name for this relation "
2008-07-29 20:41:08 +08:00
if self . rel . through is not None :
2009-11-03 22:02:49 +08:00
return self . rel . through . _meta . db_table
2008-07-29 20:41:08 +08:00
elif self . db_table :
2007-01-25 21:47:55 +08:00
return self . db_table
else :
2008-12-03 00:58:06 +08:00
return util . truncate_name ( ' %s _ %s ' % ( opts . db_table , self . name ) ,
connection . ops . max_name_length ( ) )
2006-05-02 09:31:56 +08:00
2009-11-03 22:02:49 +08:00
def _get_m2m_attr ( self , related , attr ) :
2010-02-22 22:04:13 +08:00
" Function that can be curried to provide the source accessor or DB column name for the m2m table "
2009-11-03 22:02:49 +08:00
cache_attr = ' _m2m_ %s _cache ' % attr
if hasattr ( self , cache_attr ) :
return getattr ( self , cache_attr )
for f in self . rel . through . _meta . fields :
if hasattr ( f , ' rel ' ) and f . rel and f . rel . to == related . model :
setattr ( self , cache_attr , getattr ( f , attr ) )
return getattr ( self , cache_attr )
def _get_m2m_reverse_attr ( self , related , attr ) :
2010-02-22 22:04:13 +08:00
" Function that can be curried to provide the related accessor or DB column name for the m2m table "
2009-11-03 22:02:49 +08:00
cache_attr = ' _m2m_reverse_ %s _cache ' % attr
if hasattr ( self , cache_attr ) :
return getattr ( self , cache_attr )
found = False
for f in self . rel . through . _meta . fields :
if hasattr ( f , ' rel ' ) and f . rel and f . rel . to == related . parent_model :
if related . model == related . parent_model :
# If this is an m2m-intermediate to self,
# the first foreign key you find will be
# the source column. Keep searching for
# the second foreign key.
if found :
setattr ( self , cache_attr , getattr ( f , attr ) )
break
else :
found = True
else :
setattr ( self , cache_attr , getattr ( f , attr ) )
break
return getattr ( self , cache_attr )
2006-05-02 09:31:56 +08:00
Removed oldforms, validators, and related code:
* Removed `Manipulator`, `AutomaticManipulator`, and related classes.
* Removed oldforms specific bits from model fields:
* Removed `validator_list` and `core` arguments from constructors.
* Removed the methods:
* `get_manipulator_field_names`
* `get_manipulator_field_objs`
* `get_manipulator_fields`
* `get_manipulator_new_data`
* `prepare_field_objs_and_params`
* `get_follow`
* Renamed `flatten_data` method to `value_to_string` for better alignment with its use by the serialization framework, which was the only remaining code using `flatten_data`.
* Removed oldforms methods from `django.db.models.Options` class: `get_followed_related_objects`, `get_data_holders`, `get_follow`, and `has_field_type`.
* Removed oldforms-admin specific options from `django.db.models.fields.related` classes: `num_in_admin`, `min_num_in_admin`, `max_num_in_admin`, `num_extra_on_change`, and `edit_inline`.
* Serialization framework
* `Serializer.get_string_value` now calls the model fields' renamed `value_to_string` methods.
* Removed a special-casing of `models.DateTimeField` in `core.serializers.base.Serializer.get_string_value` that's handled by `django.db.models.fields.DateTimeField.value_to_string`.
* Removed `django.core.validators`:
* Moved `ValidationError` exception to `django.core.exceptions`.
* For the couple places that were using validators, brought over the necessary code to maintain the same functionality.
* Introduced a SlugField form field for validation and to compliment the SlugField model field (refs #8040).
* Removed an oldforms-style model creation hack (refs #2160).
git-svn-id: http://code.djangoproject.com/svn/django/trunk@8616 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2008-08-27 15:19:44 +08:00
def value_to_string ( self , obj ) :
data = ' '
2006-05-02 09:31:56 +08:00
if obj :
Removed oldforms, validators, and related code:
* Removed `Manipulator`, `AutomaticManipulator`, and related classes.
* Removed oldforms specific bits from model fields:
* Removed `validator_list` and `core` arguments from constructors.
* Removed the methods:
* `get_manipulator_field_names`
* `get_manipulator_field_objs`
* `get_manipulator_fields`
* `get_manipulator_new_data`
* `prepare_field_objs_and_params`
* `get_follow`
* Renamed `flatten_data` method to `value_to_string` for better alignment with its use by the serialization framework, which was the only remaining code using `flatten_data`.
* Removed oldforms methods from `django.db.models.Options` class: `get_followed_related_objects`, `get_data_holders`, `get_follow`, and `has_field_type`.
* Removed oldforms-admin specific options from `django.db.models.fields.related` classes: `num_in_admin`, `min_num_in_admin`, `max_num_in_admin`, `num_extra_on_change`, and `edit_inline`.
* Serialization framework
* `Serializer.get_string_value` now calls the model fields' renamed `value_to_string` methods.
* Removed a special-casing of `models.DateTimeField` in `core.serializers.base.Serializer.get_string_value` that's handled by `django.db.models.fields.DateTimeField.value_to_string`.
* Removed `django.core.validators`:
* Moved `ValidationError` exception to `django.core.exceptions`.
* For the couple places that were using validators, brought over the necessary code to maintain the same functionality.
* Introduced a SlugField form field for validation and to compliment the SlugField model field (refs #8040).
* Removed an oldforms-style model creation hack (refs #2160).
git-svn-id: http://code.djangoproject.com/svn/django/trunk@8616 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2008-08-27 15:19:44 +08:00
qs = getattr ( obj , self . name ) . all ( )
data = [ instance . _get_pk_val ( ) for instance in qs ]
2006-05-02 09:31:56 +08:00
else :
# In required many-to-many fields with only one available choice,
# select that one available choice.
Removed oldforms, validators, and related code:
* Removed `Manipulator`, `AutomaticManipulator`, and related classes.
* Removed oldforms specific bits from model fields:
* Removed `validator_list` and `core` arguments from constructors.
* Removed the methods:
* `get_manipulator_field_names`
* `get_manipulator_field_objs`
* `get_manipulator_fields`
* `get_manipulator_new_data`
* `prepare_field_objs_and_params`
* `get_follow`
* Renamed `flatten_data` method to `value_to_string` for better alignment with its use by the serialization framework, which was the only remaining code using `flatten_data`.
* Removed oldforms methods from `django.db.models.Options` class: `get_followed_related_objects`, `get_data_holders`, `get_follow`, and `has_field_type`.
* Removed oldforms-admin specific options from `django.db.models.fields.related` classes: `num_in_admin`, `min_num_in_admin`, `max_num_in_admin`, `num_extra_on_change`, and `edit_inline`.
* Serialization framework
* `Serializer.get_string_value` now calls the model fields' renamed `value_to_string` methods.
* Removed a special-casing of `models.DateTimeField` in `core.serializers.base.Serializer.get_string_value` that's handled by `django.db.models.fields.DateTimeField.value_to_string`.
* Removed `django.core.validators`:
* Moved `ValidationError` exception to `django.core.exceptions`.
* For the couple places that were using validators, brought over the necessary code to maintain the same functionality.
* Introduced a SlugField form field for validation and to compliment the SlugField model field (refs #8040).
* Removed an oldforms-style model creation hack (refs #2160).
git-svn-id: http://code.djangoproject.com/svn/django/trunk@8616 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2008-08-27 15:19:44 +08:00
if not self . blank :
2006-05-02 09:31:56 +08:00
choices_list = self . get_choices_default ( )
if len ( choices_list ) == 1 :
Removed oldforms, validators, and related code:
* Removed `Manipulator`, `AutomaticManipulator`, and related classes.
* Removed oldforms specific bits from model fields:
* Removed `validator_list` and `core` arguments from constructors.
* Removed the methods:
* `get_manipulator_field_names`
* `get_manipulator_field_objs`
* `get_manipulator_fields`
* `get_manipulator_new_data`
* `prepare_field_objs_and_params`
* `get_follow`
* Renamed `flatten_data` method to `value_to_string` for better alignment with its use by the serialization framework, which was the only remaining code using `flatten_data`.
* Removed oldforms methods from `django.db.models.Options` class: `get_followed_related_objects`, `get_data_holders`, `get_follow`, and `has_field_type`.
* Removed oldforms-admin specific options from `django.db.models.fields.related` classes: `num_in_admin`, `min_num_in_admin`, `max_num_in_admin`, `num_extra_on_change`, and `edit_inline`.
* Serialization framework
* `Serializer.get_string_value` now calls the model fields' renamed `value_to_string` methods.
* Removed a special-casing of `models.DateTimeField` in `core.serializers.base.Serializer.get_string_value` that's handled by `django.db.models.fields.DateTimeField.value_to_string`.
* Removed `django.core.validators`:
* Moved `ValidationError` exception to `django.core.exceptions`.
* For the couple places that were using validators, brought over the necessary code to maintain the same functionality.
* Introduced a SlugField form field for validation and to compliment the SlugField model field (refs #8040).
* Removed an oldforms-style model creation hack (refs #2160).
git-svn-id: http://code.djangoproject.com/svn/django/trunk@8616 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2008-08-27 15:19:44 +08:00
data = [ choices_list [ 0 ] [ 0 ] ]
return smart_unicode ( data )
2006-05-02 09:31:56 +08:00
def contribute_to_class ( self , cls , name ) :
2008-08-30 05:24:00 +08:00
# To support multiple relations to self, it's useful to have a non-None
# related name on symmetrical relations for internal reasons. The
# concept doesn't make a lot of sense externally ("you want me to
# specify *what* on my non-reversible relation?!"), so we set it up
# automatically. The funky name reduces the chance of an accidental
# clash.
2009-11-03 22:02:49 +08:00
if self . rel . symmetrical and ( self . rel . to == " self " or self . rel . to == cls . _meta . object_name ) :
2008-08-30 05:24:00 +08:00
self . rel . related_name = " %s _rel_+ " % name
2008-08-26 12:55:56 +08:00
super ( ManyToManyField , self ) . contribute_to_class ( cls , name )
2009-11-03 22:02:49 +08:00
# The intermediate m2m model is not auto created if:
# 1) There is a manually specified intermediate, or
# 2) The class owning the m2m field is abstract.
if not self . rel . through and not cls . _meta . abstract :
self . rel . through = create_many_to_many_intermediary_model ( self , cls )
2006-05-02 09:31:56 +08:00
# Add the descriptor for the m2m relation
setattr ( cls , self . name , ReverseManyRelatedObjectsDescriptor ( self ) )
# Set up the accessor for the m2m table name for the relation
self . m2m_db_table = curry ( self . _get_m2m_db_table , cls . _meta )
2008-08-26 12:55:56 +08:00
2008-07-29 20:41:08 +08:00
# Populate some necessary rel arguments so that cross-app relations
# work correctly.
if isinstance ( self . rel . through , basestring ) :
def resolve_through_model ( field , model , cls ) :
2009-11-03 22:02:49 +08:00
field . rel . through = model
2008-07-29 20:41:08 +08:00
add_lazy_relation ( cls , self , self . rel . through , resolve_through_model )
2008-08-26 12:55:56 +08:00
2008-06-29 10:36:18 +08:00
if isinstance ( self . rel . to , basestring ) :
target = self . rel . to
else :
target = self . rel . to . _meta . db_table
cls . _meta . duplicate_targets [ self . column ] = ( target , " m2m " )
2006-05-02 09:31:56 +08:00
def contribute_to_related_class ( self , cls , related ) :
2009-11-03 22:02:49 +08:00
# Internal M2Ms (i.e., those with a related name ending with '+')
# don't get a related descriptor.
if not self . rel . is_hidden ( ) :
2006-05-02 09:31:56 +08:00
setattr ( cls , related . get_accessor_name ( ) , ManyRelatedObjectsDescriptor ( related ) )
# Set up the accessors for the column names on the m2m table
2009-11-03 22:02:49 +08:00
self . m2m_column_name = curry ( self . _get_m2m_attr , related , ' column ' )
self . m2m_reverse_name = curry ( self . _get_m2m_reverse_attr , related , ' column ' )
self . m2m_field_name = curry ( self . _get_m2m_attr , related , ' name ' )
self . m2m_reverse_field_name = curry ( self . _get_m2m_reverse_attr , related , ' name ' )
2006-05-02 09:31:56 +08:00
2011-01-27 03:10:08 +08:00
get_m2m_rel = curry ( self . _get_m2m_attr , related , ' rel ' )
self . m2m_target_field_name = lambda : get_m2m_rel ( ) . field_name
get_m2m_reverse_rel = curry ( self . _get_m2m_reverse_attr , related , ' rel ' )
self . m2m_reverse_target_field_name = lambda : get_m2m_reverse_rel ( ) . field_name
2006-05-02 09:31:56 +08:00
def set_attributes_from_rel ( self ) :
pass
2006-12-28 10:27:14 +08:00
def value_from_object ( self , obj ) :
" Returns the value of this field in the given model instance. "
return getattr ( obj , self . attname ) . all ( )
2007-08-06 21:58:56 +08:00
def save_form_data ( self , instance , data ) :
setattr ( instance , self . attname , data )
Merged the queryset-refactor branch into trunk.
This is a big internal change, but mostly backwards compatible with existing
code. Also adds a couple of new features.
Fixed #245, #1050, #1656, #1801, #2076, #2091, #2150, #2253, #2306, #2400, #2430, #2482, #2496, #2676, #2737, #2874, #2902, #2939, #3037, #3141, #3288, #3440, #3592, #3739, #4088, #4260, #4289, #4306, #4358, #4464, #4510, #4858, #5012, #5020, #5261, #5295, #5321, #5324, #5325, #5555, #5707, #5796, #5817, #5987, #6018, #6074, #6088, #6154, #6177, #6180, #6203, #6658
git-svn-id: http://code.djangoproject.com/svn/django/trunk@7477 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2008-04-27 10:50:16 +08:00
2007-01-22 14:32:14 +08:00
def formfield ( self , * * kwargs ) :
2009-12-22 23:18:51 +08:00
db = kwargs . pop ( ' using ' , None )
defaults = {
' form_class ' : forms . ModelMultipleChoiceField ,
' queryset ' : self . rel . to . _default_manager . using ( db ) . complex_filter ( self . rel . limit_choices_to )
}
2007-04-28 21:55:24 +08:00
defaults . update ( kwargs )
2006-12-30 08:12:02 +08:00
# If initial is passed in, it's a list of related objects, but the
# MultipleChoiceField takes a list of IDs.
2007-04-28 21:55:24 +08:00
if defaults . get ( ' initial ' ) is not None :
2009-05-02 15:03:33 +08:00
initial = defaults [ ' initial ' ]
if callable ( initial ) :
initial = initial ( )
defaults [ ' initial ' ] = [ i . _get_pk_val ( ) for i in initial ]
2007-04-28 21:55:24 +08:00
return super ( ManyToManyField , self ) . formfield ( * * defaults )
2006-12-27 13:15:22 +08:00
2009-12-22 23:18:51 +08:00
def db_type ( self , connection ) :
2007-07-20 14:28:56 +08:00
# A ManyToManyField is not represented by a single column,
# so return None.
return None