diff --git a/django/contrib/auth/forms.py b/django/contrib/auth/forms.py
--- a/django/contrib/auth/forms.py
+++ b/django/contrib/auth/forms.py
@@ -20,7 +20,7 @@
 
     class Meta:
         model = User
-        fields = ("username",)
+        fields = ("username", "password1", "password2")
 
     def clean_username(self):
         username = self.cleaned_data["username"]
diff --git a/django/forms/forms.py b/django/forms/forms.py
--- a/django/forms/forms.py
+++ b/django/forms/forms.py
@@ -23,43 +23,71 @@
         return u'' 
     return name.replace('_', ' ').capitalize() 
 
-def get_declared_fields(bases, attrs, with_base_fields=True):
+def get_declared_fields(attrs):
     """
-    Create a list of form field instances from the passed in 'attrs', plus any
-    similar fields on the base classes (in 'bases'). This is used by both the
-    Form and ModelForm metclasses.
-
-    If 'with_base_fields' is True, all fields from the bases are used.
-    Otherwise, only fields in the 'declared_fields' attribute on the bases are
-    used. The distinction is useful in ModelForm subclassing.
-    Also integrates any additional media definitions
+    Create a list of form field instances from the passed in 'attrs'. This is
+    used by both the Form and ModelForm metaclasses.
     """
-    fields = [(field_name, attrs.pop(field_name)) for field_name, obj in attrs.items() if isinstance(obj, Field)]
+    fields = [(field_name, attrs.pop(field_name)) for field_name, obj
+        in attrs.items() if isinstance(obj, Field)]
     fields.sort(lambda x, y: cmp(x[1].creation_counter, y[1].creation_counter))
-
-    # If this class is subclassing another Form, add that Form's fields.
-    # Note that we loop over the bases in *reverse*. This is necessary in
-    # order to preserve the correct order of fields.
-    if with_base_fields:
-        for base in bases[::-1]:
-            if hasattr(base, 'base_fields'):
-                fields = base.base_fields.items() + fields
-    else:
-        for base in bases[::-1]:
-            if hasattr(base, 'declared_fields'):
-                fields = base.declared_fields.items() + fields
-
     return SortedDict(fields)
 
-class DeclarativeFieldsMetaclass(type):
+def get_base_fields(new_class):
+    """
+    Create a list of form field instances declared on the form and its base
+    classes. This is used by both the Form and ModelForm metaclasses.
+
+    """
+    # Note that we loop over the bases in *reverse*. This is necessary in order
+    # to preserve the correct order of fields.
+    fields = SortedDict()
+    for base in reversed(new_class.mro()):
+        if hasattr(base, 'declared_fields'):
+            fields.update(base.declared_fields)
+    return fields
+
+def select_fields(fields, opts):
+    """
+    Select some fields based on options.  This is used by both the Form and
+    ModelForm metaclasses.
+
+    Option ``fields`` is an optional list of field names. If provided, only
+    the named fields will be included in the returned fields and fields are
+    sorted by it.
+
+    Option ``exclude`` is an optional list of field names. If provided,
+    the named fields will be excluded from the returned fields, even if they
+    are listed in the ``fields`` argument.
+    """
+    selected_fields = SortedDict()
+    for field_name, field in fields.items():
+        if opts.fields and not field_name in opts.fields:
+            continue
+        if opts.exclude and field_name in opts.exclude:
+            continue
+        selected_fields[field_name] = field
+    if opts.fields:
+        selected_fields = SortedDict((field_name, selected_fields.get(field_name))
+            for field_name in opts.fields if field_name in selected_fields)
+    return selected_fields
+
+class FormOptions(object):
+    def __init__(self, options=None):
+        self.fields = getattr(options, 'fields', None)
+        self.exclude = getattr(options, 'exclude', None)
+
+class FormMetaclass(type):
     """
     Metaclass that converts Field attributes to a dictionary called
-    'base_fields', taking into account parent class 'base_fields' as well.
+    'base_fields', taking into account parent class fields as well.
+    Also integrates any additional media definitions.
     """
     def __new__(cls, name, bases, attrs):
-        attrs['base_fields'] = get_declared_fields(bases, attrs)
-        new_class = super(DeclarativeFieldsMetaclass,
-                     cls).__new__(cls, name, bases, attrs)
+        attrs['declared_fields'] = get_declared_fields(attrs)
+        new_class = super(FormMetaclass, cls).__new__(cls, name, bases, attrs)
+        opts = new_class._meta = FormOptions(getattr(new_class, 'Meta', None))
+        new_class.base_fields = select_fields(get_base_fields(new_class), opts)
         if 'media' not in attrs:
             new_class.media = media_property(new_class)
         return new_class
@@ -384,7 +412,7 @@
     # fancy metaclass stuff purely for the semantic sugar -- it allows one
     # to define a form using declarative syntax.
     # BaseForm itself has no way of designating self.fields.
-    __metaclass__ = DeclarativeFieldsMetaclass
+    __metaclass__ = FormMetaclass
 
 class BoundField(StrAndUnicode):
     "A Field plus data"
diff --git a/django/forms/models.py b/django/forms/models.py
--- a/django/forms/models.py
+++ b/django/forms/models.py
@@ -12,7 +12,7 @@
 from django.core.exceptions import ValidationError, NON_FIELD_ERRORS
 from django.core.validators import EMPTY_VALUES
 from util import ErrorList
-from forms import BaseForm, get_declared_fields
+from forms import BaseForm, get_declared_fields, get_base_fields, select_fields
 from fields import Field, ChoiceField
 from widgets import SelectMultiple, HiddenInput, MultipleHiddenInput
 from widgets import media_property
@@ -195,36 +195,25 @@
         self.exclude = getattr(options, 'exclude', None)
         self.widgets = getattr(options, 'widgets', None)
 
-
 class ModelFormMetaclass(type):
     def __new__(cls, name, bases, attrs):
         formfield_callback = attrs.pop('formfield_callback',
                 lambda f, **kwargs: f.formfield(**kwargs))
-        try:
-            parents = [b for b in bases if issubclass(b, ModelForm)]
-        except NameError:
-            # We are defining ModelForm itself.
-            parents = None
-        declared_fields = get_declared_fields(bases, attrs, False)
-        new_class = super(ModelFormMetaclass, cls).__new__(cls, name, bases,
-                attrs)
-        if not parents:
-            return new_class
-
-        if 'media' not in attrs:
-            new_class.media = media_property(new_class)
+        attrs['declared_fields'] = get_declared_fields(attrs)
+        new_class = super(ModelFormMetaclass, cls).__new__(cls, name, bases, attrs)
         opts = new_class._meta = ModelFormOptions(getattr(new_class, 'Meta', None))
         if opts.model:
             # If a model is defined, extract form fields from it.
-            fields = fields_for_model(opts.model, opts.fields,
-                                      opts.exclude, opts.widgets, formfield_callback)
+            fields = fields_for_model(opts.model, widgets=opts.widgets,
+                formfield_callback=formfield_callback)
             # Override default model fields with any custom declared ones
             # (plus, include all the other declared fields).
-            fields.update(declared_fields)
+            fields.update(get_base_fields(new_class))
         else:
-            fields = declared_fields
-        new_class.declared_fields = declared_fields
-        new_class.base_fields = fields
+            fields = get_base_fields(new_class)
+        new_class.base_fields = select_fields(fields, opts)
+        if 'media' not in attrs:
+            new_class.media = media_property(new_class)
         return new_class
 
 class BaseModelForm(BaseForm):
diff --git a/tests/regressiontests/forms/forms.py b/tests/regressiontests/forms/forms.py
--- a/tests/regressiontests/forms/forms.py
+++ b/tests/regressiontests/forms/forms.py
@@ -928,6 +928,44 @@
 <tr><th>Field13:</th><td><input type="text" name="field13" /></td></tr>
 <tr><th>Field14:</th><td><input type="text" name="field14" /></td></tr>
 
+It is possible to select some fields and reorder them.
+>>> class OrderedTestForm(TestForm):
+...    class Meta:
+...        fields = ('field4', 'field2', 'field11', 'field8')
+>>> p = OrderedTestForm(auto_id=False)
+>>> print p
+<tr><th>Field4:</th><td><input type="text" name="field4" /></td></tr>
+<tr><th>Field2:</th><td><input type="text" name="field2" /></td></tr>
+<tr><th>Field11:</th><td><input type="text" name="field11" /></td></tr>
+<tr><th>Field8:</th><td><input type="text" name="field8" /></td></tr>
+
+Or to exlude some fields.
+>>> class ExcludingTestForm(TestForm):
+...    class Meta:
+...        exclude = ('field14', 'field3', 'field5', 'field8', 'field1')
+>>> p = ExcludingTestForm(auto_id=False)
+>>> print p
+<tr><th>Field2:</th><td><input type="text" name="field2" /></td></tr>
+<tr><th>Field4:</th><td><input type="text" name="field4" /></td></tr>
+<tr><th>Field6:</th><td><input type="text" name="field6" /></td></tr>
+<tr><th>Field7:</th><td><input type="text" name="field7" /></td></tr>
+<tr><th>Field9:</th><td><input type="text" name="field9" /></td></tr>
+<tr><th>Field10:</th><td><input type="text" name="field10" /></td></tr>
+<tr><th>Field11:</th><td><input type="text" name="field11" /></td></tr>
+<tr><th>Field12:</th><td><input type="text" name="field12" /></td></tr>
+<tr><th>Field13:</th><td><input type="text" name="field13" /></td></tr>
+
+Or to use fields and exlude at once.
+>>> class CombinedTestForm(TestForm):
+...    class Meta:
+...        fields = ('field4', 'field2', 'field11', 'field8')
+...        exclude = ('field14', 'field3', 'field5', 'field8', 'field1')
+>>> p = CombinedTestForm(auto_id=False)
+>>> print p
+<tr><th>Field4:</th><td><input type="text" name="field4" /></td></tr>
+<tr><th>Field2:</th><td><input type="text" name="field2" /></td></tr>
+<tr><th>Field11:</th><td><input type="text" name="field11" /></td></tr>
+
 Some Field classes have an effect on the HTML attributes of their associated
 Widget. If you set max_length in a CharField and its associated widget is
 either a TextInput or PasswordInput, then the widget's rendered HTML will
@@ -1314,15 +1352,15 @@
 <li>Birthday: <input type="text" name="birthday" /></li>
 <li>Instrument: <input type="text" name="instrument" /></li>
 
-Yes, you can subclass multiple forms. The fields are added in the order in
-which the parent classes are listed.
+Yes, you can subclass multiple forms. The fields are added in the order given
+by the method resolution order.
 >>> class Person(Form):
 ...     first_name = CharField()
 ...     last_name = CharField()
 ...     birthday = DateField()
 >>> class Instrument(Form):
 ...     instrument = CharField()
->>> class Beatle(Person, Instrument):
+>>> class Beatle(Instrument, Person):
 ...     haircut_type = CharField()
 >>> b = Beatle(auto_id=False)
 >>> print b.as_ul()
@@ -1332,6 +1370,39 @@
 <li>Instrument: <input type="text" name="instrument" /></li>
 <li>Haircut type: <input type="text" name="haircut_type" /></li>
 
+You can use also more complex inheritence.
+>>> class FormA(Form):
+...    field_a = CharField()
+>>> class FormB(Form):
+...    field_b = CharField()
+>>> class FormC(Form):
+...    field_c = CharField()
+>>> class FormD(FormB, FormC):
+...    field_d = CharField()
+>>> class FormE(FormC, FormA):
+...    field_e = CharField()
+>>> class FormF(FormD, FormE):
+...    field_f = CharField()
+>>> print FormF(auto_id=False).as_ul()
+<li>Field a: <input type="text" name="field_a" /></li>
+<li>Field c: <input type="text" name="field_c" /></li>
+<li>Field e: <input type="text" name="field_e" /></li>
+<li>Field b: <input type="text" name="field_b" /></li>
+<li>Field d: <input type="text" name="field_d" /></li>
+<li>Field f: <input type="text" name="field_f" /></li>
+
+But you can reorder fields by meta attributes.
+>>> class FormG(FormF):
+...    field_g = CharField()
+...    class Meta:
+...        fields = ('field_c', 'field_e', 'field_a', 'field_b', 'field_g')
+...        exclude = ('field_b', 'field_d')
+>>> print FormG(auto_id=False).as_ul()
+<li>Field c: <input type="text" name="field_c" /></li>
+<li>Field e: <input type="text" name="field_e" /></li>
+<li>Field a: <input type="text" name="field_a" /></li>
+<li>Field g: <input type="text" name="field_g" /></li>
+
 # Forms with prefixes #########################################################
 
 Sometimes it's necessary to have multiple forms display on the same HTML page,
diff --git a/tests/regressiontests/forms/models.py b/tests/regressiontests/forms/models.py
--- a/tests/regressiontests/forms/models.py
+++ b/tests/regressiontests/forms/models.py
@@ -145,7 +145,9 @@
 >>> f.is_valid()
 True
 >>> f.cleaned_data['name']
-u'Hello'
+Traceback (most recent call last):
+...
+KeyError: 'name'
 >>> obj = f.save()
 >>> obj.name
 u'class default value'
