diff options
| author | Gary Wilson Jr <gary.wilson@gmail.com> | 2008-08-27 07:19:44 +0000 |
|---|---|---|
| committer | Gary Wilson Jr <gary.wilson@gmail.com> | 2008-08-27 07:19:44 +0000 |
| commit | c2ba59fc1da5287d6286e2c2aca4083d5bafe056 (patch) | |
| tree | 26c05bc1b845efadd28126adee8f2a3726f09424 /docs/obsolete | |
| parent | a1575766604205b3bddf0f05d13ad698c78a7582 (diff) | |
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
Diffstat (limited to 'docs/obsolete')
| -rw-r--r-- | docs/obsolete/forms.txt | 692 | ||||
| -rw-r--r-- | docs/obsolete/newforms-migration.txt | 48 |
2 files changed, 0 insertions, 740 deletions
diff --git a/docs/obsolete/forms.txt b/docs/obsolete/forms.txt deleted file mode 100644 index 9bfd4a979e..0000000000 --- a/docs/obsolete/forms.txt +++ /dev/null @@ -1,692 +0,0 @@ -.. _obsolete-forms: - -=============================== -Forms, fields, and manipulators -=============================== - -Forwards-compatibility note -=========================== - -The legacy forms/manipulators system described in this document is going to be -replaced in the next Django release. If you're starting from scratch, we -strongly encourage you not to waste your time learning this. Instead, learn and -use the new :ref:`forms library <topics-forms-index>`. - -Introduction -============ - -Once you've got a chance to play with Django's admin interface, you'll probably -wonder if the fantastic form validation framework it uses is available to user -code. It is, and this document explains how the framework works. - -We'll take a top-down approach to examining Django's form validation framework, -because much of the time you won't need to use the lower-level APIs. Throughout -this document, we'll be working with the following model, a "place" object:: - - from django.db import models - - PLACE_TYPES = ( - (1, 'Bar'), - (2, 'Restaurant'), - (3, 'Movie Theater'), - (4, 'Secret Hideout'), - ) - - class Place(models.Model): - name = models.CharField(max_length=100) - address = models.CharField(max_length=100, blank=True) - city = models.CharField(max_length=50, blank=True) - state = models.USStateField() - zip_code = models.CharField(max_length=5, blank=True) - place_type = models.IntegerField(choices=PLACE_TYPES) - - class Admin: - pass - - def __unicode__(self): - return self.name - -Defining the above class is enough to create an admin interface to a ``Place``, -but what if you want to allow public users to submit places? - -Automatic Manipulators -====================== - -The highest-level interface for object creation and modification is the -**automatic Manipulator** framework. An automatic manipulator is a utility -class tied to a given model that "knows" how to create or modify instances of -that model and how to validate data for the object. Automatic Manipulators come -in two flavors: ``AddManipulators`` and ``ChangeManipulators``. Functionally -they are quite similar, but the former knows how to create new instances of the -model, while the latter modifies existing instances. Both types of classes are -automatically created when you define a new class:: - - >>> from mysite.myapp.models import Place - >>> Place.AddManipulator - <class 'django.models.manipulators.AddManipulator'> - >>> Place.ChangeManipulator - <class 'django.models.manipulators.ChangeManipulator'> - -Using the ``AddManipulator`` ----------------------------- - -We'll start with the ``AddManipulator``. Here's a very simple view that takes -POSTed data from the browser and creates a new ``Place`` object:: - - from django.shortcuts import render_to_response - from django.http import Http404, HttpResponse, HttpResponseRedirect - from django import oldforms as forms - from mysite.myapp.models import Place - - def naive_create_place(request): - """A naive approach to creating places; don't actually use this!""" - # Create the AddManipulator. - manipulator = Place.AddManipulator() - - # Make a copy of the POSTed data so that do_html2python can - # modify it in place (request.POST is immutable). - new_data = request.POST.copy() - - # Convert the request data (which will all be strings) into the - # appropriate Python types for those fields. - manipulator.do_html2python(new_data) - - # Save the new object. - new_place = manipulator.save(new_data) - - # It worked! - return HttpResponse("Place created: %s" % new_place) - -The ``naive_create_place`` example works, but as you probably can tell, this -view has a number of problems: - - * No validation of any sort is performed. If, for example, the ``name`` field - isn't given in ``request.POST``, the save step will cause a database error - because that field is required. Ugly. - - * Even if you *do* perform validation, there's still no way to give that - information to the user in any sort of useful way. - - * You'll have to separately create a form (and view) that submits to this - page, which is a pain and is redundant. - -Let's dodge these problems momentarily to take a look at how you could create a -view with a form that submits to this flawed creation view:: - - def naive_create_place_form(request): - """Simplistic place form view; don't actually use anything like this!""" - # Create a FormWrapper object that the template can use. Ignore - # the last two arguments to FormWrapper for now. - form = forms.FormWrapper(Place.AddManipulator(), {}, {}) - return render_to_response('places/naive_create_form.html', {'form': form}) - -(This view, as well as all the following ones, has the same imports as in the -first example above.) - -The ``forms.FormWrapper`` object is a wrapper that templates can -easily deal with to create forms. Here's the ``naive_create_form.html`` -template:: - - {% extends "base.html" %} - - {% block content %} - <h1>Create a place:</h1> - - <form method="post" action="../do_new/"> - <p><label for="id_name">Name:</label> {{ form.name }}</p> - <p><label for="id_address">Address:</label> {{ form.address }}</p> - <p><label for="id_city">City:</label> {{ form.city }}</p> - <p><label for="id_state">State:</label> {{ form.state }}</p> - <p><label for="id_zip_code">Zip:</label> {{ form.zip_code }}</p> - <p><label for="id_place_type">Place type:</label> {{ form.place_type }}</p> - <input type="submit" /> - </form> - {% endblock %} - -Before we get back to the problems with these naive set of views, let's go over -some salient points of the above template: - - * Field "widgets" are handled for you: ``{{ form.field }}`` automatically - creates the "right" type of widget for the form, as you can see with the - ``place_type`` field above. - - * There isn't a way just to spit out the form. You'll still need to define - how the form gets laid out. This is a feature: Every form should be - designed differently. Django doesn't force you into any type of mold. - If you must use tables, use tables. If you're a semantic purist, you can - probably find better HTML than in the above template. - - * To avoid name conflicts, the ``id`` values of form elements take the - form "id_*fieldname*". - -By creating a creation form we've solved problem number 3 above, but we still -don't have any validation. Let's revise the validation issue by writing a new -creation view that takes validation into account:: - - def create_place_with_validation(request): - manipulator = Place.AddManipulator() - new_data = request.POST.copy() - - # Check for validation errors - errors = manipulator.get_validation_errors(new_data) - manipulator.do_html2python(new_data) - if errors: - return render_to_response('places/errors.html', {'errors': errors}) - else: - new_place = manipulator.save(new_data) - return HttpResponse("Place created: %s" % new_place) - -In this new version, errors will be found -- ``manipulator.get_validation_errors`` -handles all the validation for you -- and those errors can be nicely presented -on an error page (templated, of course):: - - {% extends "base.html" %} - - {% block content %} - - <h1>Please go back and correct the following error{{ errors|pluralize }}:</h1> - <ul> - {% for e in errors.items %} - <li>Field "{{ e.0 }}": {{ e.1|join:", " }}</li> - {% endfor %} - </ul> - - {% endblock %} - -Still, this has its own problems: - - * There's still the issue of creating a separate (redundant) view for the - submission form. - - * Errors, though nicely presented, are on a separate page, so the user will - have to use the "back" button to fix errors. That's ridiculous and unusable. - -The best way to deal with these issues is to collapse the two views -- the form -and the submission -- into a single view. This view will be responsible for -creating the form, validating POSTed data, and creating the new object (if the -data is valid). An added bonus of this approach is that errors and the form will -both be available on the same page, so errors with fields can be presented in -context. - -.. admonition:: Philosophy: - - Finally, for the HTTP purists in the audience (and the authorship), this - nicely matches the "true" meanings of HTTP GET and HTTP POST: GET fetches - the form, and POST creates the new object. - -Below is the finished view:: - - def create_place(request): - manipulator = Place.AddManipulator() - - if request.method == 'POST': - # If data was POSTed, we're trying to create a new Place. - new_data = request.POST.copy() - - # Check for errors. - errors = manipulator.get_validation_errors(new_data) - manipulator.do_html2python(new_data) - - if not errors: - # No errors. This means we can save the data! - new_place = manipulator.save(new_data) - - # Redirect to the object's "edit" page. Always use a redirect - # after POST data, so that reloads don't accidentally create - # duplicate entries, and so users don't see the confusing - # "Repost POST data?" alert box in their browsers. - return HttpResponseRedirect("/places/edit/%i/" % new_place.id) - else: - # No POST, so we want a brand new form without any data or errors. - errors = new_data = {} - - # Create the FormWrapper, template, context, response. - form = forms.FormWrapper(manipulator, new_data, errors) - return render_to_response('places/create_form.html', {'form': form}) - -and here's the ``create_form`` template:: - - {% extends "base.html" %} - - {% block content %} - <h1>Create a place:</h1> - - {% if form.has_errors %} - <h2>Please correct the following error{{ form.error_dict|pluralize }}:</h2> - {% endif %} - - <form method="post" action="."> - <p> - <label for="id_name">Name:</label> {{ form.name }} - {% if form.name.errors %}*** {{ form.name.errors|join:", " }}{% endif %} - </p> - <p> - <label for="id_address">Address:</label> {{ form.address }} - {% if form.address.errors %}*** {{ form.address.errors|join:", " }}{% endif %} - </p> - <p> - <label for="id_city">City:</label> {{ form.city }} - {% if form.city.errors %}*** {{ form.city.errors|join:", " }}{% endif %} - </p> - <p> - <label for="id_state">State:</label> {{ form.state }} - {% if form.state.errors %}*** {{ form.state.errors|join:", " }}{% endif %} - </p> - <p> - <label for="id_zip_code">Zip:</label> {{ form.zip_code }} - {% if form.zip_code.errors %}*** {{ form.zip_code.errors|join:", " }}{% endif %} - </p> - <p> - <label for="id_place_type">Place type:</label> {{ form.place_type }} - {% if form.place_type.errors %}*** {{ form.place_type.errors|join:", " }}{% endif %} - </p> - <input type="submit" /> - </form> - {% endblock %} - -The second two arguments to ``FormWrapper`` (``new_data`` and ``errors``) -deserve some mention. - -The first is any "default" data to be used as values for the fields. Pulling -the data from ``request.POST``, as is done above, makes sure that if there are -errors, the values the user put in aren't lost. If you try the above example, -you'll see this in action. - -The second argument is the error list retrieved from -``manipulator.get_validation_errors``. When passed into the ``FormWrapper``, -this gives each field an ``errors`` item (which is a list of error messages -associated with the field) as well as a ``html_error_list`` item, which is a -``<ul>`` of error messages. The above template uses these error items to -display a simple error message next to each field. The error list is saved as -an ``error_dict`` attribute of the ``FormWrapper`` object. - -Using the ``ChangeManipulator`` -------------------------------- - -The above has covered using the ``AddManipulator`` to create a new object. What -about editing an existing one? It's shockingly similar to creating a new one:: - - def edit_place(request, place_id): - # Get the place in question from the database and create a - # ChangeManipulator at the same time. - try: - manipulator = Place.ChangeManipulator(place_id) - except Place.DoesNotExist: - raise Http404 - - # Grab the Place object in question for future use. - place = manipulator.original_object - - if request.method == 'POST': - new_data = request.POST.copy() - errors = manipulator.get_validation_errors(new_data) - manipulator.do_html2python(new_data) - if not errors: - manipulator.save(new_data) - - # Do a post-after-redirect so that reload works, etc. - return HttpResponseRedirect("/places/edit/%i/" % place.id) - else: - errors = {} - # This makes sure the form accurate represents the fields of the place. - new_data = manipulator.flatten_data() - - form = forms.FormWrapper(manipulator, new_data, errors) - return render_to_response('places/edit_form.html', {'form': form, 'place': place}) - -The only real differences are: - - * We create a ``ChangeManipulator`` instead of an ``AddManipulator``. - The argument to a ``ChangeManipulator`` is the ID of the object - to be changed. As you can see, the initializer will raise an - ``ObjectDoesNotExist`` exception if the ID is invalid. - - * ``ChangeManipulator.original_object`` stores the instance of the - object being edited. - - * We set ``new_data`` based upon ``flatten_data()`` from the manipulator. - ``flatten_data()`` takes the data from the original object under - manipulation, and converts it into a data dictionary that can be used - to populate form elements with the existing values for the object. - - * The above example uses a different template, so create and edit can be - "skinned" differently if needed, but the form chunk itself is completely - identical to the one in the create form above. - -The astute programmer will notice the add and create functions are nearly -identical and could in fact be collapsed into a single view. This is left as an -exercise for said programmer. - -(However, the even-more-astute programmer will take heed of the note at the top -of this document and check out the :ref:`generic views <ref-generic-views>` -documentation if all she wishes to do is this type of simple create/update.) - -Custom forms and manipulators -============================= - -All the above is fine and dandy if you just want to use the automatically -created manipulators. But the coolness doesn't end there: You can easily create -your own custom manipulators for handling custom forms. - -Custom manipulators are pretty simple. Here's a manipulator that you might use -for a "contact" form on a website:: - - from django import oldforms as forms - - urgency_choices = ( - (1, "Extremely urgent"), - (2, "Urgent"), - (3, "Normal"), - (4, "Unimportant"), - ) - - class ContactManipulator(forms.Manipulator): - def __init__(self): - self.fields = ( - forms.EmailField(field_name="from", is_required=True), - forms.TextField(field_name="subject", length=30, max_length=200, is_required=True), - forms.SelectField(field_name="urgency", choices=urgency_choices), - forms.LargeTextField(field_name="contents", is_required=True), - ) - -A certain similarity to Django's models should be apparent. The only required -method of a custom manipulator is ``__init__`` which must define the fields -present in the manipulator. See the ``django.forms`` module for -all the form fields provided by Django. - -You use this custom manipulator exactly as you would use an auto-generated one. -Here's a simple function that might drive the above form:: - - def contact_form(request): - manipulator = ContactManipulator() - if request.method == 'POST': - new_data = request.POST.copy() - errors = manipulator.get_validation_errors(new_data) - manipulator.do_html2python(new_data) - if not errors: - - # Send e-mail using new_data here... - - return HttpResponseRedirect("/contact/thankyou/") - else: - errors = new_data = {} - form = forms.FormWrapper(manipulator, new_data, errors) - return render_to_response('contact_form.html', {'form': form}) - -Implementing ``flatten_data`` for custom manipulators ------------------------------------------------------- - -It is possible (although rarely needed) to replace the default automatically -created manipulators on a model with your own custom manipulators. If you do -this and you are intending to use those models in generic views, you should -also define a ``flatten_data`` method in any ``ChangeManipulator`` replacement. -This should act like the default ``flatten_data`` and return a dictionary -mapping field names to their values, like so:: - - def flatten_data(self): - obj = self.original_object - return dict( - from = obj.from, - subject = obj.subject, - ... - ) - -In this way, your new change manipulator will act exactly like the default -version. - -``FileField`` and ``ImageField`` special cases -============================================== - -Dealing with ``FileField`` and ``ImageField`` objects is a little more -complicated. - -First, you'll need to make sure that your ``<form>`` element correctly defines -the ``enctype`` as ``"multipart/form-data"``, in order to upload files:: - - <form enctype="multipart/form-data" method="post" action="/foo/"> - -Next, you'll need to treat the field in the template slightly differently. A -``FileField`` or ``ImageField`` is represented by *two* HTML form elements. - -For example, given this field in a model:: - - photo = model.ImageField('/path/to/upload/location') - -You'd need to display two formfields in the template:: - - <p><label for="id_photo">Photo:</label> {{ form.photo }}{{ form.photo_file }}</p> - -The first bit (``{{ form.photo }}``) displays the currently-selected file, -while the second (``{{ form.photo_file }}``) actually contains the file upload -form field. Thus, at the validation layer you need to check the ``photo_file`` -key. - -Finally, in your view, make sure to access ``request.FILES``, rather than -``request.POST``, for the uploaded files. This is necessary because -``request.POST`` does not contain file-upload data. - -For example, following the ``new_data`` convention, you might do something like -this:: - - new_data = request.POST.copy() - new_data.update(request.FILES) - -Validators -========== - -One useful feature of manipulators is the automatic validation. Validation is -done using a simple validation API: A validator is a callable that raises a -``ValidationError`` if there's something wrong with the data. -``django.core.validators`` defines a host of validator functions (see below), -but defining your own couldn't be easier:: - - from django.core import validators - from django import oldforms as forms - - class ContactManipulator(forms.Manipulator): - def __init__(self): - self.fields = ( - # ... snip fields as above ... - forms.EmailField(field_name="to", validator_list=[self.isValidToAddress]) - ) - - def isValidToAddress(self, field_data, all_data): - if not field_data.endswith("@example.com"): - raise validators.ValidationError("You can only send messages to example.com e-mail addresses.") - -Above, we've added a "to" field to the contact form, but required that the "to" -address end with "@example.com" by adding the ``isValidToAddress`` validator to -the field's ``validator_list``. - -The arguments to a validator function take a little explanation. ``field_data`` -is the value of the field in question, and ``all_data`` is a dictionary of all -the data being validated. - -.. admonition:: Note:: - - At the point validators are called all data will still be - strings (as ``do_html2python`` hasn't been called yet). - -Also, because consistency in user interfaces is important, we strongly urge you -to put punctuation at the end of your validation messages. - -When are validators called? ---------------------------- - -After a form has been submitted, Django validates each field in turn. First, -if the field is required, Django checks that it is present and non-empty. Then, -if that test passes *and the form submission contained data* for that field, all -the validators for that field are called in turn. The emphasized portion in the -last sentence is important: if a form field is not submitted (because it -contains no data -- which is normal HTML behavior), the validators are not -run against the field. - -This feature is particularly important for models using -``models.BooleanField`` or custom manipulators using things like -``forms.CheckBoxField``. If the checkbox is not selected, it will not -contribute to the form submission. - -If you would like your validator to run *always*, regardless of whether its -attached field contains any data, set the ``always_test`` attribute on the -validator function. For example:: - - def my_custom_validator(field_data, all_data): - # ... - my_custom_validator.always_test = True - -This validator will always be executed for any field it is attached to. - -Ready-made validators ---------------------- - -Writing your own validator is not difficult, but there are some situations -that come up over and over again. Django comes with a number of validators -that can be used directly in your code. All of these functions and classes -reside in ``django/core/validators.py``. - -The following validators should all be self-explanatory. Each one provides a -check for the given property: - - * isAlphaNumeric - * isAlphaNumericURL - * isSlug - * isLowerCase - * isUpperCase - * isCommaSeparatedIntegerList - * isCommaSeparatedEmailList - * isValidIPAddress4 - * isNotEmpty - * isOnlyDigits - * isNotOnlyDigits - * isInteger - * isOnlyLetters - * isValidANSIDate - * isValidANSITime - * isValidEmail - * isValidFloat - * isValidImage - * isValidImageURL - * isValidPhone - * isValidQuicktimeVideoURL - * isValidURL - * isValidHTML - * isWellFormedXml - * isWellFormedXmlFragment - * isExistingURL - * isValidUSState - * hasNoProfanities - -There are also a group of validators that are slightly more flexible. For -these validators, you create a validator instance, passing in the parameters -described below. The returned object is a callable that can be used as a -validator. - -For example:: - - from django.core import validators - from django import oldforms as forms - - power_validator = validators.IsAPowerOf(2) - - class InstallationManipulator(forms.Manipulator) - def __init__(self): - self.fields = ( - ... - forms.IntegerField(field_name = "size", validator_list=[power_validator]) - ) - -Here, ``validators.IsAPowerOf(...)`` returned something that could be used as -a validator (in this case, a check that a number was a power of 2). - -Each of the standard validators that take parameters have an optional final -argument (``error_message``) that is the message returned when validation -fails. If no message is passed in, a default message is used. - -``AlwaysMatchesOtherField`` - Takes a field name and the current field is valid if and only if its value - matches the contents of the other field. - -``ValidateIfOtherFieldEquals`` - Takes three parameters: ``other_field``, ``other_value`` and - ``validator_list``, in that order. If ``other_field`` has a value of - ``other_value``, then the validators in ``validator_list`` are all run - against the current field. - -``RequiredIfOtherFieldGiven`` - Takes a field name of the current field is only required if the other - field has a value. - -``RequiredIfOtherFieldsGiven`` - Similar to ``RequiredIfOtherFieldGiven``, except that it takes a list of - field names and if any one of the supplied fields has a value provided, - the current field being validated is required. - -``RequiredIfOtherFieldNotGiven`` - Takes the name of the other field and this field is only required if the - other field has no value. - -``RequiredIfOtherFieldEquals`` and ``RequiredIfOtherFieldDoesNotEqual`` - Each of these validator classes takes a field name and a value (in that - order). If the given field does (or does not have, in the latter case) the - given value, then the current field being validated is required. - - An optional ``other_label`` argument can be passed which, if given, is used - in error messages instead of the value. This allows more user friendly error - messages if the value itself is not descriptive enough. - - Note that because validators are called before any ``do_html2python()`` - functions, the value being compared against is a string. So - ``RequiredIfOtherFieldEquals('choice', '1')`` is correct, whilst - ``RequiredIfOtherFieldEquals('choice', 1)`` will never result in the - equality test succeeding. - -``IsLessThanOtherField`` - Takes a field name and validates that the current field being validated - has a value that is less than (or equal to) the other field's value. - Again, comparisons are done using strings, so be cautious about using - this function to compare data that should be treated as another type. The - string "123" is less than the string "2", for example. If you don't want - string comparison here, you will need to write your own validator. - -``NumberIsInRange`` - Takes two boundary numbers, ``lower`` and ``upper``, and checks that the - field is greater than ``lower`` (if given) and less than ``upper`` (if - given). - - Both checks are inclusive. That is, ``NumberIsInRange(10, 20)`` will allow - values of both 10 and 20. This validator only checks numeric values - (e.g., float and integer values). - -``IsAPowerOf`` - Takes an integer argument and when called as a validator, checks that the - field being validated is a power of the integer. - -``IsValidDecimal`` - Takes a maximum number of digits and number of decimal places (in that - order) and validates whether the field is a decimal with no more than the - maximum number of digits and decimal places. - -``MatchesRegularExpression`` - Takes a regular expression (a string) as a parameter and validates the - field value against it. - -``AnyValidator`` - Takes a list of validators as a parameter. At validation time, if the - field successfully validates against any one of the validators, it passes - validation. The validators are tested in the order specified in the - original list. - -``URLMimeTypeCheck`` - Used to validate URL fields. Takes a list of MIME types (such as - ``text/plain``) at creation time. At validation time, it verifies that the - field is indeed a URL and then tries to retrieve the content at the URL. - Validation succeeds if the content could be retrieved and it has a content - type from the list used to create the validator. - -``RelaxNGCompact`` - Used to validate an XML document against a Relax NG compact schema. Takes a - file path to the location of the schema and an optional root element (which - is wrapped around the XML fragment before validation, if supplied). At - validation time, the XML fragment is validated against the schema using the - executable specified in the ``JING_PATH`` setting (see the :ref:`settings - <ref-settings>` document for more details). diff --git a/docs/obsolete/newforms-migration.txt b/docs/obsolete/newforms-migration.txt deleted file mode 100644 index da56b5704e..0000000000 --- a/docs/obsolete/newforms-migration.txt +++ /dev/null @@ -1,48 +0,0 @@ -.. _howto-newforms-migration: - -Migrating from "oldforms" to "newforms" -======================================= - -:mod:`django.newforms` is new in Django's 0.96 release, but, as it won't be new -forever. We plan to rename it to ``django.forms`` in next official release. The -current ``django.forms`` package will be available as ``django.oldforms`` until -Django 1.0, when we plan to remove it for good. - -If you're using "old" forms -- and if you started using Django after 0.96 you're -probably not -- you need to read this document and understand this migration -plan. - - * The old forms framework (the current ``django.forms``) has been copied to - ``django.oldforms``. Thus, you can start upgrading your code *now*, - rather than waiting for the future backwards-incompatible change, by - changing your import statements like this:: - - from django import forms # old - from django import oldforms as forms # new - - * In the next Django release, we will move the current ``django.newforms`` - to ``django.forms``. This will be a backwards-incompatible change, and - anybody who is still using the old version of ``django.forms`` at that - time will need to change their import statements, as described in the - previous bullet. - - * We will remove ``django.oldforms`` in Django 1.0. It will continue to be - available from older tags in our SVN repository, but it will not be - consider part of Django, and will not be supported.. - -With this in mind, we recommend you use the following import statement when -using ``django.newforms``:: - - from django import newforms as forms - -This way, your code can refer to the ``forms`` module, and when -``django.newforms`` is renamed to ``django.forms``, you'll only have to change -your ``import`` statements. - -If you prefer "``import *``" syntax, you can do the following:: - - from django.newforms import * - -This will import all fields, widgets, form classes and other various utilities -into your local namespace. Some people find this convenient; others find it -too messy. The choice is yours. |
