Changeset 8291
- Timestamp:
- 08/10/08 16:10:47 (11 months ago)
- Files:
-
- django/trunk/django/core/files/storage.py (modified) (1 diff)
- django/trunk/django/core/files/uploadedfile.py (modified) (6 diffs)
- django/trunk/django/db/models/base.py (modified) (2 diffs)
- django/trunk/django/db/models/fields/files.py (modified) (4 diffs)
- django/trunk/django/dispatch/dispatcher.py (modified) (2 diffs)
- django/trunk/django/forms/fields.py (modified) (3 diffs)
- django/trunk/django/forms/models.py (modified) (12 diffs)
- django/trunk/django/newforms (deleted)
- django/trunk/django/utils/images.py (deleted)
- django/trunk/django/views/generic/create_update.py (modified) (5 diffs)
- django/trunk/docs/custom_model_fields.txt (modified) (1 diff)
- django/trunk/docs/db-api.txt (modified) (4 diffs)
- django/trunk/docs/form_for_model.txt (deleted)
- django/trunk/docs/forms.txt (modified) (1 diff)
- django/trunk/docs/model-api.txt (modified) (15 diffs)
- django/trunk/tests/modeltests/model_forms/models.py (modified) (1 diff)
- django/trunk/tests/regressiontests/forms/models.py (modified) (4 diffs)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
django/trunk/django/core/files/storage.py
r8262 r8291 37 37 proper File object, ready to be read from the beginning. 38 38 """ 39 # Check for old-style usage. Warn here first since there are multiple40 # locations where we need to support both new and old usage.41 if isinstance(content, basestring):42 import warnings43 warnings.warn(44 message = "Representing files as strings is deprecated." \45 "Use django.core.files.base.ContentFile instead.",46 category = DeprecationWarning,47 stacklevel = 248 )49 from django.core.files.base import ContentFile50 content = ContentFile(content)51 52 39 # Get the proper name for the file, as it will actually be saved. 53 40 if name is None: django/trunk/django/core/files/uploadedfile.py
r8244 r8291 4 4 5 5 import os 6 import warnings7 6 try: 8 7 from cStringIO import StringIO … … 12 11 from django.conf import settings 13 12 from django.core.files.base import File 14 15 13 from django.core.files import temp as tempfile 16 14 17 __all__ = ('UploadedFile', 'TemporaryUploadedFile', 'InMemoryUploadedFile', 'SimpleUploadedFile') 18 19 # Because we fooled around with it a bunch, UploadedFile has a bunch 20 # of deprecated properties. This little shortcut helps define 'em 21 # without too much code duplication. 22 def deprecated_property(old, new, readonly=False): 23 def issue_warning(): 24 warnings.warn( 25 message = "UploadedFile.%s is deprecated; use UploadedFile.%s instead." % (old, new), 26 category = DeprecationWarning, 27 stacklevel = 3 28 ) 29 30 def getter(self): 31 issue_warning() 32 return getattr(self, new) 33 34 def setter(self, value): 35 issue_warning() 36 setattr(self, new, value) 37 38 if readonly: 39 return property(getter) 40 else: 41 return property(getter, setter) 15 __all__ = ('UploadedFile', 'TemporaryUploadedFile', 'InMemoryUploadedFile', 16 'SimpleUploadedFile') 42 17 43 18 class UploadedFile(File): … … 78 53 name = property(_get_name, _set_name) 79 54 80 # Deprecated properties81 filename = deprecated_property(old="filename", new="name")82 file_name = deprecated_property(old="file_name", new="name")83 file_size = deprecated_property(old="file_size", new="size")84 chunk = deprecated_property(old="chunk", new="chunks", readonly=True)85 86 def _get_data(self):87 warnings.warn(88 message = "UploadedFile.data is deprecated; use UploadedFile.read() instead.",89 category = DeprecationWarning,90 stacklevel = 291 )92 return self.read()93 data = property(_get_data)94 95 55 # Abstract methods; subclasses *must* define read() and probably should 96 56 # define open/close. … … 103 63 def close(self): 104 64 pass 105 106 # Backwards-compatible support for uploaded-files-as-dictionaries.107 def __getitem__(self, key):108 warnings.warn(109 message = "The dictionary access of uploaded file objects is deprecated. Use the new object interface instead.",110 category = DeprecationWarning,111 stacklevel = 2112 )113 backwards_translate = {114 'filename': 'name',115 'content-type': 'content_type',116 }117 118 if key == 'content':119 return self.read()120 elif key == 'filename':121 return self.name122 elif key == 'content-type':123 return self.content_type124 else:125 return getattr(self, key)126 65 127 66 class TemporaryUploadedFile(UploadedFile): … … 141 80 """ 142 81 return self._file.name 143 82 144 83 # Most methods on this object get proxied to NamedTemporaryFile. 145 84 # We can't directly subclass because NamedTemporaryFile is actually a … … 160 99 # before the exception 161 100 return 162 else: 101 else: 163 102 raise e 164 103 165 104 class InMemoryUploadedFile(UploadedFile): 166 105 """ django/trunk/django/db/models/base.py
r8267 r8291 4 4 import os 5 5 from itertools import izip 6 from warnings import warn7 6 try: 8 7 set … … 478 477 return getattr(self, cachename) 479 478 480 def _get_FIELD_filename(self, field):481 warn("instance.get_%s_filename() is deprecated. Use instance.%s.path instead." % \482 (field.attname, field.attname), DeprecationWarning, stacklevel=3)483 try:484 return getattr(self, field.attname).path485 except ValueError:486 return ''487 488 def _get_FIELD_url(self, field):489 warn("instance.get_%s_url() is deprecated. Use instance.%s.url instead." % \490 (field.attname, field.attname), DeprecationWarning, stacklevel=3)491 try:492 return getattr(self, field.attname).url493 except ValueError:494 return ''495 496 def _get_FIELD_size(self, field):497 warn("instance.get_%s_size() is deprecated. Use instance.%s.size instead." % \498 (field.attname, field.attname), DeprecationWarning, stacklevel=3)499 return getattr(self, field.attname).size500 501 def _save_FIELD_file(self, field, filename, content, save=True):502 warn("instance.save_%s_file() is deprecated. Use instance.%s.save() instead." % \503 (field.attname, field.attname), DeprecationWarning, stacklevel=3)504 return getattr(self, field.attname).save(filename, content, save)505 506 _save_FIELD_file.alters_data = True507 508 def _get_FIELD_width(self, field):509 warn("instance.get_%s_width() is deprecated. Use instance.%s.width instead." % \510 (field.attname, field.attname), DeprecationWarning, stacklevel=3)511 return getattr(self, field.attname).width()512 513 def _get_FIELD_height(self, field):514 warn("instance.get_%s_height() is deprecated. Use instance.%s.height instead." % \515 (field.attname, field.attname), DeprecationWarning, stacklevel=3)516 return getattr(self, field.attname).height()517 479 518 480 django/trunk/django/db/models/fields/files.py
r8244 r8291 193 193 super(FileField, self).contribute_to_class(cls, name) 194 194 setattr(cls, self.name, FileDescriptor(self)) 195 setattr(cls, 'get_%s_filename' % self.name, curry(cls._get_FIELD_filename, field=self))196 setattr(cls, 'get_%s_url' % self.name, curry(cls._get_FIELD_url, field=self))197 setattr(cls, 'get_%s_size' % self.name, curry(cls._get_FIELD_size, field=self))198 setattr(cls, 'save_%s_file' % self.name, lambda instance, name, content, save=True: instance._save_FIELD_file(self, name, content, save))199 195 signals.post_delete.connect(self.delete_file, sender=cls) 200 196 … … 263 259 class ImageFieldFile(ImageFile, FieldFile): 264 260 def save(self, name, content, save=True): 265 266 if not hasattr(content, 'read'):267 import warnings268 warnings.warn(269 message = "Representing files as strings is deprecated." \270 "Use django.core.files.base.ContentFile instead.",271 category = DeprecationWarning,272 stacklevel = 2273 )274 content = ContentFile(content)275 276 261 # Repopulate the image dimension cache. 277 262 self._dimensions_cache = get_image_dimensions(content) 278 263 279 264 # Update width/height fields, if needed 280 265 if self.field.width_field: … … 282 267 if self.field.height_field: 283 268 setattr(self.instance, self.field.height_field, self.height) 284 269 285 270 super(ImageFieldFile, self).save(name, content, save) 286 271 … … 301 286 return [oldforms.ImageUploadField, oldforms.HiddenField] 302 287 303 def contribute_to_class(self, cls, name):304 super(ImageField, self).contribute_to_class(cls, name)305 # Add get_BLAH_width and get_BLAH_height methods, but only if the306 # image field doesn't have width and height cache fields.307 if not self.width_field:308 setattr(cls, 'get_%s_width' % self.name, curry(cls._get_FIELD_width, field=self))309 if not self.height_field:310 setattr(cls, 'get_%s_height' % self.name, curry(cls._get_FIELD_height, field=self))311 312 288 def formfield(self, **kwargs): 313 289 defaults = {'form_class': forms.ImageField} django/trunk/django/dispatch/dispatcher.py
r8223 r8291 1 1 import weakref 2 import warnings3 2 try: 4 3 set … … 198 197 if r_key == key: 199 198 del self.receivers[idx] 200 201 def connect(receiver, signal, sender=None, weak=True):202 """203 For backward compatibility only. See Signal.connect()204 """205 warnings.warn(206 category = DeprecationWarning,207 message = "dispatcher.connect() is deprecated; use Signal.connect() instead.",208 stacklevel = 2209 )210 return signal.connect(receiver, sender, weak)211 212 def disconnect(receiver, signal, sender=None, weak=True):213 """214 For backward compatibility only. See Signal.disconnect()215 """216 warnings.warn(217 category = DeprecationWarning,218 message = "dispatcher.disconnect() is deprecated; use Signal.disconnect() instead.",219 stacklevel = 2220 )221 signal.disconnect(receiver, sender, weak)222 223 def send(signal, sender=None, **named):224 """225 For backward compatibility only. See Signal.send()226 """227 warnings.warn(228 category = DeprecationWarning,229 message = "dispatcher.send() is deprecated; use Signal.send() instead.",230 stacklevel = 2231 )232 return signal.send(sender=sender, **named)233 234 def sendExact(signal, sender, **named ):235 """236 This function is deprecated, as it now has the same meaning as send.237 """238 warnings.warn(239 category = DeprecationWarning,240 message = "dispatcher.sendExact() is deprecated; use Signal.send() instead.",241 stacklevel = 2242 )243 return signal.send(sender=sender, **named)django/trunk/django/forms/fields.py
r8148 r8291 443 443 return initial 444 444 445 if isinstance(data, dict): 446 # We warn once, then support both ways below. 447 import warnings 448 warnings.warn( 449 message = "Representing uploaded files as dictionaries is deprecated. Use django.core.files.uploadedfile.SimpleUploadedFile instead.", 450 category = DeprecationWarning, 451 stacklevel = 2 452 ) 453 data = UploadedFile(data['filename'], data['content']) 454 445 # UploadedFile objects should have name and size attributes. 455 446 try: 456 447 file_name = data.name … … 508 499 trial_image = Image.open(file) 509 500 trial_image.verify() 510 except ImportError: 501 except ImportError: 511 502 # Under PyPy, it is possible to import PIL. However, the underlying 512 # _imaging C module isn't available, so an ImportError will be 513 # raised. Catch and re-raise. 503 # _imaging C module isn't available, so an ImportError will be 504 # raised. Catch and re-raise. 514 505 raise 515 506 except Exception: # Python Imaging Library doesn't recognize it as an image … … 644 635 return True 645 636 return False 646 637 647 638 class MultipleChoiceField(ChoiceField): 648 639 hidden_widget = MultipleHiddenInput django/trunk/django/forms/models.py
r8243 r8291 3 3 and database field objects. 4 4 """ 5 6 from warnings import warn7 5 8 6 from django.utils.translation import ugettext_lazy as _ … … 19 17 __all__ = ( 20 18 'ModelForm', 'BaseModelForm', 'model_to_dict', 'fields_for_model', 21 'save_instance', 'form_for_ model', 'form_for_instance', 'form_for_fields',22 'Model ChoiceField', 'ModelMultipleChoiceField',19 'save_instance', 'form_for_fields', 'ModelChoiceField', 20 'ModelMultipleChoiceField', 23 21 ) 24 22 … … 75 73 return save 76 74 77 def form_for_model(model, form=BaseForm, fields=None,78 formfield_callback=lambda f: f.formfield()):79 """80 Returns a Form class for the given Django model class.81 82 Provide ``form`` if you want to use a custom BaseForm subclass.83 84 Provide ``formfield_callback`` if you want to define different logic for85 determining the formfield for a given database field. It's a callable that86 takes a database Field instance and returns a form Field instance.87 """88 warn("form_for_model is deprecated. Use ModelForm instead.",89 PendingDeprecationWarning, stacklevel=3)90 opts = model._meta91 field_list = []92 for f in opts.fields + opts.many_to_many:93 if not f.editable:94 continue95 if fields and not f.name in fields:96 continue97 formfield = formfield_callback(f)98 if formfield:99 field_list.append((f.name, formfield))100 base_fields = SortedDict(field_list)101 return type(opts.object_name + 'Form', (form,),102 {'base_fields': base_fields, '_model': model,103 'save': make_model_save(model, fields, 'created')})104 105 def form_for_instance(instance, form=BaseForm, fields=None,106 formfield_callback=lambda f, **kwargs: f.formfield(**kwargs)):107 """108 Returns a Form class for the given Django model instance.109 110 Provide ``form`` if you want to use a custom BaseForm subclass.111 112 Provide ``formfield_callback`` if you want to define different logic for113 determining the formfield for a given database field. It's a callable that114 takes a database Field instance, plus **kwargs, and returns a form Field115 instance with the given kwargs (i.e. 'initial').116 """117 warn("form_for_instance is deprecated. Use ModelForm instead.",118 PendingDeprecationWarning, stacklevel=3)119 model = instance.__class__120 opts = model._meta121 field_list = []122 for f in opts.fields + opts.many_to_many:123 if not f.editable:124 continue125 if fields and not f.name in fields:126 continue127 current_value = f.value_from_object(instance)128 formfield = formfield_callback(f, initial=current_value)129 if formfield:130 field_list.append((f.name, formfield))131 base_fields = SortedDict(field_list)132 return type(opts.object_name + 'InstanceForm', (form,),133 {'base_fields': base_fields, '_model': model,134 'save': make_instance_save(instance, fields, 'changed')})135 136 75 def form_for_fields(field_list): 137 76 """ … … 290 229 setattr(Meta, 'exclude', exclude) 291 230 class_name = model.__name__ + 'Form' 292 return ModelFormMetaclass(class_name, (form,), {'Meta': Meta, 231 return ModelFormMetaclass(class_name, (form,), {'Meta': Meta, 293 232 'formfield_callback': formfield_callback}) 294 233 … … 411 350 self.rel_name = RelatedObject(self.fk.rel.to, self.model, self.fk).get_accessor_name() 412 351 super(BaseInlineFormSet, self).__init__(data, files, prefix=prefix or self.rel_name) 413 352 414 353 def _construct_forms(self): 415 354 if self.save_as_new: … … 420 359 def get_queryset(self): 421 360 """ 422 Returns this FormSet's queryset, but restricted to children of 361 Returns this FormSet's queryset, but restricted to children of 423 362 self.instance 424 363 """ … … 444 383 fk = fks_to_parent[0] 445 384 if not isinstance(fk, ForeignKey) or \ 446 (fk.rel.to != parent_model and 385 (fk.rel.to != parent_model and 447 386 fk.rel.to not in parent_model._meta.parents.keys()): 448 387 raise Exception("fk_name '%s' is not a ForeignKey to %s" % (fk_name, parent_model)) … … 452 391 # Try to discover what the ForeignKey from model to parent_model is 453 392 fks_to_parent = [ 454 f for f in opts.fields 455 if isinstance(f, ForeignKey) 456 and (f.rel.to == parent_model 393 f for f in opts.fields 394 if isinstance(f, ForeignKey) 395 and (f.rel.to == parent_model 457 396 or f.rel.to in parent_model._meta.parents.keys()) 458 397 ] … … 479 418 fk = _get_foreign_key(parent_model, model, fk_name=fk_name) 480 419 # let the formset handle object deletion by default 481 420 482 421 if exclude is not None: 483 422 exclude.append(fk.name) … … 529 468 self.empty_label = empty_label 530 469 self.cache_choices = cache_choices 531 470 532 471 # Call Field instead of ChoiceField __init__() because we don't need 533 472 # ChoiceField.__init__(). … … 546 485 queryset = property(_get_queryset, _set_queryset) 547 486 548 # this method will be used to create object labels by the QuerySetIterator. 549 # Override it to customize the label. 487 # this method will be used to create object labels by the QuerySetIterator. 488 # Override it to customize the label. 550 489 def label_from_instance(self, obj): 551 490 """ … … 555 494 """ 556 495 return smart_unicode(obj) 557 496 558 497 def _get_choices(self): 559 498 # If self._choices is set, then somebody must have manually set django/trunk/django/views/generic/create_update.py
r8106 r8291 8 8 from django.views.generic import GenericViewError 9 9 10 def deprecate_follow(follow):11 """12 Issues a DeprecationWarning if follow is anything but None.13 14 The old Manipulator-based forms used a follow argument that is no longer15 needed for newforms-based forms.16 """17 if follow is not None:18 import warnings19 msg = ("Generic views have been changed to use newforms, and the"20 " 'follow' argument is no longer used. Please update your code"21 " to not use the 'follow' argument.")22 warnings.warn(msg, DeprecationWarning, stacklevel=3)23 10 24 11 def apply_extra_context(extra_context, context): … … 106 93 def create_object(request, model=None, template_name=None, 107 94 template_loader=loader, extra_context=None, post_save_redirect=None, 108 login_required=False, follow=None, context_processors=None, 109 form_class=None): 95 login_required=False, context_processors=None, form_class=None): 110 96 """ 111 97 Generic object-creation function. … … 116 102 the form for the object 117 103 """ 118 deprecate_follow(follow)119 104 if extra_context is None: extra_context = {} 120 105 if login_required and not request.user.is_authenticated(): … … 144 129 def update_object(request, model=None, object_id=None, slug=None, 145 130 slug_field='slug', template_name=None, template_loader=loader, 146 extra_context=None, post_save_redirect=None, 147 login_required=False, follow=None, context_processors=None,148 template_object_name='object',form_class=None):131 extra_context=None, post_save_redirect=None, login_required=False, 132 context_processors=None, template_object_name='object', 133 form_class=None): 149 134 """ 150 135 Generic object-update function. … … 157 142 the original object being edited 158 143 """ 159 deprecate_follow(follow)160 144 if extra_context is None: extra_context = {} 161 145 if login_required and not request.user.is_authenticated(): django/trunk/docs/custom_model_fields.txt
r8244 r8291 484 484 485 485 Returns the default form field to use when this field is displayed 486 in a model. This method is called by the `helper functions`_ 487 ``form_for_model()`` and ``form_for_instance()``. 486 in a model. 488 487 489 488 All of the ``kwargs`` dictionary is passed directly to the form field's django/trunk/docs/db-api.txt
r8267 r8291 1419 1419 You can also use a queryset to dynamically evaluate the list of values 1420 1420 instead of providing a list of literal values. The queryset must be 1421 reduced to a list of individual values using the ``values()`` method, 1421 reduced to a list of individual values using the ``values()`` method, 1422 1422 and then converted into a query using the ``query`` attribute:: 1423 1423 … … 2107 2107 2108 2108 One-to-one relationships are very similar to many-to-one relationships. 2109 If you define a OneToOneField on your model, instances of that model will have 2109 If you define a OneToOneField on your model, instances of that model will have 2110 2110 access to the related object via a simple attribute of the model. 2111 2111 … … 2129 2129 a ``DoesNotExist`` exception. 2130 2130 2131 Instances can be assigned to the reverse relationship in the same way as 2131 Instances can be assigned to the reverse relationship in the same way as 2132 2132 you would assign the forward relationship:: 2133 2133 2134 2134 e.entrydetail = ed 2135 2135 … … 2314 2314 .. _lookup API sample model: ../models/lookup/ 2315 2315 2316 get_FOO_filename()2317 ------------------2318 2319 **Deprecated in Django development version**; use ``object.FOO.name`` instead.2320 See `managing files`_ for details.2321 2322 get_FOO_url()2323 -------------2324 2325 **Deprecated in Django development version**; use ``object.FOO.url`` instead.2326 See `managing files`_ for details.2327 2328 get_FOO_size()2329 --------------2330 2331 **Deprecated in Django development version**; use ``object.FOO.size`` instead.2332 See `managing files`_ for details.2333 2334 save_FOO_file(filename, raw_contents)2335 -------------------------------------2336 2337 **Deprecated in Django development version**; use ``object.FOO.save()`` instead.2338 See `managing files`_ for details.2339 2340 get_FOO_height() and get_FOO_width()2341 ------------------------------------2342 2343 **Deprecated in Django development version**; use ``object.FOO.width`` and2344 ``object.FOO.height`` instead. See `managing files`_ for details.2345 2346 .. _`managing files`: ../files/2347 2316 2348 2317 Shortcuts django/trunk/docs/forms.txt
r8201 r8291 1829 1829 `ModelForms documentation`_. 1830 1830 1831 Looking for the ``form_for_model`` and ``form_for_instance`` documentation?1832 They've been deprecated, but you can still `view the documentation`_.1833 1834 1831 .. _ModelForms documentation: ../modelforms/ 1835 .. _view the documentation: ../form_for_model/1836 1832 1837 1833 Media django/trunk/docs/model-api.txt
r8244 r8291 309 309 ``/home/media/photos/2007/01/15``. 310 310 311 If you want to retrieve the upload file's on-disk filename, or a URL that 312 refers to that file, or the file's size, you can use the 313 ``get_FOO_filename()``, ``get_FOO_url()`` and ``get_FOO_size()`` methods. 314 They are all documented here__. 315 316 __ ../db-api/#get-foo-filename 311 Information about the uploaded ``File`` object, such as its on-disk filename, 312 its size, or its URL, is available via attributes on the object itself. See the 313 `managing files`__ documentation for more information about ``File`` objects. 314 315 __ ../files/ 317 316 318 317 Note that whenever you deal with uploaded files, you should pay close attention … … 393 392 width of the image each time a model instance is saved. 394 393 395 In addition to the special ``get_FOO_*`` methods that are available for 396 ``FileField``, an ``ImageField`` also has ``get_FOO_height()`` and 397 ``get_FOO_width()`` methods. These are documented elsewhere_. 394 In addition to the `standard attributes and methods`_ that are available for 395 ``FileField``, an ``ImageField`` also has ``width`` and ``height`` attributes. 398 396 399 397 Requires the `Python Imaging Library`_. 400 401 .. _Python Imaging Library: http://www.pythonware.com/products/pil/402 .. _elsewhere: ../db-api/#get-foo-height-and-get-foo-width403 398 404 399 **New in development version:** By default, ``ImageField`` instances are … … 406 401 can change the maximum length using the ``max_length`` argument. 407 402 403 .. _standard attributes and methods: ../files/#file-attributes-and-methods 404 .. _Python Imaging Library: http://www.pythonware.com/products/pil/ 408 405 409 406 ``IntegerField`` … … 606 603 ) 607 604 608 The first element in each tuple is the name to apply to the group. The 605 The first element in each tuple is the name to apply to the group. The 609 606 second element is an iterable of 2-tuples, with each 2-tuple containing 610 a value and a human-readable name for an option. Grouped options may be 611 combined with ungrouped options within a single list (such as the 607 a value and a human-readable name for an option. Grouped options may be 608 combined with ungrouped options within a single list (such as the 612 609 `unknown` option in this example). 613 610 … … 982 979 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 983 980 984 **New in Django development version** 981 **New in Django development version** 985 982 986 983 When you're only dealing with simple many-to-many relationships such as 987 984 mixing and matching pizzas and toppings, a standard ``ManyToManyField`` 988 985 is all you need. However, sometimes you may need to associate data with the 989 relationship between two models. 986 relationship between two models. 990 987 991 988 For example, consider the case of an application tracking the musical groups … … 1022 1019 invite_reason = models.CharField(max_length=64) 1023 1020 1024 When you set up the intermediary model, you explicitly specify foreign 1021 When you set up the intermediary model, you explicitly specify foreign 1025 1022 keys to the models that are involved in the ManyToMany relation. This 1026 1023 explicit declaration defines how the two models are related. … … 1031 1028 on the target model (this would be ``Person`` in our example). If you 1032 1029 have more than one foreign key, a validation error will be raised. 1033 1034 * Your intermediate model must contain one - and *only* one - foreign key 1030 1031 * Your intermediate model must contain one - and *only* one - foreign key 1035 1032 on the source model (this would be ``Group`` in our example). If you 1036 1033 have more than one foreign key, a validation error will be raised. … … 1041 1038 will be treated as the two (different) sides of the many-to-many 1042 1039 relation. 1043 1040 1044 1041 * When defining a many-to-many relationship from a model to 1045 1042 itself, using an intermediary model, you *must* use … … 1047 1044 ``ManyToManyField`` above). 1048 1045 1049 Now that you have set up your ``ManyToManyField`` to use your intermediary 1046 Now that you have set up your ``ManyToManyField`` to use your intermediary 1050 1047 model (Membership, in this case), you're ready to start creating some 1051 1048 many-to-many relationships. You do this by creating instances of the 1052 1049 intermediate model:: 1053 1050 1054 1051 >>> ringo = Person.objects.create(name="Ringo Starr") 1055 1052 >>> paul = Person.objects.create(name="Paul McCartney") 1056 1053 >>> beatles = Group.objects.create(name="The Beatles") 1057 1054 >>> m1 = Membership(person=ringo, group=beatles, 1058 ... date_joined=date(1962, 8, 16), 1055 ... date_joined=date(1962, 8, 16), 1059 1056 ... invite_reason= "Needed a new drummer.") 1060 1057 >>> m1.save() … … 1064 1061 [<Group: The Beatles>] 1065 1062 >>> m2 = Membership.objects.create(person=paul, group=beatles, 1066 ... date_joined=date(1960, 8, 1), 1063 ... date_joined=date(1960, 8, 1), 1067 1064 ... invite_reason= "Wanted to form a band.") 1068 1065 >>> beatles.members.all() … … 1078 1075 # AND NEITHER WILL THIS 1079 1076 >>> beatles.members = [john, paul, ringo, george] 1080 1077 1081 1078 Why? You can't just create a relationship between a Person and a Group - you 1082 1079 need to specify all the detail for the relationship required by the … … 1095 1092 1096 1093 Once you have established the many-to-many relationships by creating instances 1097 of your intermediate model, you can issue queries. Just as with normal 1098 many-to-many relationships, you can query using the attributes of the 1094 of your intermediate model, you can issue queries. Just as with normal 1095 many-to-many relationships, you can query using the attributes of the 1099 1096 many-to-many-related model:: 1100 1097 … … 1103 1100 [<Group: The Beatles>] 1104 1101 1105 As you are using an intermediate table, you can also query on the attributes 1102 As you are using an intermediate table, you can also query on the attributes 1106 1103 of the intermediate model:: 1107 1104 … … 1111 1108 ... membership__date_joined__gt=date(1961,1,1)) 1112 1109 [<Person: Ringo Starr] 1113 1110 1114 1111 One-to-one relationships 1115 1112 ~~~~~~~~~~~~~~~~~~~~~~~~ … … 1556 1553 class MyManager(models.Manager):: 1557 1554 use_for_related_fields = True 1558 1555 1559 1556 ... 1560 1557 django/trunk/tests/modeltests/model_forms/models.py
r8257 r8291 364 364 <tr><th>Pub date:</th><td><input type="text" name="pub_date" /></td></tr> 365 365 366 Use form_for_instance to create a Form from a model instance. The difference 367 between this Form and one created via form_for_model is that the object's 368 current values are inserted as 'initial' data in each Field. 366 When the ModelForm is passed an instance, that instance's current values are 367 inserted as 'initial' data in each Field. 369 368 >>> w = Writer.objects.get(name='Mike Royko') 370 369 >>> class RoykoForm(ModelForm): django/trunk/tests/regressiontests/forms/models.py
r8013 r8291 26 26 27 27 __test__ = {'API_TESTS': """ 28 >>> from django.forms import form_for_model, form_for_instance28 >>> from django.forms.models import ModelForm 29 29 >>> from django.core.files.uploadedfile import SimpleUploadedFile 30 30 … … 38 38 39 39 # Boundary conditions on a PostitiveIntegerField ######################### 40 >>> BoundaryForm = form_for_model(BoundaryModel) 41 >>> f = BoundaryForm({'positive_integer':100}) 40 >>> class BoundaryForm(ModelForm): 41 ... class Meta: 42 ... model = BoundaryModel 43 >>> f = BoundaryForm({'positive_integer': 100}) 42 44 >>> f.is_valid() 43 45 True 44 >>> f = BoundaryForm({'positive_integer': 0})46 >>> f = BoundaryForm({'positive_integer': 0}) 45 47 >>> f.is_valid() 46 48 True 47 >>> f = BoundaryForm({'positive_integer': -100})49 >>> f = BoundaryForm({'positive_integer': -100}) 48 50 >>> f.is_valid() 49 51 False … … 52 54 If the model has default values for some fields, they are used as the formfield 53 55 initial values. 54 >>> DefaultsForm = form_for_model(Defaults) 56 >>> class DefaultsForm(ModelForm): 57 ... class Meta: 58 ... model = Defaults 55 59 >>> DefaultsForm().fields['name'].initial 56 60 u'class default value' … … 60 64 42 61 65 62 In form_for_instance(), the initial values come from the instance's values, not63 the model's defaults.64 >>> foo_instance = Defaults(name=u'instance value', def_date = datetime.date(1969, 4, 4), value =12)65 >>> InstanceForm = form_for_instance(foo_instance)66 >>> InstanceForm().fields['name'].initial66 In a ModelForm that is passed an instance, the initial values come from the 67 instance's values, not the model's defaults. 68 >>> foo_instance = Defaults(name=u'instance value', def_date=datetime.date(1969, 4, 4), value=12) 69 >>> instance_form = DefaultsForm(instance=foo_instance) 70 >>> instance_form.initial['name'] 67 71 u'instance value' 68 >>> InstanceForm().fields['def_date'].initial72 >>> instance_form.initial['def_date'] 69 73 datetime.date(1969, 4, 4) 70 >>> InstanceForm().fields['value'].initial74 >>> instance_form.initial['value'] 71 75 12 72 76 """}
