mirror of
https://github.com/django/django.git
synced 2025-07-04 09:49:12 +00:00
boulder-oracle-sprint: Merged to trunk [4276]
git-svn-id: http://code.djangoproject.com/svn/django/branches/boulder-oracle-sprint@4279 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
499bfc1f4a
commit
92b7851424
3
AUTHORS
3
AUTHORS
@ -78,6 +78,7 @@ answer newbie questions, and generally made Django that much better:
|
||||
Clint Ecker
|
||||
Enrico <rico.bl@gmail.com>
|
||||
favo@exoweb.net
|
||||
Eric Floehr <eric@intellovations.com>
|
||||
gandalf@owca.info
|
||||
Baishampayan Ghose
|
||||
martin.glueck@gmail.com
|
||||
@ -127,6 +128,7 @@ answer newbie questions, and generally made Django that much better:
|
||||
mmarshall
|
||||
Eric Moritz <http://eric.themoritzfamily.com/>
|
||||
Robin Munn <http://www.geekforgod.com/>
|
||||
Robert Myers <myer0052@gmail.com>
|
||||
Nebojša Dorđević
|
||||
Fraser Nevett <mail@nevett.org>
|
||||
Sam Newman <http://www.magpiebrain.com/>
|
||||
@ -151,6 +153,7 @@ answer newbie questions, and generally made Django that much better:
|
||||
serbaut@gmail.com
|
||||
Pete Shinners <pete@shinners.org>
|
||||
SmileyChris <smileychris@gmail.com>
|
||||
smurf@smurf.noris.de
|
||||
sopel
|
||||
Thomas Steinacher <tom@eggdrop.ch>
|
||||
nowell strite
|
||||
|
@ -1,3 +1,5 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
"""
|
||||
Daily cleanup job.
|
||||
|
||||
|
@ -0,0 +1,52 @@
|
||||
{% extends "admin/base_site.html" %}
|
||||
{% load i18n admin_modify adminmedia %}
|
||||
{% block extrahead %}{{ block.super }}
|
||||
<script type="text/javascript" src="../../../../jsi18n/"></script>
|
||||
{% for js in javascript_imports %}{% include_admin_script js %}{% endfor %}
|
||||
{% endblock %}
|
||||
{% block stylesheet %}{% admin_media_prefix %}css/forms.css{% endblock %}
|
||||
{% block bodyclass %}{{ opts.app_label }}-{{ opts.object_name.lower }} change-form{% endblock %}
|
||||
{% block userlinks %}<a href="../../../../doc/">{% trans 'Documentation' %}</a> / <a href="../../../password_change/">{% trans 'Change password' %}</a> / <a href="../../../logout/">{% trans 'Log out' %}</a>{% endblock %}
|
||||
{% block breadcrumbs %}{% if not is_popup %}
|
||||
<div class="breadcrumbs">
|
||||
<a href="../../../../">{% trans "Home" %}</a> ›
|
||||
<a href="../../">{{ opts.verbose_name_plural|capfirst|escape }}</a> ›
|
||||
<a href="../">{{ original|truncatewords:"18"|escape }}</a> ›
|
||||
{% trans 'Change password' %}
|
||||
</div>
|
||||
{% endif %}{% endblock %}
|
||||
{% block content %}<div id="content-main">
|
||||
<form action="{{ form_url }}" method="post" id="{{ opts.module_name }}_form">{% block form_top %}{% endblock %}
|
||||
<div>
|
||||
{% if is_popup %}<input type="hidden" name="_popup" value="1" />{% endif %}
|
||||
{% if form.error_dict %}
|
||||
<p class="errornote">
|
||||
{% blocktrans count form.error_dict.items|length as counter %}Please correct the error below.{% plural %}Please correct the errors below.{% endblocktrans %}
|
||||
</p>
|
||||
{% endif %}
|
||||
|
||||
<p>{% blocktrans with original.username|escape as username %}Enter a new username and password for the user <strong>{{ username }}</strong>.{% endblocktrans %}</p>
|
||||
|
||||
<fieldset class="module aligned">
|
||||
|
||||
<div class="form-row">
|
||||
{{ form.password1.html_error_list }}
|
||||
<label for="id_password1" class="required">{% trans 'Password' %}:</label> {{ form.password1 }}
|
||||
</div>
|
||||
|
||||
<div class="form-row">
|
||||
{{ form.password2.html_error_list }}
|
||||
<label for="id_password2" class="required">{% trans 'Password (again)' %}:</label> {{ form.password2 }}
|
||||
<p class="help">{% trans 'Enter the same password as above, for verification.' %}</p>
|
||||
</div>
|
||||
|
||||
</fieldset>
|
||||
|
||||
<div class="submit-row">
|
||||
<input type="submit" value="{% trans 'Change password' %}" class="default" />
|
||||
</div>
|
||||
|
||||
<script type="text/javascript">document.getElementById("{{ first_form_field_id }}").focus();</script>
|
||||
</div>
|
||||
</form></div>
|
||||
{% endblock %}
|
@ -29,6 +29,8 @@ urlpatterns = patterns('',
|
||||
|
||||
# "Add user" -- a special-case view
|
||||
('^auth/user/add/$', 'django.contrib.admin.views.auth.user_add_stage'),
|
||||
# "Change user password" -- another special-case view
|
||||
('^auth/user/(\d+)/password/$', 'django.contrib.admin.views.auth.user_change_password'),
|
||||
|
||||
# Add/change/delete/history
|
||||
('^([^/]+)/([^/]+)/$', 'django.contrib.admin.views.main.change_list'),
|
||||
|
@ -1,10 +1,11 @@
|
||||
from django.contrib.admin.views.decorators import staff_member_required
|
||||
from django.contrib.auth.forms import UserCreationForm
|
||||
from django.contrib.auth.forms import UserCreationForm, AdminPasswordChangeForm
|
||||
from django.contrib.auth.models import User
|
||||
from django.core.exceptions import PermissionDenied
|
||||
from django import oldforms, template
|
||||
from django.shortcuts import render_to_response
|
||||
from django.shortcuts import render_to_response, get_object_or_404
|
||||
from django.http import HttpResponseRedirect
|
||||
from django.utils.html import escape
|
||||
|
||||
def user_add_stage(request):
|
||||
if not request.user.has_perm('auth.change_user'):
|
||||
@ -42,3 +43,35 @@ def user_add_stage(request):
|
||||
'username_help_text': User._meta.get_field('username').help_text,
|
||||
}, context_instance=template.RequestContext(request))
|
||||
user_add_stage = staff_member_required(user_add_stage)
|
||||
|
||||
def user_change_password(request, id):
|
||||
if not request.user.has_perm('auth.change_user'):
|
||||
raise PermissionDenied
|
||||
user = get_object_or_404(User, pk=id)
|
||||
manipulator = AdminPasswordChangeForm(user)
|
||||
if request.method == 'POST':
|
||||
new_data = request.POST.copy()
|
||||
errors = manipulator.get_validation_errors(new_data)
|
||||
if not errors:
|
||||
new_user = manipulator.save(new_data)
|
||||
msg = _('Password changed successfully.')
|
||||
request.user.message_set.create(message=msg)
|
||||
return HttpResponseRedirect('..')
|
||||
else:
|
||||
errors = new_data = {}
|
||||
form = oldforms.FormWrapper(manipulator, new_data, errors)
|
||||
return render_to_response('admin/auth/user/change_password.html', {
|
||||
'title': _('Change password: %s') % escape(user.username),
|
||||
'form': form,
|
||||
'is_popup': request.REQUEST.has_key('_popup'),
|
||||
'add': True,
|
||||
'change': False,
|
||||
'has_delete_permission': False,
|
||||
'has_change_permission': True,
|
||||
'has_absolute_url': False,
|
||||
'first_form_field_id': 'id_password1',
|
||||
'opts': User._meta,
|
||||
'original': user,
|
||||
'show_save': True,
|
||||
}, context_instance=template.RequestContext(request))
|
||||
user_change_password = staff_member_required(user_change_password)
|
||||
|
@ -46,8 +46,8 @@ def quote(s):
|
||||
"""
|
||||
Ensure that primary key values do not confuse the admin URLs by escaping
|
||||
any '/', '_' and ':' characters. Similar to urllib.quote, except that the
|
||||
quoting is slightly different so that it doesn't get autoamtically
|
||||
unquoted by the web browser.
|
||||
quoting is slightly different so that it doesn't get automatically
|
||||
unquoted by the Web browser.
|
||||
"""
|
||||
if type(s) != type(''):
|
||||
return s
|
||||
|
@ -126,3 +126,18 @@ class PasswordChangeForm(oldforms.Manipulator):
|
||||
"Saves the new password."
|
||||
self.user.set_password(new_data['new_password1'])
|
||||
self.user.save()
|
||||
|
||||
class AdminPasswordChangeForm(oldforms.Manipulator):
|
||||
"A form used to change the password of a user in the admin interface."
|
||||
def __init__(self, user):
|
||||
self.user = user
|
||||
self.fields = (
|
||||
oldforms.PasswordField(field_name='password1', length=30, maxlength=60, is_required=True),
|
||||
oldforms.PasswordField(field_name='password2', length=30, maxlength=60, is_required=True,
|
||||
validator_list=[validators.AlwaysMatchesOtherField('password1', _("The two password fields didn't match."))]),
|
||||
)
|
||||
|
||||
def save(self, new_data):
|
||||
"Saves the new password."
|
||||
self.user.set_password(new_data['password1'])
|
||||
self.user.save()
|
||||
|
@ -91,7 +91,7 @@ class User(models.Model):
|
||||
first_name = models.CharField(_('first name'), maxlength=30, blank=True)
|
||||
last_name = models.CharField(_('last name'), maxlength=30, blank=True)
|
||||
email = models.EmailField(_('e-mail address'), blank=True)
|
||||
password = models.CharField(_('password'), maxlength=128, help_text=_("Use '[algo]$[salt]$[hexdigest]'"))
|
||||
password = models.CharField(_('password'), maxlength=128, help_text=_("Use '[algo]$[salt]$[hexdigest]' or use the <a href=\"password/\">change password form</a>."))
|
||||
is_staff = models.BooleanField(_('staff status'), default=False, help_text=_("Designates whether the user can log into this admin site."))
|
||||
is_active = models.BooleanField(_('active'), default=True, help_text=_("Designates whether this user can log into the Django admin. Unselect this instead of deleting accounts."))
|
||||
is_superuser = models.BooleanField(_('superuser status'), default=False, help_text=_("Designates that this user has all permissions without explicitly assigning them."))
|
||||
|
@ -48,6 +48,7 @@ from django.conf import settings
|
||||
from django.core.exceptions import ImproperlyConfigured
|
||||
from django.http import Http404
|
||||
from django.shortcuts import render_to_response
|
||||
from django.template.context import RequestContext
|
||||
import cPickle as pickle
|
||||
import md5
|
||||
|
||||
@ -91,7 +92,9 @@ class FormPreview(object):
|
||||
def preview_get(self, request):
|
||||
"Displays the form"
|
||||
f = self.form(auto_id=AUTO_ID)
|
||||
return render_to_response(self.form_template, {'form': f, 'stage_field': self.unused_name('stage'), 'state': self.state})
|
||||
return render_to_response(self.form_template,
|
||||
{'form': f, 'stage_field': self.unused_name('stage'), 'state': self.state},
|
||||
context_instance=RequestContext(request))
|
||||
|
||||
def preview_post(self, request):
|
||||
"Validates the POST data. If valid, displays the preview page. Else, redisplays form."
|
||||
@ -100,9 +103,9 @@ class FormPreview(object):
|
||||
if f.is_valid():
|
||||
context['hash_field'] = self.unused_name('hash')
|
||||
context['hash_value'] = self.security_hash(request, f)
|
||||
return render_to_response(self.preview_template, context)
|
||||
return render_to_response(self.preview_template, context, context_instance=RequestContext(request))
|
||||
else:
|
||||
return render_to_response(self.form_template, context)
|
||||
return render_to_response(self.form_template, context, context_instance=RequestContext(request))
|
||||
|
||||
def post_post(self, request):
|
||||
"Validates the POST data. If valid, calls done(). Else, redisplays form."
|
||||
@ -112,7 +115,9 @@ class FormPreview(object):
|
||||
return self.failed_hash(request) # Security hash failed.
|
||||
return self.done(request, f.clean_data)
|
||||
else:
|
||||
return render_to_response(self.form_template, {'form': f, 'stage_field': self.unused_name('stage'), 'state': self.state})
|
||||
return render_to_response(self.form_template,
|
||||
{'form': f, 'stage_field': self.unused_name('stage'), 'state': self.state},
|
||||
context_instance=RequestContext(request))
|
||||
|
||||
# METHODS SUBCLASSES MIGHT OVERRIDE IF APPROPRIATE ########################
|
||||
|
||||
|
@ -98,9 +98,11 @@ class DatabaseWrapper(local):
|
||||
kwargs['port'] = int(settings.DATABASE_PORT)
|
||||
kwargs.update(self.options)
|
||||
self.connection = Database.connect(**kwargs)
|
||||
cursor = self.connection.cursor()
|
||||
if self.connection.get_server_info() >= '4.1':
|
||||
cursor.execute("SET NAMES 'utf8'")
|
||||
cursor = self.connection.cursor()
|
||||
if self.connection.get_server_info() >= '4.1':
|
||||
cursor.execute("SET NAMES 'utf8'")
|
||||
else:
|
||||
cursor = self.connection.cursor()
|
||||
if settings.DEBUG:
|
||||
return util.CursorDebugWrapper(MysqlDebugWrapper(cursor), self)
|
||||
return cursor
|
||||
|
@ -43,7 +43,7 @@ class UnicodeCursorWrapper(object):
|
||||
return self.cursor.execute(sql, [smart_basestring(p, self.charset) for p in params])
|
||||
|
||||
def executemany(self, sql, param_list):
|
||||
new_param_list = [[smart_basestring(p, self.charset) for p in params] for params in param_list]
|
||||
new_param_list = [tuple([smart_basestring(p, self.charset) for p in params]) for params in param_list]
|
||||
return self.cursor.executemany(sql, new_param_list)
|
||||
|
||||
def __getattr__(self, attr):
|
||||
|
@ -729,6 +729,10 @@ class ManyToManyField(RelatedField, Field):
|
||||
return getattr(obj, self.attname).all()
|
||||
|
||||
def formfield(self, initial=None):
|
||||
# If initial is passed in, it's a list of related objects, but the
|
||||
# MultipleChoiceField takes a list of IDs.
|
||||
if initial is not None:
|
||||
initial = [i._get_pk_val() for i in initial]
|
||||
return forms.MultipleChoiceField(choices=self.get_choices_default(), required=not self.blank, label=capfirst(self.verbose_name), initial=initial)
|
||||
|
||||
class ManyToOneRel(object):
|
||||
|
@ -4,20 +4,29 @@
|
||||
|
||||
from django.template import loader
|
||||
from django.http import HttpResponse, Http404
|
||||
|
||||
from django.db.models.manager import Manager
|
||||
|
||||
def render_to_response(*args, **kwargs):
|
||||
return HttpResponse(loader.render_to_string(*args, **kwargs))
|
||||
load_and_render = render_to_response # For backwards compatibility.
|
||||
|
||||
def get_object_or_404(klass, *args, **kwargs):
|
||||
if isinstance(klass, Manager):
|
||||
manager = klass
|
||||
klass = manager.model
|
||||
else:
|
||||
manager = klass._default_manager
|
||||
try:
|
||||
return klass._default_manager.get(*args, **kwargs)
|
||||
return manager.get(*args, **kwargs)
|
||||
except klass.DoesNotExist:
|
||||
raise Http404
|
||||
|
||||
def get_list_or_404(klass, *args, **kwargs):
|
||||
obj_list = list(klass._default_manager.filter(*args, **kwargs))
|
||||
if isinstance(klass, Manager):
|
||||
manager = klass
|
||||
else:
|
||||
manager = klass._default_manager
|
||||
obj_list = list(manager.filter(*args, **kwargs))
|
||||
if not obj_list:
|
||||
raise Http404
|
||||
return obj_list
|
||||
|
@ -27,20 +27,38 @@ def fix_ampersands(value):
|
||||
from django.utils.html import fix_ampersands
|
||||
return fix_ampersands(value)
|
||||
|
||||
def floatformat(text):
|
||||
def floatformat(text, arg=-1):
|
||||
"""
|
||||
Displays a floating point number as 34.2 (with one decimal place) -- but
|
||||
only if there's a point to be displayed
|
||||
If called without an argument, displays a floating point
|
||||
number as 34.2 -- but only if there's a point to be displayed.
|
||||
With a positive numeric argument, it displays that many decimal places
|
||||
always.
|
||||
With a negative numeric argument, it will display that many decimal
|
||||
places -- but only if there's places to be displayed.
|
||||
Examples:
|
||||
num1 = 34.23234
|
||||
num2 = 34.00000
|
||||
num1|floatformat results in 34.2
|
||||
num2|floatformat is 34
|
||||
num1|floatformat:3 is 34.232
|
||||
num2|floatformat:3 is 34.000
|
||||
num1|floatformat:-3 is 34.232
|
||||
num2|floatformat:-3 is 34
|
||||
"""
|
||||
try:
|
||||
f = float(text)
|
||||
except ValueError:
|
||||
return ''
|
||||
try:
|
||||
d = int(arg)
|
||||
except ValueError:
|
||||
return str(f)
|
||||
m = f - int(f)
|
||||
if m:
|
||||
return '%.1f' % f
|
||||
else:
|
||||
if not m and d < 0:
|
||||
return '%d' % int(f)
|
||||
else:
|
||||
formatstr = '%%.%df' % abs(d)
|
||||
return formatstr % f
|
||||
|
||||
def linenumbers(value):
|
||||
"Displays text with line numbers"
|
||||
|
@ -1704,6 +1704,46 @@ For every ``ImageField``, the object will have ``get_FOO_height()`` and
|
||||
``get_FOO_width()`` methods, where ``FOO`` is the name of the field. This
|
||||
returns the height (or width) of the image, as an integer, in pixels.
|
||||
|
||||
Shortcuts
|
||||
=========
|
||||
|
||||
As you develop views, you will discover a number of common idioms in the
|
||||
way you use the database API. Django encodes some of these idioms as
|
||||
shortcuts that can be used to simplify the process of writing views.
|
||||
|
||||
get_object_or_404()
|
||||
-------------------
|
||||
|
||||
One common idiom to use ``get()`` and raise ``Http404`` if the
|
||||
object doesn't exist. This idiom is captured by ``get_object_or_404()``.
|
||||
This function takes a Django model as its first argument and an
|
||||
arbitrary number of keyword arguments, which it passes to the manager's
|
||||
``get()`` function. It raises ``Http404`` if the object doesn't
|
||||
exist. For example::
|
||||
|
||||
# Get the Entry with a primary key of 3
|
||||
e = get_object_or_404(Entry, pk=3)
|
||||
|
||||
When you provide a model to this shortcut function, the default manager
|
||||
is used to execute the underlying ``get()`` query. If you don't want to
|
||||
use the default manager, or you want to search a list of related objects,
|
||||
you can provide ``get_object_or_404()`` with a manager object, instead.
|
||||
For example::
|
||||
|
||||
# Get the author of blog instance `e` with a name of 'Fred'
|
||||
a = get_object_or_404(e.authors, name='Fred')
|
||||
|
||||
# Use a custom manager 'recent_entries' in the search for an
|
||||
# entry with a primary key of 3
|
||||
e = get_object_or_404(Entry.recent_entries, pk=3)
|
||||
|
||||
get_list_or_404()
|
||||
-----------------
|
||||
|
||||
``get_list_or_404`` behaves the same was as ``get_object_or_404()``
|
||||
-- except the it uses using ``filter()`` instead of ``get()``. It raises
|
||||
``Http404`` if the list is empty.
|
||||
|
||||
Falling back to raw SQL
|
||||
=======================
|
||||
|
||||
|
@ -94,7 +94,7 @@ Django places only two restrictions on model field names:
|
||||
the way Django's query lookup syntax works. For example::
|
||||
|
||||
class Example(models.Model):
|
||||
foo__bar = models.IntegerField() 'foo__bar' has two underscores!
|
||||
foo__bar = models.IntegerField() # 'foo__bar' has two underscores!
|
||||
|
||||
These limitations can be worked around, though, because your field name doesn't
|
||||
necessarily have to match your database column name. See `db_column`_ below.
|
||||
|
@ -72,6 +72,10 @@ The library deals with these concepts:
|
||||
* **Form** -- A collection of fields that knows how to validate itself and
|
||||
display itself as HTML.
|
||||
|
||||
The library is decoupled from the other Django components, such as the database
|
||||
layer, views and templates. It relies only on Django settings, a couple of
|
||||
``django.utils`` helper functions and Django's internationalization system.
|
||||
|
||||
Form objects
|
||||
============
|
||||
|
||||
@ -282,12 +286,41 @@ example, in the ``ContactForm`` example, the fields are defined in the order
|
||||
``subject``, ``message``, ``sender``, ``cc_myself``. To reorder the HTML
|
||||
output, just change the order in which those fields are listed in the class.
|
||||
|
||||
Using forms to validate data
|
||||
----------------------------
|
||||
More granular output
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
In addition to HTML form display, a ``Form`` class is responsible for
|
||||
validating data.
|
||||
The ``as_p()``, ``as_ul()`` and ``as_table()`` methods are simply shortcuts for
|
||||
lazy developers -- they're not the only way a form object can be displayed.
|
||||
|
||||
To display the HTML for a single field in your form, use dictionary lookup
|
||||
syntax using the field's name as the key, and print the resulting object::
|
||||
|
||||
>>> f = ContactForm()
|
||||
>>> print f['subject']
|
||||
<input id="id_subject" type="text" name="subject" maxlength="100" />
|
||||
>>> print f['message']
|
||||
<input type="text" name="message" id="id_message" />
|
||||
>>> print f['sender']
|
||||
<input type="text" name="sender" id="id_sender" />
|
||||
>>> print f['cc_myself']
|
||||
<input type="checkbox" name="cc_myself" id="id_cc_myself" />
|
||||
|
||||
Call ``str()`` or ``unicode()`` on the field to get its rendered HTML as a
|
||||
string or Unicode object, respectively::
|
||||
|
||||
>>> str(f['subject'])
|
||||
'<input id="id_subject" type="text" name="subject" maxlength="100" />'
|
||||
>>> unicode(f['subject'])
|
||||
u'<input id="id_subject" type="text" name="subject" maxlength="100" />'
|
||||
|
||||
The field-specific output honors the form object's ``auto_id`` setting::
|
||||
|
||||
>>> f = ContactForm(auto_id=False)
|
||||
>>> print f['message']
|
||||
<input type="text" name="message" />
|
||||
>>> f = ContactForm(auto_id='id_%s')
|
||||
>>> print f['message']
|
||||
<input type="text" name="message" id="id_message" />
|
||||
|
||||
More coming soon
|
||||
================
|
||||
@ -297,6 +330,9 @@ http://code.djangoproject.com/browser/django/trunk/tests/regressiontests/forms/t
|
||||
-- the unit tests for ``django.newforms``. This can give you a good idea of
|
||||
what's possible.
|
||||
|
||||
If you're really itching to learn and use this library, please be patient.
|
||||
We're working hard on finishing both the code and documentation.
|
||||
|
||||
Using forms with templates
|
||||
==========================
|
||||
|
||||
|
@ -217,6 +217,23 @@ browser-length cookies -- cookies that expire as soon as the user closes his or
|
||||
her browser. Use this if you want people to have to log in every time they open
|
||||
a browser.
|
||||
|
||||
Clearing the session table
|
||||
==========================
|
||||
|
||||
Note that session data can accumulate in the ``django_session`` database table
|
||||
and Django does *not* provide automatic purging. Therefore, it's your job to
|
||||
purge expired sessions on a regular basis.
|
||||
|
||||
To understand this problem, consider what happens when a user uses a session.
|
||||
When a user logs in, Django adds a row to the ``django_session`` database
|
||||
table. Django updates this row each time the session data changes. If the user
|
||||
logs out manually, Django deletes the row. But if the user does *not* log out,
|
||||
the row never gets deleted.
|
||||
|
||||
Django provides a sample clean-up script in ``django/bin/daily_cleanup.py``.
|
||||
That script deletes any session in the session table whose ``expire_date`` is
|
||||
in the past -- but your application may have different requirements.
|
||||
|
||||
Settings
|
||||
========
|
||||
|
||||
|
@ -924,13 +924,31 @@ Replaces ampersands with ``&`` entities.
|
||||
floatformat
|
||||
~~~~~~~~~~~
|
||||
|
||||
Rounds a floating-point number to one decimal place -- but only if there's a
|
||||
decimal part to be displayed. For example:
|
||||
When used without an argument, rounds a floating-point number to one decimal
|
||||
place -- but only if there's a decimal part to be displayed. For example:
|
||||
|
||||
* ``36.123`` gets converted to ``36.1``
|
||||
* ``36.15`` gets converted to ``36.2``
|
||||
* ``36`` gets converted to ``36``
|
||||
|
||||
**New in Django development version**
|
||||
|
||||
If used with a numeric integer argument, ``floatformat`` rounds a number to that
|
||||
many decimal places. For example:
|
||||
|
||||
* ``36.1234`` with floatformat:3 gets converted to ``36.123``
|
||||
* ``36`` with floatformat:4 gets converted to ``36.0000``
|
||||
|
||||
If the argument passed to ``floatformat`` is negative, it will round a number to
|
||||
that many decimal places -- but only if there's a decimal part to be displayed.
|
||||
For example:
|
||||
|
||||
* ``36.1234`` with floatformat:-3 gets converted to ``36.123``
|
||||
* ``36`` with floatformat:-4 gets converted to ``36``
|
||||
|
||||
Using ``floatformat`` with no argument is equivalent to using ``floatformat`` with
|
||||
an argument of ``-1``.
|
||||
|
||||
get_digit
|
||||
~~~~~~~~~
|
||||
|
||||
|
@ -300,7 +300,7 @@ rewritten::
|
||||
|
||||
The ``get_object_or_404()`` function takes a Django model module as its first
|
||||
argument and an arbitrary number of keyword arguments, which it passes to the
|
||||
module's ``get_object()`` function. It raises ``Http404`` if the object doesn't
|
||||
module's ``get()`` function. It raises ``Http404`` if the object doesn't
|
||||
exist.
|
||||
|
||||
.. admonition:: Philosophy
|
||||
|
9
setup.py
9
setup.py
@ -1,6 +1,7 @@
|
||||
from distutils.core import setup
|
||||
from distutils.command.install import INSTALL_SCHEMES
|
||||
import os
|
||||
import sys
|
||||
|
||||
# Tell distutils to put the data_files in platform-specific installation
|
||||
# locations. See here for an explanation:
|
||||
@ -23,7 +24,13 @@ for dirpath, dirnames, filenames in os.walk(django_dir):
|
||||
package = dirpath[len_root_dir:].lstrip('/').replace('/', '.')
|
||||
packages.append(package)
|
||||
else:
|
||||
data_files.append((dirpath, [os.path.join(dirpath, f) for f in filenames]))
|
||||
data_files.append([dirpath, [os.path.join(dirpath, f) for f in filenames]])
|
||||
|
||||
# Small hack for working with bdist_wininst.
|
||||
# See http://mail.python.org/pipermail/distutils-sig/2004-August/004134.html
|
||||
if sys.argv[1] == 'bdist_wininst':
|
||||
for file_info in data_files:
|
||||
file_info[0] = '/PURELIB/%s' % file_info[0]
|
||||
|
||||
# Dynamically calculate the version based on django.VERSION.
|
||||
version = "%d.%d-%s" % (__import__('django').VERSION)
|
||||
|
0
tests/modeltests/get_object_or_404/__init__.py
Normal file
0
tests/modeltests/get_object_or_404/__init__.py
Normal file
86
tests/modeltests/get_object_or_404/models.py
Normal file
86
tests/modeltests/get_object_or_404/models.py
Normal file
@ -0,0 +1,86 @@
|
||||
"""
|
||||
34. DB-API Shortcuts
|
||||
|
||||
get_object_or_404 is a shortcut function to be used in view functions for
|
||||
performing a get() lookup and raising a Http404 exception if a DoesNotExist
|
||||
exception was rasied during the get() call.
|
||||
|
||||
get_list_or_404 is a shortcut function to be used in view functions for
|
||||
performing a filter() lookup and raising a Http404 exception if a DoesNotExist
|
||||
exception was rasied during the filter() call.
|
||||
"""
|
||||
|
||||
from django.db import models
|
||||
from django.http import Http404
|
||||
from django.shortcuts import get_object_or_404, get_list_or_404
|
||||
|
||||
class Author(models.Model):
|
||||
name = models.CharField(maxlength=50)
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
class ArticleManager(models.Manager):
|
||||
def get_query_set(self):
|
||||
return super(ArticleManager, self).get_query_set().filter(authors__name__icontains='sir')
|
||||
|
||||
class Article(models.Model):
|
||||
authors = models.ManyToManyField(Author)
|
||||
title = models.CharField(maxlength=50)
|
||||
objects = models.Manager()
|
||||
by_a_sir = ArticleManager()
|
||||
|
||||
def __str__(self):
|
||||
return self.title
|
||||
|
||||
__test__ = {'API_TESTS':"""
|
||||
# Create some Authors.
|
||||
>>> a = Author.objects.create(name="Brave Sir Robin")
|
||||
>>> a.save()
|
||||
>>> a2 = Author.objects.create(name="Patsy")
|
||||
>>> a2.save()
|
||||
|
||||
# No Articles yet, so we should get a Http404 error.
|
||||
>>> get_object_or_404(Article, title="Foo")
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
Http404
|
||||
|
||||
# Create an Article.
|
||||
>>> article = Article.objects.create(title="Run away!")
|
||||
>>> article.authors = [a, a2]
|
||||
>>> article.save()
|
||||
|
||||
# get_object_or_404 can be passed a Model to query.
|
||||
>>> get_object_or_404(Article, title__contains="Run")
|
||||
<Article: Run away!>
|
||||
|
||||
# We can also use the the Article manager through an Author object.
|
||||
>>> get_object_or_404(a.article_set, title__contains="Run")
|
||||
<Article: Run away!>
|
||||
|
||||
# No articles containing "Camelot". This should raise a Http404 error.
|
||||
>>> get_object_or_404(a.article_set, title__contains="Camelot")
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
Http404
|
||||
|
||||
# Custom managers can be used too.
|
||||
>>> get_object_or_404(Article.by_a_sir, title="Run away!")
|
||||
<Article: Run away!>
|
||||
|
||||
# get_list_or_404 can be used to get lists of objects
|
||||
>>> get_list_or_404(a.article_set, title__icontains='Run')
|
||||
[<Article: Run away!>]
|
||||
|
||||
# Http404 is returned if the list is empty
|
||||
>>> get_list_or_404(a.article_set, title__icontains='Shrubbery')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
Http404
|
||||
|
||||
# Custom managers can be used too.
|
||||
>>> get_list_or_404(Article.by_a_sir, title__icontains="Run")
|
||||
[<Article: Run away!>]
|
||||
|
||||
"""}
|
@ -1,7 +1,8 @@
|
||||
"""
|
||||
34. Generating HTML forms from models
|
||||
|
||||
Django provides shortcuts for creating Form objects from a model class.
|
||||
Django provides shortcuts for creating Form objects from a model class and a
|
||||
model instance.
|
||||
|
||||
The function django.newforms.form_for_model() takes a model class and returns
|
||||
a Form that is tied to the model. This Form works just like any other Form,
|
||||
@ -9,6 +10,13 @@ with one additional method: create(). The create() method creates an instance
|
||||
of the model and returns that newly created instance. It saves the instance to
|
||||
the database if create(save=True), which is default. If you pass
|
||||
create(save=False), then you'll get the object without saving it.
|
||||
|
||||
The function django.newforms.form_for_instance() takes a model instance and
|
||||
returns a Form that is tied to the instance. This form works just like any
|
||||
other Form, with one additional method: apply_changes(). The apply_changes()
|
||||
method updates the model instance. It saves the changes to the database if
|
||||
apply_changes(save=True), which is default. If you pass save=False, then you'll
|
||||
get the object without saving it.
|
||||
"""
|
||||
|
||||
from django.db import models
|
||||
@ -28,7 +36,7 @@ class Writer(models.Model):
|
||||
|
||||
class Article(models.Model):
|
||||
headline = models.CharField(maxlength=50)
|
||||
pub_date = models.DateTimeField()
|
||||
pub_date = models.DateField()
|
||||
writer = models.ForeignKey(Writer)
|
||||
categories = models.ManyToManyField(Category, blank=True)
|
||||
|
||||
@ -80,6 +88,8 @@ __test__ = {'API_TESTS': """
|
||||
>>> Category.objects.all()
|
||||
[<Category: Entertainment>, <Category: It's a test>]
|
||||
|
||||
If you call create() with save=False, then it will return an object that hasn't
|
||||
yet been saved. In this case, it's up to you to save it.
|
||||
>>> f = CategoryForm({'name': 'Third test', 'url': 'third'})
|
||||
>>> f.errors
|
||||
{}
|
||||
@ -94,6 +104,7 @@ __test__ = {'API_TESTS': """
|
||||
>>> Category.objects.all()
|
||||
[<Category: Entertainment>, <Category: It's a test>, <Category: Third test>]
|
||||
|
||||
If you call create() with invalid data, you'll get a ValueError.
|
||||
>>> f = CategoryForm({'name': '', 'url': 'foo'})
|
||||
>>> f.errors
|
||||
{'name': [u'This field is required.']}
|
||||
@ -102,7 +113,6 @@ __test__ = {'API_TESTS': """
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValueError: The Category could not be created because the data didn't validate.
|
||||
|
||||
>>> f = CategoryForm({'name': '', 'url': 'foo'})
|
||||
>>> f.create()
|
||||
Traceback (most recent call last):
|
||||
@ -181,4 +191,27 @@ True
|
||||
>>> new_art = Article.objects.get(id=1)
|
||||
>>> new_art.headline
|
||||
'New headline'
|
||||
|
||||
Add some categories and test the many-to-many form output.
|
||||
>>> new_art.categories.all()
|
||||
[]
|
||||
>>> new_art.categories.add(Category.objects.get(name='Entertainment'))
|
||||
>>> new_art.categories.all()
|
||||
[<Category: Entertainment>]
|
||||
>>> TestArticleForm = form_for_instance(new_art)
|
||||
>>> f = TestArticleForm(auto_id=False)
|
||||
>>> print f.as_ul()
|
||||
<li>Headline: <input type="text" name="headline" value="New headline" maxlength="50" /></li>
|
||||
<li>Pub date: <input type="text" name="pub_date" value="1988-01-04" /></li>
|
||||
<li>Writer: <select name="writer">
|
||||
<option value="">---------</option>
|
||||
<option value="1" selected="selected">Mike Royko</option>
|
||||
<option value="2">Bob Woodward</option>
|
||||
</select></li>
|
||||
<li>Categories: <select multiple="multiple" name="categories">
|
||||
<option value="1" selected="selected">Entertainment</option>
|
||||
<option value="2">It's a test</option>
|
||||
<option value="3">Third test</option>
|
||||
</select></li>
|
||||
|
||||
"""}
|
||||
|
@ -11,6 +11,26 @@ r"""
|
||||
'0.0'
|
||||
>>> floatformat(0.0)
|
||||
'0'
|
||||
>>> floatformat(7.7,3)
|
||||
'7.700'
|
||||
>>> floatformat(6.000000,3)
|
||||
'6.000'
|
||||
>>> floatformat(13.1031,-3)
|
||||
'13.103'
|
||||
>>> floatformat(11.1197, -2)
|
||||
'11.12'
|
||||
>>> floatformat(11.0000, -2)
|
||||
'11'
|
||||
>>> floatformat(11.000001, -2)
|
||||
'11.00'
|
||||
>>> floatformat(8.2798, 3)
|
||||
'8.280'
|
||||
>>> floatformat('foo')
|
||||
''
|
||||
>>> floatformat(13.1031, 'bar')
|
||||
'13.1031'
|
||||
>>> floatformat('foo', 'bar')
|
||||
''
|
||||
|
||||
>>> addslashes('"double quotes" and \'single quotes\'')
|
||||
'\\"double quotes\\" and \\\'single quotes\\\''
|
||||
|
@ -2482,7 +2482,7 @@ demonstrate some of the library's abilities.
|
||||
# SelectDateWidget ############################################################
|
||||
|
||||
>>> from django.newforms.extras import SelectDateWidget
|
||||
>>> w = SelectDateWidget()
|
||||
>>> w = SelectDateWidget(years=('2007','2008','2009','2010','2011','2012','2013','2014','2015','2016'))
|
||||
>>> print w.render('mydate', '')
|
||||
<select name="mydate_month">
|
||||
<option value="1">January</option>
|
||||
@ -2532,7 +2532,6 @@ demonstrate some of the library's abilities.
|
||||
<option value="31">31</option>
|
||||
</select>
|
||||
<select name="mydate_year">
|
||||
<option value="2006">2006</option>
|
||||
<option value="2007">2007</option>
|
||||
<option value="2008">2008</option>
|
||||
<option value="2009">2009</option>
|
||||
@ -2542,6 +2541,7 @@ demonstrate some of the library's abilities.
|
||||
<option value="2013">2013</option>
|
||||
<option value="2014">2014</option>
|
||||
<option value="2015">2015</option>
|
||||
<option value="2016">2016</option>
|
||||
</select>
|
||||
>>> w.render('mydate', None) == w.render('mydate', '')
|
||||
True
|
||||
@ -2594,7 +2594,6 @@ True
|
||||
<option value="31">31</option>
|
||||
</select>
|
||||
<select name="mydate_year">
|
||||
<option value="2006">2006</option>
|
||||
<option value="2007">2007</option>
|
||||
<option value="2008">2008</option>
|
||||
<option value="2009">2009</option>
|
||||
@ -2604,6 +2603,7 @@ True
|
||||
<option value="2013">2013</option>
|
||||
<option value="2014">2014</option>
|
||||
<option value="2015">2015</option>
|
||||
<option value="2016">2016</option>
|
||||
</select>
|
||||
|
||||
"""
|
||||
|
337
tests/regressiontests/invalid_admin_options/models.py
Normal file
337
tests/regressiontests/invalid_admin_options/models.py
Normal file
@ -0,0 +1,337 @@
|
||||
"""
|
||||
Admin options
|
||||
|
||||
Test invalid and valid admin options to make sure that
|
||||
model validation is working properly.
|
||||
"""
|
||||
|
||||
from django.db import models
|
||||
model_errors = ""
|
||||
|
||||
# TODO: Invalid admin options should not cause a metaclass error
|
||||
##This should fail gracefully but is causing a metaclass error
|
||||
#class BadAdminOption(models.Model):
|
||||
# "Test nonexistent admin option"
|
||||
# name = models.CharField(maxlength=30)
|
||||
#
|
||||
# class Admin:
|
||||
# nonexistent = 'option'
|
||||
#
|
||||
#model_errors += """invalid_admin_options.badadminoption: "admin" attribute, if given, must be set to a models.AdminOptions() instance.
|
||||
#"""
|
||||
|
||||
class ListDisplayBadOne(models.Model):
|
||||
"Test list_display, list_display must be a list or tuple"
|
||||
first_name = models.CharField(maxlength=30)
|
||||
|
||||
class Admin:
|
||||
list_display = 'first_name'
|
||||
|
||||
model_errors += """invalid_admin_options.listdisplaybadone: "admin.list_display", if given, must be set to a list or tuple.
|
||||
"""
|
||||
|
||||
class ListDisplayBadTwo(models.Model):
|
||||
"Test list_display, list_display items must be attributes, methods or properties."
|
||||
first_name = models.CharField(maxlength=30)
|
||||
|
||||
class Admin:
|
||||
list_display = ['first_name','nonexistent']
|
||||
|
||||
model_errors += """invalid_admin_options.listdisplaybadtwo: "admin.list_display" refers to 'nonexistent', which isn't an attribute, method or property.
|
||||
"""
|
||||
class ListDisplayBadThree(models.Model):
|
||||
"Test list_display, list_display items can not be a ManyToManyField."
|
||||
first_name = models.CharField(maxlength=30)
|
||||
nick_names = models.ManyToManyField('ListDisplayGood')
|
||||
|
||||
class Admin:
|
||||
list_display = ['first_name','nick_names']
|
||||
|
||||
model_errors += """invalid_admin_options.listdisplaybadthree: "admin.list_display" doesn't support ManyToManyFields ('nick_names').
|
||||
"""
|
||||
|
||||
class ListDisplayGood(models.Model):
|
||||
"Test list_display, Admin list_display can be a attribute, method or property."
|
||||
first_name = models.CharField(maxlength=30)
|
||||
|
||||
def _last_name(self):
|
||||
return self.first_name
|
||||
last_name = property(_last_name)
|
||||
|
||||
def full_name(self):
|
||||
return "%s %s" % (self.first_name, self.last_name)
|
||||
|
||||
class Admin:
|
||||
list_display = ['first_name','last_name','full_name']
|
||||
|
||||
class ListDisplayLinksBadOne(models.Model):
|
||||
"Test list_display_links, item must be included in list_display."
|
||||
first_name = models.CharField(maxlength=30)
|
||||
last_name = models.CharField(maxlength=30)
|
||||
|
||||
class Admin:
|
||||
list_display = ['last_name']
|
||||
list_display_links = ['first_name']
|
||||
|
||||
model_errors += """invalid_admin_options.listdisplaylinksbadone: "admin.list_display_links" refers to 'first_name', which is not defined in "admin.list_display".
|
||||
"""
|
||||
|
||||
class ListDisplayLinksBadTwo(models.Model):
|
||||
"Test list_display_links, must be a list or tuple."
|
||||
first_name = models.CharField(maxlength=30)
|
||||
last_name = models.CharField(maxlength=30)
|
||||
|
||||
class Admin:
|
||||
list_display = ['first_name','last_name']
|
||||
list_display_links = 'last_name'
|
||||
|
||||
model_errors += """invalid_admin_options.listdisplaylinksbadtwo: "admin.list_display_links", if given, must be set to a list or tuple.
|
||||
"""
|
||||
|
||||
# TODO: Fix list_display_links validation or remove the check for list_display
|
||||
## This is failing but the validation which should fail is not.
|
||||
#class ListDisplayLinksBadThree(models.Model):
|
||||
# "Test list_display_links, must define list_display to use list_display_links."
|
||||
# first_name = models.CharField(maxlength=30)
|
||||
# last_name = models.CharField(maxlength=30)
|
||||
#
|
||||
# class Admin:
|
||||
# list_display_links = ('first_name',)
|
||||
#
|
||||
#model_errors += """invalid_admin_options.listdisplaylinksbadthree: "admin.list_display" must be defined for "admin.list_display_links" to be used.
|
||||
#"""
|
||||
|
||||
class ListDisplayLinksGood(models.Model):
|
||||
"Test list_display_links, Admin list_display_list can be a attribute, method or property."
|
||||
first_name = models.CharField(maxlength=30)
|
||||
|
||||
def _last_name(self):
|
||||
return self.first_name
|
||||
last_name = property(_last_name)
|
||||
|
||||
def full_name(self):
|
||||
return "%s %s" % (self.first_name, self.last_name)
|
||||
|
||||
class Admin:
|
||||
list_display = ['first_name','last_name','full_name']
|
||||
list_display_links = ['first_name','last_name','full_name']
|
||||
|
||||
class ListFilterBadOne(models.Model):
|
||||
"Test list_filter, must be a list or tuple."
|
||||
first_name = models.CharField(maxlength=30)
|
||||
|
||||
class Admin:
|
||||
list_filter = 'first_name'
|
||||
|
||||
model_errors += """invalid_admin_options.listfilterbadone: "admin.list_filter", if given, must be set to a list or tuple.
|
||||
"""
|
||||
|
||||
class ListFilterBadTwo(models.Model):
|
||||
"Test list_filter, must be a field not a property or method."
|
||||
first_name = models.CharField(maxlength=30)
|
||||
|
||||
def _last_name(self):
|
||||
return self.first_name
|
||||
last_name = property(_last_name)
|
||||
|
||||
def full_name(self):
|
||||
return "%s %s" % (self.first_name, self.last_name)
|
||||
|
||||
class Admin:
|
||||
list_filter = ['first_name','last_name','full_name']
|
||||
|
||||
model_errors += """invalid_admin_options.listfilterbadtwo: "admin.list_filter" refers to 'last_name', which isn't a field.
|
||||
invalid_admin_options.listfilterbadtwo: "admin.list_filter" refers to 'full_name', which isn't a field.
|
||||
"""
|
||||
|
||||
class DateHierarchyBadOne(models.Model):
|
||||
"Test date_hierarchy, must be a date or datetime field."
|
||||
first_name = models.CharField(maxlength=30)
|
||||
birth_day = models.DateField()
|
||||
|
||||
class Admin:
|
||||
date_hierarchy = 'first_name'
|
||||
|
||||
# TODO: Date Hierarchy needs to check if field is a date/datetime field.
|
||||
#model_errors += """invalid_admin_options.datehierarchybadone: "admin.date_hierarchy" refers to 'first_name', which isn't a date field or datetime field.
|
||||
#"""
|
||||
|
||||
class DateHierarchyBadTwo(models.Model):
|
||||
"Test date_hieracrhy, must be a field."
|
||||
first_name = models.CharField(maxlength=30)
|
||||
birth_day = models.DateField()
|
||||
|
||||
class Admin:
|
||||
date_hierarchy = 'nonexistent'
|
||||
|
||||
model_errors += """invalid_admin_options.datehierarchybadtwo: "admin.date_hierarchy" refers to 'nonexistent', which isn't a field.
|
||||
"""
|
||||
|
||||
class DateHierarchyGood(models.Model):
|
||||
"Test date_hieracrhy, must be a field."
|
||||
first_name = models.CharField(maxlength=30)
|
||||
birth_day = models.DateField()
|
||||
|
||||
class Admin:
|
||||
date_hierarchy = 'birth_day'
|
||||
|
||||
class SearchFieldsBadOne(models.Model):
|
||||
"Test search_fields, must be a list or tuple."
|
||||
first_name = models.CharField(maxlength=30)
|
||||
|
||||
class Admin:
|
||||
search_fields = ('nonexistent')
|
||||
|
||||
# TODO: Add search_fields validation
|
||||
#model_errors += """invalid_admin_options.seacrhfieldsbadone: "admin.search_fields", if given, must be set to a list or tuple.
|
||||
#"""
|
||||
|
||||
class SearchFieldsBadTwo(models.Model):
|
||||
"Test search_fields, must be a field."
|
||||
first_name = models.CharField(maxlength=30)
|
||||
|
||||
def _last_name(self):
|
||||
return self.first_name
|
||||
last_name = property(_last_name)
|
||||
|
||||
class Admin:
|
||||
search_fields = ['first_name','last_name']
|
||||
|
||||
# TODO: Add search_fields validation
|
||||
#model_errors += """invalid_admin_options.seacrhfieldsbadone: "admin.search_fields" refers to 'last_name', which isn't a field.
|
||||
#"""
|
||||
|
||||
class SearchFieldsGood(models.Model):
|
||||
"Test search_fields, must be a list or tuple."
|
||||
first_name = models.CharField(maxlength=30)
|
||||
last_name = models.CharField(maxlength=30)
|
||||
|
||||
class Admin:
|
||||
search_fields = ['first_name','last_name']
|
||||
|
||||
|
||||
class JsBadOne(models.Model):
|
||||
"Test js, must be a list or tuple"
|
||||
name = models.CharField(maxlength=30)
|
||||
|
||||
class Admin:
|
||||
js = 'test.js'
|
||||
|
||||
# TODO: Add a js validator
|
||||
#model_errors += """invalid_admin_options.jsbadone: "admin.js", if given, must be set to a list or tuple.
|
||||
#"""
|
||||
|
||||
class SaveAsBad(models.Model):
|
||||
"Test save_as, should be True or False"
|
||||
name = models.CharField(maxlength=30)
|
||||
|
||||
class Admin:
|
||||
save_as = 'not True or False'
|
||||
|
||||
# TODO: Add a save_as validator.
|
||||
#model_errors += """invalid_admin_options.saveasbad: "admin.save_as", if given, must be set to True or False.
|
||||
#"""
|
||||
|
||||
class SaveOnTopBad(models.Model):
|
||||
"Test save_on_top, should be True or False"
|
||||
name = models.CharField(maxlength=30)
|
||||
|
||||
class Admin:
|
||||
save_on_top = 'not True or False'
|
||||
|
||||
# TODO: Add a save_on_top validator.
|
||||
#model_errors += """invalid_admin_options.saveontopbad: "admin.save_on_top", if given, must be set to True or False.
|
||||
#"""
|
||||
|
||||
class ListSelectRelatedBad(models.Model):
|
||||
"Test list_select_related, should be True or False"
|
||||
name = models.CharField(maxlength=30)
|
||||
|
||||
class Admin:
|
||||
list_select_related = 'not True or False'
|
||||
|
||||
# TODO: Add a list_select_related validator.
|
||||
#model_errors += """invalid_admin_options.listselectrelatebad: "admin.list_select_related", if given, must be set to True or False.
|
||||
#"""
|
||||
|
||||
class ListPerPageBad(models.Model):
|
||||
"Test list_per_page, should be a positive integer value."
|
||||
name = models.CharField(maxlength=30)
|
||||
|
||||
class Admin:
|
||||
list_per_page = 89.3
|
||||
|
||||
# TODO: Add a list_per_page validator.
|
||||
#model_errors += """invalid_admin_options.listperpagebad: "admin.list_per_page", if given, must be a positive integer.
|
||||
#"""
|
||||
|
||||
class FieldsBadOne(models.Model):
|
||||
"Test fields, should be a tuple"
|
||||
first_name = models.CharField(maxlength=30)
|
||||
last_name = models.CharField(maxlength=30)
|
||||
|
||||
class Admin:
|
||||
fields = 'not a tuple'
|
||||
|
||||
# TODO: Add a fields validator.
|
||||
#model_errors += """invalid_admin_options.fieldsbadone: "admin.fields", if given, must be a tuple.
|
||||
#"""
|
||||
|
||||
class FieldsBadTwo(models.Model):
|
||||
"""Test fields, 'fields' dict option is required."""
|
||||
first_name = models.CharField(maxlength=30)
|
||||
last_name = models.CharField(maxlength=30)
|
||||
|
||||
class Admin:
|
||||
fields = ('Name', {'description': 'this fieldset needs fields'})
|
||||
|
||||
# TODO: Add a fields validator.
|
||||
#model_errors += """invalid_admin_options.fieldsbadtwo: "admin.fields" each fieldset must include a 'fields' dict.
|
||||
#"""
|
||||
|
||||
class FieldsBadThree(models.Model):
|
||||
"""Test fields, 'classes' and 'description' are the only allowable extra dict options."""
|
||||
first_name = models.CharField(maxlength=30)
|
||||
last_name = models.CharField(maxlength=30)
|
||||
|
||||
class Admin:
|
||||
fields = ('Name', {'fields': ('first_name','last_name'),'badoption': 'verybadoption'})
|
||||
|
||||
# TODO: Add a fields validator.
|
||||
#model_errors += """invalid_admin_options.fieldsbadthree: "admin.fields" fieldset options must be either 'classes' or 'description'.
|
||||
#"""
|
||||
|
||||
class FieldsGood(models.Model):
|
||||
"Test fields, working example"
|
||||
first_name = models.CharField(maxlength=30)
|
||||
last_name = models.CharField(maxlength=30)
|
||||
birth_day = models.DateField()
|
||||
|
||||
class Admin:
|
||||
fields = (
|
||||
('Name', {'fields': ('first_name','last_name'),'classes': 'collapse'}),
|
||||
(None, {'fields': ('birth_day',),'description': 'enter your b-day'})
|
||||
)
|
||||
|
||||
class OrderingBad(models.Model):
|
||||
"Test ordering, must be a field."
|
||||
first_name = models.CharField(maxlength=30)
|
||||
last_name = models.CharField(maxlength=30)
|
||||
|
||||
class Admin:
|
||||
ordering = 'nonexistent'
|
||||
|
||||
# TODO: Add a ordering validator.
|
||||
#model_errors += """invalid_admin_options.orderingbad: "admin.ordering" refers to 'nonexistent', which isn't a field.
|
||||
#"""
|
||||
|
||||
## TODO: Add a manager validator, this should fail gracefully.
|
||||
#class ManagerBad(models.Model):
|
||||
# "Test manager, must be a manager object."
|
||||
# first_name = models.CharField(maxlength=30)
|
||||
#
|
||||
# class Admin:
|
||||
# manager = 'nonexistent'
|
||||
#
|
||||
#model_errors += """invalid_admin_options.managerbad: "admin.manager" refers to 'nonexistent', which isn't a Manager().
|
||||
#"""
|
Loading…
x
Reference in New Issue
Block a user