mirror of
https://github.com/encode/django-rest-framework.git
synced 2024-11-22 09:36:49 +03:00
Relational field support in browseable API.
Add slug relational fields. Add quickstart.
This commit is contained in:
parent
027c9079f6
commit
d327c5f531
19
djangorestframework.egg-info/PKG-INFO
Normal file
19
djangorestframework.egg-info/PKG-INFO
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
Metadata-Version: 1.0
|
||||||
|
Name: djangorestframework
|
||||||
|
Version: 2.0.0
|
||||||
|
Summary: A lightweight REST framework for Django.
|
||||||
|
Home-page: http://django-rest-framework.org
|
||||||
|
Author: Tom Christie
|
||||||
|
Author-email: tom@tomchristie.com
|
||||||
|
License: BSD
|
||||||
|
Download-URL: http://pypi.python.org/pypi/rest_framework/
|
||||||
|
Description: UNKNOWN
|
||||||
|
Platform: UNKNOWN
|
||||||
|
Classifier: Development Status :: 4 - Beta
|
||||||
|
Classifier: Environment :: Web Environment
|
||||||
|
Classifier: Framework :: Django
|
||||||
|
Classifier: Intended Audience :: Developers
|
||||||
|
Classifier: License :: OSI Approved :: BSD License
|
||||||
|
Classifier: Operating System :: OS Independent
|
||||||
|
Classifier: Programming Language :: Python
|
||||||
|
Classifier: Topic :: Internet :: WWW/HTTP
|
86
djangorestframework.egg-info/SOURCES.txt
Normal file
86
djangorestframework.egg-info/SOURCES.txt
Normal file
|
@ -0,0 +1,86 @@
|
||||||
|
MANIFEST.in
|
||||||
|
setup.py
|
||||||
|
djangorestframework.egg-info/PKG-INFO
|
||||||
|
djangorestframework.egg-info/SOURCES.txt
|
||||||
|
djangorestframework.egg-info/dependency_links.txt
|
||||||
|
djangorestframework.egg-info/top_level.txt
|
||||||
|
rest_framework/__init__.py
|
||||||
|
rest_framework/authentication.py
|
||||||
|
rest_framework/compat.py
|
||||||
|
rest_framework/decorators.py
|
||||||
|
rest_framework/exceptions.py
|
||||||
|
rest_framework/fields.py
|
||||||
|
rest_framework/generics.py
|
||||||
|
rest_framework/mixins.py
|
||||||
|
rest_framework/models.py
|
||||||
|
rest_framework/negotiation.py
|
||||||
|
rest_framework/pagination.py
|
||||||
|
rest_framework/parsers.py
|
||||||
|
rest_framework/permissions.py
|
||||||
|
rest_framework/renderers.py
|
||||||
|
rest_framework/request.py
|
||||||
|
rest_framework/response.py
|
||||||
|
rest_framework/reverse.py
|
||||||
|
rest_framework/serializers.py
|
||||||
|
rest_framework/settings.py
|
||||||
|
rest_framework/status.py
|
||||||
|
rest_framework/throttling.py
|
||||||
|
rest_framework/urlpatterns.py
|
||||||
|
rest_framework/urls.py
|
||||||
|
rest_framework/views.py
|
||||||
|
rest_framework/authtoken/__init__.py
|
||||||
|
rest_framework/authtoken/models.py
|
||||||
|
rest_framework/authtoken/views.py
|
||||||
|
rest_framework/authtoken/migrations/0001_initial.py
|
||||||
|
rest_framework/authtoken/migrations/__init__.py
|
||||||
|
rest_framework/runtests/__init__.py
|
||||||
|
rest_framework/runtests/runcoverage.py
|
||||||
|
rest_framework/runtests/runtests.py
|
||||||
|
rest_framework/runtests/settings.py
|
||||||
|
rest_framework/runtests/urls.py
|
||||||
|
rest_framework/static/rest_framework/css/bootstrap-tweaks.css
|
||||||
|
rest_framework/static/rest_framework/css/bootstrap.min.css
|
||||||
|
rest_framework/static/rest_framework/css/default.css
|
||||||
|
rest_framework/static/rest_framework/css/prettify.css
|
||||||
|
rest_framework/static/rest_framework/img/glyphicons-halflings-white.png
|
||||||
|
rest_framework/static/rest_framework/img/glyphicons-halflings.png
|
||||||
|
rest_framework/static/rest_framework/img/grid.png
|
||||||
|
rest_framework/static/rest_framework/js/bootstrap.min.js
|
||||||
|
rest_framework/static/rest_framework/js/default.js
|
||||||
|
rest_framework/static/rest_framework/js/jquery-1.8.1-min.js
|
||||||
|
rest_framework/static/rest_framework/js/prettify-min.js
|
||||||
|
rest_framework/templates/rest_framework/api.html
|
||||||
|
rest_framework/templates/rest_framework/base.html
|
||||||
|
rest_framework/templates/rest_framework/login.html
|
||||||
|
rest_framework/templatetags/__init__.py
|
||||||
|
rest_framework/templatetags/rest_framework.py
|
||||||
|
rest_framework/tests/__init__.py
|
||||||
|
rest_framework/tests/authentication.py
|
||||||
|
rest_framework/tests/breadcrumbs.py
|
||||||
|
rest_framework/tests/decorators.py
|
||||||
|
rest_framework/tests/description.py
|
||||||
|
rest_framework/tests/files.py
|
||||||
|
rest_framework/tests/genericrelations.py
|
||||||
|
rest_framework/tests/generics.py
|
||||||
|
rest_framework/tests/htmlrenderer.py
|
||||||
|
rest_framework/tests/hyperlinkedserializers.py
|
||||||
|
rest_framework/tests/models.py
|
||||||
|
rest_framework/tests/modelviews.py
|
||||||
|
rest_framework/tests/negotiation.py
|
||||||
|
rest_framework/tests/pagination.py
|
||||||
|
rest_framework/tests/parsers.py
|
||||||
|
rest_framework/tests/renderers.py
|
||||||
|
rest_framework/tests/request.py
|
||||||
|
rest_framework/tests/response.py
|
||||||
|
rest_framework/tests/reverse.py
|
||||||
|
rest_framework/tests/serializer.py
|
||||||
|
rest_framework/tests/status.py
|
||||||
|
rest_framework/tests/testcases.py
|
||||||
|
rest_framework/tests/tests.py
|
||||||
|
rest_framework/tests/throttling.py
|
||||||
|
rest_framework/tests/validators.py
|
||||||
|
rest_framework/tests/views.py
|
||||||
|
rest_framework/utils/__init__.py
|
||||||
|
rest_framework/utils/breadcrumbs.py
|
||||||
|
rest_framework/utils/encoders.py
|
||||||
|
rest_framework/utils/mediatypes.py
|
1
djangorestframework.egg-info/dependency_links.txt
Normal file
1
djangorestframework.egg-info/dependency_links.txt
Normal file
|
@ -0,0 +1 @@
|
||||||
|
|
7
djangorestframework.egg-info/top_level.txt
Normal file
7
djangorestframework.egg-info/top_level.txt
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
rest_framework/authtoken
|
||||||
|
rest_framework/utils
|
||||||
|
rest_framework/tests
|
||||||
|
rest_framework/runtests
|
||||||
|
rest_framework/templatetags
|
||||||
|
rest_framework
|
||||||
|
rest_framework/authtoken/migrations
|
|
@ -66,11 +66,9 @@ If you're intending to use the browseable API you'll want to add REST framework'
|
||||||
|
|
||||||
Note that the URL path can be whatever you want, but you must include `rest_framework.urls` with the `rest_framework` namespace.
|
Note that the URL path can be whatever you want, but you must include `rest_framework.urls` with the `rest_framework` namespace.
|
||||||
|
|
||||||
<!--
|
|
||||||
## Quickstart
|
## Quickstart
|
||||||
|
|
||||||
Can't wait to get started? The [quickstart guide][quickstart] is the fastest way to get up and running with REST framework.
|
Can't wait to get started? The [quickstart guide][quickstart] is the fastest way to get up and running with REST framework.
|
||||||
-->
|
|
||||||
|
|
||||||
## Tutorial
|
## Tutorial
|
||||||
|
|
||||||
|
|
|
@ -53,7 +53,7 @@
|
||||||
<li class="dropdown">
|
<li class="dropdown">
|
||||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown">Tutorial <b class="caret"></b></a>
|
<a href="#" class="dropdown-toggle" data-toggle="dropdown">Tutorial <b class="caret"></b></a>
|
||||||
<ul class="dropdown-menu">
|
<ul class="dropdown-menu">
|
||||||
<!--<li><a href="{{ base_url }}/tutorial/quickstart{{ suffix }}">Quickstart</a></li>-->
|
<li><a href="{{ base_url }}/tutorial/quickstart{{ suffix }}">Quickstart</a></li>
|
||||||
<li><a href="{{ base_url }}/tutorial/1-serialization{{ suffix }}">1 - Serialization</a></li>
|
<li><a href="{{ base_url }}/tutorial/1-serialization{{ suffix }}">1 - Serialization</a></li>
|
||||||
<li><a href="{{ base_url }}/tutorial/2-requests-and-responses{{ suffix }}">2 - Requests and responses</a></li>
|
<li><a href="{{ base_url }}/tutorial/2-requests-and-responses{{ suffix }}">2 - Requests and responses</a></li>
|
||||||
<li><a href="{{ base_url }}/tutorial/3-class-based-views{{ suffix }}">3 - Class based views</a></li>
|
<li><a href="{{ base_url }}/tutorial/3-class-based-views{{ suffix }}">3 - Class based views</a></li>
|
||||||
|
|
|
@ -19,12 +19,19 @@ First up we're going to define some serializers in `quickstart/serializers.py` t
|
||||||
|
|
||||||
|
|
||||||
class GroupSerializer(serializers.HyperlinkedModelSerializer):
|
class GroupSerializer(serializers.HyperlinkedModelSerializer):
|
||||||
|
permissions = serializers.ManySlugRelatedField(
|
||||||
|
slug_field='codename',
|
||||||
|
queryset=Permission.objects.all()
|
||||||
|
)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Group
|
model = Group
|
||||||
fields = ('url', 'name', 'permissions')
|
fields = ('url', 'name', 'permissions')
|
||||||
|
|
||||||
Notice that we're using hyperlinked relations in this case, with `HyperlinkedModelSerializer`. You can also use primary key and various other relationships, but hyperlinking is good RESTful design.
|
Notice that we're using hyperlinked relations in this case, with `HyperlinkedModelSerializer`. You can also use primary key and various other relationships, but hyperlinking is good RESTful design.
|
||||||
|
|
||||||
|
We've also overridden the `permission` field on the `GroupSerializer`. In this case we don't want to use a hyperlinked representation, but instead use the list of permission codenames associated with the group, so we've used a `ManySlugRelatedField`, using the `codename` field for the representation.
|
||||||
|
|
||||||
## Views
|
## Views
|
||||||
|
|
||||||
Right, we'd better write some views then. Open `quickstart/views.py` and get typing.
|
Right, we'd better write some views then. Open `quickstart/views.py` and get typing.
|
||||||
|
@ -152,7 +159,7 @@ We can now access our API, both from the command-line, using tools like `curl`..
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"email": "tom@example.com",
|
"email": "tom@example.com",
|
||||||
"groups": [],
|
"groups": [ ],
|
||||||
"url": "http://127.0.0.1:8000/users/2/",
|
"url": "http://127.0.0.1:8000/users/2/",
|
||||||
"username": "tom"
|
"username": "tom"
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@ from django.core.exceptions import ObjectDoesNotExist, ValidationError
|
||||||
from django.core.urlresolvers import resolve, get_script_prefix
|
from django.core.urlresolvers import resolve, get_script_prefix
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.forms import widgets
|
from django.forms import widgets
|
||||||
|
from django.forms.models import ModelChoiceIterator
|
||||||
from django.utils.encoding import is_protected_type, smart_unicode
|
from django.utils.encoding import is_protected_type, smart_unicode
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
from rest_framework.reverse import reverse
|
from rest_framework.reverse import reverse
|
||||||
|
@ -232,11 +233,72 @@ class ModelField(WritableField):
|
||||||
class RelatedField(WritableField):
|
class RelatedField(WritableField):
|
||||||
"""
|
"""
|
||||||
Base class for related model fields.
|
Base class for related model fields.
|
||||||
|
|
||||||
|
If not overridden, this represents a to-one relatinship, using the unicode
|
||||||
|
representation of the target.
|
||||||
"""
|
"""
|
||||||
|
widget = widgets.Select
|
||||||
|
cache_choices = False
|
||||||
|
empty_label = None
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
self.queryset = kwargs.pop('queryset', None)
|
self.queryset = kwargs.pop('queryset', None)
|
||||||
super(RelatedField, self).__init__(*args, **kwargs)
|
super(RelatedField, self).__init__(*args, **kwargs)
|
||||||
|
|
||||||
|
### We need this stuff to make form choices work...
|
||||||
|
|
||||||
|
# def __deepcopy__(self, memo):
|
||||||
|
# result = super(RelatedField, self).__deepcopy__(memo)
|
||||||
|
# result.queryset = result.queryset
|
||||||
|
# return result
|
||||||
|
|
||||||
|
def prepare_value(self, obj):
|
||||||
|
return self.to_native(obj)
|
||||||
|
|
||||||
|
def label_from_instance(self, obj):
|
||||||
|
"""
|
||||||
|
Return a readable representation for use with eg. select widgets.
|
||||||
|
"""
|
||||||
|
desc = smart_unicode(obj)
|
||||||
|
ident = self.to_native(obj)
|
||||||
|
if desc == ident:
|
||||||
|
return desc
|
||||||
|
return "%s - %s" % (desc, ident)
|
||||||
|
|
||||||
|
def _get_queryset(self):
|
||||||
|
return self._queryset
|
||||||
|
|
||||||
|
def _set_queryset(self, queryset):
|
||||||
|
self._queryset = queryset
|
||||||
|
self.widget.choices = self.choices
|
||||||
|
|
||||||
|
queryset = property(_get_queryset, _set_queryset)
|
||||||
|
|
||||||
|
def _get_choices(self):
|
||||||
|
# If self._choices is set, then somebody must have manually set
|
||||||
|
# the property self.choices. In this case, just return self._choices.
|
||||||
|
if hasattr(self, '_choices'):
|
||||||
|
return self._choices
|
||||||
|
|
||||||
|
# Otherwise, execute the QuerySet in self.queryset to determine the
|
||||||
|
# choices dynamically. Return a fresh ModelChoiceIterator that has not been
|
||||||
|
# consumed. Note that we're instantiating a new ModelChoiceIterator *each*
|
||||||
|
# time _get_choices() is called (and, thus, each time self.choices is
|
||||||
|
# accessed) so that we can ensure the QuerySet has not been consumed. This
|
||||||
|
# construct might look complicated but it allows for lazy evaluation of
|
||||||
|
# the queryset.
|
||||||
|
return ModelChoiceIterator(self)
|
||||||
|
|
||||||
|
def _set_choices(self, value):
|
||||||
|
# Setting choices also sets the choices on the widget.
|
||||||
|
# choices can be any iterable, but we call list() on it because
|
||||||
|
# it will be consumed more than once.
|
||||||
|
self._choices = self.widget.choices = list(value)
|
||||||
|
|
||||||
|
choices = property(_get_choices, _set_choices)
|
||||||
|
|
||||||
|
### Regular serializier stuff...
|
||||||
|
|
||||||
def field_to_native(self, obj, field_name):
|
def field_to_native(self, obj, field_name):
|
||||||
value = getattr(obj, self.source or field_name)
|
value = getattr(obj, self.source or field_name)
|
||||||
return self.to_native(value)
|
return self.to_native(value)
|
||||||
|
@ -253,6 +315,8 @@ class ManyRelatedMixin(object):
|
||||||
"""
|
"""
|
||||||
Mixin to convert a related field to a many related field.
|
Mixin to convert a related field to a many related field.
|
||||||
"""
|
"""
|
||||||
|
widget = widgets.SelectMultiple
|
||||||
|
|
||||||
def field_to_native(self, obj, field_name):
|
def field_to_native(self, obj, field_name):
|
||||||
value = getattr(obj, self.source or field_name)
|
value = getattr(obj, self.source or field_name)
|
||||||
return [self.to_native(item) for item in value.all()]
|
return [self.to_native(item) for item in value.all()]
|
||||||
|
@ -276,6 +340,9 @@ class ManyRelatedMixin(object):
|
||||||
class ManyRelatedField(ManyRelatedMixin, RelatedField):
|
class ManyRelatedField(ManyRelatedMixin, RelatedField):
|
||||||
"""
|
"""
|
||||||
Base class for related model managers.
|
Base class for related model managers.
|
||||||
|
|
||||||
|
If not overridden, this represents a to-many relatinship, using the unicode
|
||||||
|
representations of the target, and is read-only.
|
||||||
"""
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@ -284,7 +351,7 @@ class ManyRelatedField(ManyRelatedMixin, RelatedField):
|
||||||
|
|
||||||
class PrimaryKeyRelatedField(RelatedField):
|
class PrimaryKeyRelatedField(RelatedField):
|
||||||
"""
|
"""
|
||||||
Serializes a related field or related object to a pk value.
|
Represents a to-one relationship as a pk value.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def to_native(self, pk):
|
def to_native(self, pk):
|
||||||
|
@ -313,7 +380,7 @@ class PrimaryKeyRelatedField(RelatedField):
|
||||||
|
|
||||||
class ManyPrimaryKeyRelatedField(ManyRelatedField):
|
class ManyPrimaryKeyRelatedField(ManyRelatedField):
|
||||||
"""
|
"""
|
||||||
Serializes a to-many related field or related manager to a pk value.
|
Represents a to-many relationship as a pk value.
|
||||||
"""
|
"""
|
||||||
def to_native(self, pk):
|
def to_native(self, pk):
|
||||||
return pk
|
return pk
|
||||||
|
@ -329,10 +396,36 @@ class ManyPrimaryKeyRelatedField(ManyRelatedField):
|
||||||
# Forward relationship
|
# Forward relationship
|
||||||
return [self.to_native(item.pk) for item in queryset.all()]
|
return [self.to_native(item.pk) for item in queryset.all()]
|
||||||
|
|
||||||
|
### Slug relationships
|
||||||
|
|
||||||
|
|
||||||
|
class SlugRelatedField(RelatedField):
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
self.slug_field = kwargs.pop('slug_field', None)
|
||||||
|
assert self.slug_field, 'slug_field is required'
|
||||||
|
super(SlugRelatedField, self).__init__(*args, **kwargs)
|
||||||
|
|
||||||
|
def to_native(self, obj):
|
||||||
|
return getattr(obj, self.slug_field)
|
||||||
|
|
||||||
|
def from_native(self, data):
|
||||||
|
try:
|
||||||
|
return self.queryset.get(**{self.slug_field: data})
|
||||||
|
except ObjectDoesNotExist:
|
||||||
|
raise ValidationError('Object with %s=%s does not exist.' %
|
||||||
|
(self.slug_field, unicode(data)))
|
||||||
|
|
||||||
|
|
||||||
|
class ManySlugRelatedField(ManyRelatedMixin, SlugRelatedField):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
### Hyperlinked relationships
|
### Hyperlinked relationships
|
||||||
|
|
||||||
class HyperlinkedRelatedField(RelatedField):
|
class HyperlinkedRelatedField(RelatedField):
|
||||||
|
"""
|
||||||
|
Represents a to-one relationship, using hyperlinking.
|
||||||
|
"""
|
||||||
pk_url_kwarg = 'pk'
|
pk_url_kwarg = 'pk'
|
||||||
slug_url_kwarg = 'slug'
|
slug_url_kwarg = 'slug'
|
||||||
slug_field = 'slug'
|
slug_field = 'slug'
|
||||||
|
@ -417,16 +510,20 @@ class HyperlinkedRelatedField(RelatedField):
|
||||||
|
|
||||||
|
|
||||||
class ManyHyperlinkedRelatedField(ManyRelatedMixin, HyperlinkedRelatedField):
|
class ManyHyperlinkedRelatedField(ManyRelatedMixin, HyperlinkedRelatedField):
|
||||||
|
"""
|
||||||
|
Represents a to-many relationship, using hyperlinking.
|
||||||
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class HyperlinkedIdentityField(Field):
|
class HyperlinkedIdentityField(Field):
|
||||||
"""
|
"""
|
||||||
A field that represents the model's identity using a hyperlink.
|
Represents the instance, or a property on the instance, using hyperlinking.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
# TODO: Make this mandatory, and have the HyperlinkedModelSerializer
|
# TODO: Make view_name mandatory, and have the
|
||||||
# set it on-the-fly
|
# HyperlinkedModelSerializer set it on-the-fly
|
||||||
self.view_name = kwargs.pop('view_name', None)
|
self.view_name = kwargs.pop('view_name', None)
|
||||||
self.format = kwargs.pop('format', None)
|
self.format = kwargs.pop('format', None)
|
||||||
super(HyperlinkedIdentityField, self).__init__(*args, **kwargs)
|
super(HyperlinkedIdentityField, self).__init__(*args, **kwargs)
|
||||||
|
|
|
@ -282,10 +282,12 @@ class BrowsableAPIRenderer(BaseRenderer):
|
||||||
serializers.EmailField: forms.EmailField,
|
serializers.EmailField: forms.EmailField,
|
||||||
serializers.CharField: forms.CharField,
|
serializers.CharField: forms.CharField,
|
||||||
serializers.BooleanField: forms.BooleanField,
|
serializers.BooleanField: forms.BooleanField,
|
||||||
serializers.PrimaryKeyRelatedField: forms.ModelChoiceField,
|
serializers.PrimaryKeyRelatedField: forms.ChoiceField,
|
||||||
serializers.ManyPrimaryKeyRelatedField: forms.ModelMultipleChoiceField,
|
serializers.ManyPrimaryKeyRelatedField: forms.MultipleChoiceField,
|
||||||
serializers.HyperlinkedRelatedField: forms.ModelChoiceField,
|
serializers.SlugRelatedField: forms.ChoiceField,
|
||||||
serializers.ManyHyperlinkedRelatedField: forms.ModelMultipleChoiceField
|
serializers.ManySlugRelatedField: forms.MultipleChoiceField,
|
||||||
|
serializers.HyperlinkedRelatedField: forms.ChoiceField,
|
||||||
|
serializers.ManyHyperlinkedRelatedField: forms.MultipleChoiceField
|
||||||
}
|
}
|
||||||
|
|
||||||
fields = {}
|
fields = {}
|
||||||
|
@ -296,19 +298,14 @@ class BrowsableAPIRenderer(BaseRenderer):
|
||||||
kwargs = {}
|
kwargs = {}
|
||||||
kwargs['required'] = v.required
|
kwargs['required'] = v.required
|
||||||
|
|
||||||
if getattr(v, 'queryset', None):
|
#if getattr(v, 'queryset', None):
|
||||||
kwargs['queryset'] = v.queryset
|
# kwargs['queryset'] = v.queryset
|
||||||
|
|
||||||
|
if getattr(v, 'choices', None) is not None:
|
||||||
|
kwargs['choices'] = v.choices
|
||||||
|
|
||||||
if getattr(v, 'widget', None):
|
if getattr(v, 'widget', None):
|
||||||
widget = copy.deepcopy(v.widget)
|
widget = copy.deepcopy(v.widget)
|
||||||
# If choices have friendly readable names,
|
|
||||||
# then add in the identities too
|
|
||||||
if getattr(widget, 'choices', None):
|
|
||||||
choices = widget.choices
|
|
||||||
if any([ident != desc for (ident, desc) in choices]):
|
|
||||||
choices = [(ident, "%s (%s)" % (desc, ident))
|
|
||||||
for (ident, desc) in choices]
|
|
||||||
widget.choices = choices
|
|
||||||
kwargs['widget'] = widget
|
kwargs['widget'] = widget
|
||||||
|
|
||||||
if getattr(v, 'default', None) is not None:
|
if getattr(v, 'default', None) is not None:
|
||||||
|
|
|
@ -36,6 +36,13 @@ ul.breadcrumb {
|
||||||
margin: 58px 0 0 0;
|
margin: 58px 0 0 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
form select, form input {
|
||||||
|
width: 90%;
|
||||||
|
}
|
||||||
|
|
||||||
|
form select[multiple] {
|
||||||
|
height: 150px;
|
||||||
|
}
|
||||||
/* To allow tooltips to work on disabled elements */
|
/* To allow tooltips to work on disabled elements */
|
||||||
.disabled-tooltip-shield {
|
.disabled-tooltip-shield {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
|
|
@ -134,7 +134,7 @@
|
||||||
<div class="control-group {% if field.errors %}error{% endif %}">
|
<div class="control-group {% if field.errors %}error{% endif %}">
|
||||||
{{ field.label_tag|add_class:"control-label" }}
|
{{ field.label_tag|add_class:"control-label" }}
|
||||||
<div class="controls">
|
<div class="controls">
|
||||||
{{ field|add_class:"input-xlarge" }}
|
{{ field }}
|
||||||
<span class="help-inline">{{ field.help_text }}</span>
|
<span class="help-inline">{{ field.help_text }}</span>
|
||||||
{{ field.errors|add_class:"help-block" }}
|
{{ field.errors|add_class:"help-block" }}
|
||||||
</div>
|
</div>
|
||||||
|
@ -159,7 +159,7 @@
|
||||||
<div class="control-group {% if field.errors %}error{% endif %}">
|
<div class="control-group {% if field.errors %}error{% endif %}">
|
||||||
{{ field.label_tag|add_class:"control-label" }}
|
{{ field.label_tag|add_class:"control-label" }}
|
||||||
<div class="controls">
|
<div class="controls">
|
||||||
{{ field|add_class:"input-xlarge" }}
|
{{ field }}
|
||||||
<span class='help-inline'>{{ field.help_text }}</span>
|
<span class='help-inline'>{{ field.help_text }}</span>
|
||||||
{{ field.errors|add_class:"help-block" }}
|
{{ field.errors|add_class:"help-block" }}
|
||||||
</div>
|
</div>
|
||||||
|
|
Loading…
Reference in New Issue
Block a user