1
0
mirror of https://github.com/django/django.git synced 2025-07-05 02:09:13 +00:00

Synced to trunk. Fixed views/decorators/auth.py. Added extra customisation points to admin change_forms.

git-svn-id: http://code.djangoproject.com/svn/django/branches/new-admin@998 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Robert Wittams 2005-10-23 15:45:02 +00:00
commit a4ce9cf2ce
11 changed files with 530 additions and 70 deletions

View File

@ -19,8 +19,7 @@
{% if has_absolute_url %}<li><a href="/r/{{ content_type_id }}/{{ object_id }}/" class="viewsitelink">View on site</a></li>{% endif%} {% if has_absolute_url %}<li><a href="/r/{{ content_type_id }}/{{ object_id }}/" class="viewsitelink">View on site</a></li>{% endif%}
</ul> </ul>
{% endif %}{% endif %} {% endif %}{% endif %}
<form {{ form_enc_attrib }} action='{{ form_url }}' method="post"> <form {{ form_enc_attrib }} action='{{ form_url }}' method="post">{% block form_top %}{%endblock%}
{% if is_popup %}<input type="hidden" name="_popup" value="1">{% endif %} {% if is_popup %}<input type="hidden" name="_popup" value="1">{% endif %}
{% if save_on_top %}{% submit_row %}{% endif %} {% if save_on_top %}{% submit_row %}{% endif %}
{% if form.error_dict %}<p class="errornote">Please correct the error{{ form.error_dict.items|pluralize }} below.</p>{% endif %} {% if form.error_dict %}<p class="errornote">Please correct the error{{ form.error_dict.items|pluralize }} below.</p>{% endif %}
@ -35,6 +34,7 @@
{% endfor %} {% endfor %}
</fieldset> </fieldset>
{% endfor %} {% endfor %}
{% block after_field_sets %}{% endblock %}
{% if change %} {% if change %}
{% if ordered_objects %} {% if ordered_objects %}
<fieldset class="module"><h2>Ordering</h2> <fieldset class="module"><h2>Ordering</h2>
@ -44,7 +44,9 @@
</div></fieldset> </div></fieldset>
{% endif %} {% endif %}
{% endif %} {% endif %}
{% for related_object in inline_related_objects %}{% edit_inline related_object %}{% endfor %} {% for related_object in inline_related_objects %}{% edit_inline related_object %}{% endfor %}
{% block after_related_objects%}{%endblock%}
{% submit_row %} {% submit_row %}
{% if add %} {% if add %}
<script type="text/javascript">document.getElementById("{{first_form_field_id}}").focus();</script> <script type="text/javascript">document.getElementById("{{first_form_field_id}}").focus();</script>

View File

@ -607,7 +607,7 @@ class AdminBoundFieldSet(BoundFieldSet):
super(AdminBoundFieldSet, self).__init__(field_set, field_mapping, original, AdminBoundFieldLine) super(AdminBoundFieldSet, self).__init__(field_set, field_mapping, original, AdminBoundFieldLine)
def fill_extra_context(opts, app_label, context, add=False, change=False, show_delete=False, form_url=''): def render_change_form(opts, app_label, context, add=False, change=False, show_delete=False, form_url=''):
ordered_objects = opts.get_ordered_objects()[:] ordered_objects = opts.get_ordered_objects()[:]
auto_populated_fields = [f for f in opts.fields if f.prepopulate_from] auto_populated_fields = [f for f in opts.fields if f.prepopulate_from]
coltype = ordered_objects and 'colMS' or 'colM' coltype = ordered_objects and 'colMS' or 'colM'
@ -652,6 +652,14 @@ def fill_extra_context(opts, app_label, context, add=False, change=False, show_d
context.update(extra_context) context.update(extra_context)
return render_to_response(["admin/%s/%s/change_form" % (app_label, opts.object_name.lower() ),
"admin/%s/change_form" % app_label ,
"admin/change_form"],
context_instance=context)
def log_add_message(user, opts,manipulator,new_object):
pk_value = getattr(new_object, opts.pk.column)
log.log_action(user.id, opts.get_content_type_id(), pk_value, repr(new_object), log.ADDITION)
def add_stage(request, app_label, module_name, show_delete=False, form_url='', post_url='../', post_url_continue='../%s/', object_id_override=None): def add_stage(request, app_label, module_name, show_delete=False, form_url='', post_url='../', post_url_continue='../%s/', object_id_override=None):
mod, opts = _get_mod_opts(app_label, module_name) mod, opts = _get_mod_opts(app_label, module_name)
@ -666,13 +674,10 @@ def add_stage(request, app_label, module_name, show_delete=False, form_url='', p
manipulator.do_html2python(new_data) manipulator.do_html2python(new_data)
if not errors and not request.POST.has_key("_preview"): if not errors and not request.POST.has_key("_preview"):
for f in opts.many_to_many:
if f.rel.raw_id_admin:
new_data.setlist(f.name, new_data[f.name].split(","))
new_object = manipulator.save(new_data) new_object = manipulator.save(new_data)
pk_value = getattr(new_object, opts.pk.column) log_add_message(request.user, opts,manipulator,new_object)
log.log_action(request.user.id, opts.get_content_type_id(), pk_value, repr(new_object), log.ADDITION)
msg = 'The %s "%s" was added successfully.' % (opts.verbose_name, new_object) msg = 'The %s "%s" was added successfully.' % (opts.verbose_name, new_object)
# Here, we distinguish between different save types by checking for # Here, we distinguish between different save types by checking for
# the presence of keys in request.POST. # the presence of keys in request.POST.
if request.POST.has_key("_continue"): if request.POST.has_key("_continue"):
@ -689,8 +694,6 @@ def add_stage(request, app_label, module_name, show_delete=False, form_url='', p
else: else:
request.user.add_message(msg) request.user.add_message(msg)
return HttpResponseRedirect(post_url) return HttpResponseRedirect(post_url)
# if request.POST.has_key("_preview"): # Always happens anyway.
# manipulator.do_html2python(new_data)
else: else:
# Add default data. # Add default data.
new_data = manipulator.flatten_data() new_data = manipulator.flatten_data()
@ -710,12 +713,23 @@ def add_stage(request, app_label, module_name, show_delete=False, form_url='', p
if object_id_override is not None: if object_id_override is not None:
c['object_id'] = object_id_override c['object_id'] = object_id_override
return render_change_form(opts, app_label, c, add=True)
fill_extra_context(opts, app_label, c, add=True)
return render_to_response("admin/change_form", context_instance=c)
add_stage = staff_member_required(add_stage) add_stage = staff_member_required(add_stage)
def log_change_message(user, opts,manipulator,new_object):
pk_value = getattr(new_object, opts.pk.column)
# Construct the change message.
change_message = []
if manipulator.fields_added:
change_message.append('Added %s.' % get_text_list(manipulator.fields_added, 'and'))
if manipulator.fields_changed:
change_message.append('Changed %s.' % get_text_list(manipulator.fields_changed, 'and'))
if manipulator.fields_deleted:
change_message.append('Deleted %s.' % get_text_list(manipulator.fields_deleted, 'and'))
change_message = ' '.join(change_message)
if not change_message:
change_message = 'No fields changed.'
log.log_action(user.id, opts.get_content_type_id(), pk_value, repr(new_object), log.CHANGE, change_message)
def change_stage(request, app_label, module_name, object_id): def change_stage(request, app_label, module_name, object_id):
mod, opts = _get_mod_opts(app_label, module_name) mod, opts = _get_mod_opts(app_label, module_name)
@ -737,26 +751,8 @@ def change_stage(request, app_label, module_name, object_id):
manipulator.do_html2python(new_data) manipulator.do_html2python(new_data)
if not errors and not request.POST.has_key("_preview"): if not errors and not request.POST.has_key("_preview"):
# Now done in commaseparatedint
# for f in opts.many_to_many:
# if f.rel.raw_id_admin:
# new_data.setlist(f.name, new_data[f.name].split(","))
new_object = manipulator.save(new_data) new_object = manipulator.save(new_data)
pk_value = getattr(new_object, opts.pk.column) log_change_message(request.user,opts,manipulator,new_object)
# Construct the change message.
change_message = []
if manipulator.fields_added:
change_message.append('Added %s.' % get_text_list(manipulator.fields_added, 'and'))
if manipulator.fields_changed:
change_message.append('Changed %s.' % get_text_list(manipulator.fields_changed, 'and'))
if manipulator.fields_deleted:
change_message.append('Deleted %s.' % get_text_list(manipulator.fields_deleted, 'and'))
change_message = ' '.join(change_message)
if not change_message:
change_message = 'No fields changed.'
log.log_action(request.user.id, opts.get_content_type_id(), pk_value, repr(new_object), log.CHANGE, change_message)
msg = 'The %s "%s" was changed successfully.' % (opts.verbose_name, new_object) msg = 'The %s "%s" was changed successfully.' % (opts.verbose_name, new_object)
if request.POST.has_key("_continue"): if request.POST.has_key("_continue"):
request.user.add_message("%s You may edit it again below." % msg) request.user.add_message("%s You may edit it again below." % msg)
@ -773,15 +769,14 @@ def change_stage(request, app_label, module_name, object_id):
else: else:
request.user.add_message(msg) request.user.add_message(msg)
return HttpResponseRedirect("../") return HttpResponseRedirect("../")
# if request.POST.has_key("_preview"): # always happens
# manipulator.do_html2python(new_data)
else: else:
# Populate new_data with a "flattened" version of the current data. # Populate new_data with a "flattened" version of the current data.
new_data = manipulator.flatten_data() new_data = manipulator.flatten_data()
# TODO: do this in flatten_data...
# If the object has ordered objects on its admin page, get the existing # If the object has ordered objects on its admin page, get the existing
# order and flatten it into a comma-separated list of IDs. # order and flatten it into a comma-separated list of IDs.
id_order_list = [] id_order_list = []
for rel_obj in opts.get_ordered_objects(): for rel_obj in opts.get_ordered_objects():
id_order_list.extend(getattr(obj, 'get_%s_order' % rel_obj.object_name.lower())()) id_order_list.extend(getattr(obj, 'get_%s_order' % rel_obj.object_name.lower())())
@ -794,6 +789,7 @@ def change_stage(request, app_label, module_name, object_id):
form.original = manipulator.original_object form.original = manipulator.original_object
form.order_objects = [] form.order_objects = []
#TODO Should be done in flatten_data / FormWrapper construction
for related in opts.get_followed_related_objects(): for related in opts.get_followed_related_objects():
wrt = related.opts.order_with_respect_to wrt = related.opts.order_with_respect_to
if wrt and wrt.rel and wrt.rel.to == opts: if wrt and wrt.rel and wrt.rel.to == opts:
@ -810,10 +806,9 @@ def change_stage(request, app_label, module_name, object_id):
'is_popup' : request.REQUEST.has_key('_popup') 'is_popup' : request.REQUEST.has_key('_popup')
}) })
fill_extra_context(opts, app_label, c, change=True) return render_change_form(opts, app_label, c, change=True)
return render_to_response('admin/change_form', context_instance=c)
change_stage = staff_member_required(change_stage)
def _nest_help(obj, depth, val): def _nest_help(obj, depth, val):
current = obj current = obj

View File

@ -1498,9 +1498,10 @@ def function_get_sql_clause(opts, **kwargs):
def function_get_in_bulk(opts, klass, *args, **kwargs): def function_get_in_bulk(opts, klass, *args, **kwargs):
id_list = args and args[0] or kwargs['id_list'] id_list = args and args[0] or kwargs['id_list']
assert id_list != [], "get_in_bulk() cannot be passed an empty list." assert id_list != [], "get_in_bulk() cannot be passed an empty list."
kwargs['where'] = ["%s.id IN (%s)" % (opts.db_table, ",".join(map(str, id_list)))] kwargs['where'] = ["%s.%s IN (%s)" % (opts.db_table, opts.pk.column, ",".join(['%s'] * len(id_list)))]
kwargs['params'] = id_list
obj_list = function_get_list(opts, klass, **kwargs) obj_list = function_get_list(opts, klass, **kwargs)
return dict([(o.id, o) for o in obj_list]) return dict([(getattr(o, opts.pk.column), o) for o in obj_list])
def function_get_latest(opts, klass, does_not_exist_exception, **kwargs): def function_get_latest(opts, klass, does_not_exist_exception, **kwargs):
kwargs['order_by'] = ('-' + opts.get_latest_by,) kwargs['order_by'] = ('-' + opts.get_latest_by,)

View File

@ -12,8 +12,9 @@ Usage:
""" """
from django.utils.dates import MONTHS, MONTHS_AP, WEEKDAYS from django.utils.dates import MONTHS, MONTHS_AP, WEEKDAYS
from django.utils.tzinfo import LocalTimezone
from calendar import isleap from calendar import isleap
import re import re, time
re_formatchars = re.compile(r'(?<!\\)([aABdDfFgGhHiIjlLmMnNOPrsStTUwWyYzZ])') re_formatchars = re.compile(r'(?<!\\)([aABdDfFgGhHiIjlLmMnNOPrsStTUwWyYzZ])')
re_escaped = re.compile(r'\\(.)') re_escaped = re.compile(r'\\(.)')
@ -40,7 +41,9 @@ class TimeFormat(Formatter):
def A(self): def A(self):
"'AM' or 'PM'" "'AM' or 'PM'"
return self.a().upper() if self.data.hour > 11:
return 'PM'
return 'AM'
def B(self): def B(self):
"Swatch Internet time" "Swatch Internet time"
@ -100,8 +103,12 @@ class TimeFormat(Formatter):
class DateFormat(TimeFormat): class DateFormat(TimeFormat):
year_days = [None, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334] year_days = [None, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334]
def __init__(self, d): def __init__(self, dt):
self.data = d # Accepts either a datetime or date object.
self.data = dt
self.timezone = getattr(dt, 'tzinfo', None)
if hasattr(self.data, 'hour') and not self.timezone:
self.timezone = LocalTimezone(dt)
def d(self): def d(self):
"Day of the month, 2 digits with leading zeros; i.e. '01' to '31'" "Day of the month, 2 digits with leading zeros; i.e. '01' to '31'"
@ -119,6 +126,13 @@ class DateFormat(TimeFormat):
"'1' if Daylight Savings Time, '0' otherwise." "'1' if Daylight Savings Time, '0' otherwise."
raise NotImplementedError raise NotImplementedError
def I(self):
"'1' if Daylight Savings Time, '0' otherwise."
if self.timezone.dst(self.data):
return '1'
else:
return '0'
def j(self): def j(self):
"Day of the month without leading zeros; i.e. '1' to '31'" "Day of the month without leading zeros; i.e. '1' to '31'"
return self.data.day return self.data.day
@ -149,11 +163,12 @@ class DateFormat(TimeFormat):
def O(self): def O(self):
"Difference to Greenwich time in hours; e.g. '+0200'" "Difference to Greenwich time in hours; e.g. '+0200'"
raise NotImplementedError tz = self.timezone.utcoffset(self.data)
return "%+03d%02d" % (tz.seconds // 3600, (tz.seconds // 60) % 60)
def r(self): def r(self):
"RFC 822 formatted date; e.g. 'Thu, 21 Dec 2000 16:01:07 +0200'" "RFC 822 formatted date; e.g. 'Thu, 21 Dec 2000 16:01:07 +0200'"
raise NotImplementedError return self.format('D, j M Y H:i:s O')
def S(self): def S(self):
"English ordinal suffix for the day of the month, 2 characters; i.e. 'st', 'nd', 'rd' or 'th'" "English ordinal suffix for the day of the month, 2 characters; i.e. 'st', 'nd', 'rd' or 'th'"
@ -174,11 +189,15 @@ class DateFormat(TimeFormat):
def T(self): def T(self):
"Time zone of this machine; e.g. 'EST' or 'MDT'" "Time zone of this machine; e.g. 'EST' or 'MDT'"
raise NotImplementedError name = self.timezone.tzname(self.data)
if name is None:
name = self.format('O')
return name
def U(self): def U(self):
"Seconds since the Unix epoch (January 1 1970 00:00:00 GMT)" "Seconds since the Unix epoch (January 1 1970 00:00:00 GMT)"
raise NotImplementedError off = self.timezone.utcoffset(self.data)
return int(time.mktime(self.data.timetuple())) + off.seconds * 60
def w(self): def w(self):
"Day of the week, numeric, i.e. '0' (Sunday) to '6' (Saturday)" "Day of the week, numeric, i.e. '0' (Sunday) to '6' (Saturday)"
@ -229,7 +248,7 @@ class DateFormat(TimeFormat):
"""Time zone offset in seconds (i.e. '-43200' to '43200'). The offset """Time zone offset in seconds (i.e. '-43200' to '43200'). The offset
for timezones west of UTC is always negative, and for those east of UTC for timezones west of UTC is always negative, and for those east of UTC
is always positive.""" is always positive."""
raise NotImplementedError return self.timezone.utcoffset(self.data).seconds
def format(value, format_string): def format(value, format_string):
"Convenience function" "Convenience function"

View File

@ -1,4 +1,5 @@
import time, math, datetime import datetime, math, time
from django.utils.tzinfo import LocalTimezone
def timesince(d, now=None): def timesince(d, now=None):
""" """
@ -6,7 +7,6 @@ def timesince(d, now=None):
as a nicely formatted string, e.g "10 minutes" as a nicely formatted string, e.g "10 minutes"
Adapted from http://blog.natbat.co.uk/archive/2003/Jun/14/time_since Adapted from http://blog.natbat.co.uk/archive/2003/Jun/14/time_since
""" """
original = time.mktime(d.timetuple())
chunks = ( chunks = (
(60 * 60 * 24 * 365, 'year'), (60 * 60 * 24 * 365, 'year'),
(60 * 60 * 24 * 30, 'month'), (60 * 60 * 24 * 30, 'month'),
@ -14,9 +14,17 @@ def timesince(d, now=None):
(60 * 60, 'hour'), (60 * 60, 'hour'),
(60, 'minute') (60, 'minute')
) )
if not now: if now:
now = time.time() t = time.mktime(now)
since = now - original else:
t = time.localtime()
if d.tzinfo:
tz = LocalTimezone()
else:
tz = None
now = datetime.datetime(t[0], t[1], t[2], t[3], t[4], t[5], tzinfo=tz)
delta = now - d
since = delta.days * 24 * 60 * 60 + delta.seconds
# Crazy iteration syntax because we need i to be current index # Crazy iteration syntax because we need i to be current index
for i, (seconds, name) in zip(range(len(chunks)), chunks): for i, (seconds, name) in zip(range(len(chunks)), chunks):
count = math.floor(since / seconds) count = math.floor(since / seconds)

52
django/utils/tzinfo.py Normal file
View File

@ -0,0 +1,52 @@
"Implementation of tzinfo classes for use with datetime.datetime."
import time
from datetime import timedelta, tzinfo
class FixedOffset(tzinfo):
"Fixed offset in minutes east from UTC."
def __init__(self, offset):
self.__offset = timedelta(minutes=offset)
self.__name = "%+03d%02d" % (offset // 60, offset % 60)
def __repr__(self):
return self.__name
def utcoffset(self, dt):
return self.__offset
def tzname(self, dt):
return self.__name
def dst(self, dt):
return timedelta(0)
class LocalTimezone(tzinfo):
"Proxy timezone information from time module."
def __init__(self, dt):
tzinfo.__init__(self, dt)
self._tzname = time.tzname[self._isdst(dt)]
def __repr__(self):
return self._tzname
def utcoffset(self, dt):
if self._isdst(dt):
return timedelta(seconds=-time.altzone)
else:
return timedelta(seconds=-time.timezone)
def dst(self, dt):
if self._isdst(dt):
return timedelta(seconds=-time.altzone) - timedelta(seconds=-time.timezone)
else:
return timedelta(0)
def tzname(self, dt):
return time.tzname[self._isdst(dt)]
def _isdst(self, dt):
tt = (dt.year, dt.month, dt.day, dt.hour, dt.minute, dt.second, dt.weekday(), 0, -1)
stamp = time.mktime(tt)
tt = time.localtime(stamp)
return tt.tm_isdst > 0

View File

@ -1,12 +1,25 @@
def login_required(view_func): def user_passes_test(test_func):
"""
Decorator for views that checks that the user passes the given test,
redirecting to the log-in page if necessary. The test should be a callable
that takes the user object and returns True if the user passes.
"""
def _dec(view_func):
def _checklogin(request, *args, **kwargs):
from django.views.auth.login import redirect_to_login
if test_func(request.user):
return view_func(request, *args, **kwargs)
return redirect_to_login(request.path)
return _checklogin
return _dec
login_required = user_passes_test(lambda u: not u.is_anonymous())
login_required.__doc__ = (
""" """
Decorator for views that checks that the user is logged in, redirecting Decorator for views that checks that the user is logged in, redirecting
to the log-in page if necessary. to the log-in page if necessary.
""" """
from django.views.auth.login import redirect_to_login )
def _checklogin(request, *args, **kwargs):
if request.user.is_anonymous():
return redirect_to_login(request.path)
else:
return view_func(request, *args, **kwargs)
return _checklogin

288
docs/authentication.txt Normal file
View File

@ -0,0 +1,288 @@
=============================
User authentication in Django
=============================
Django comes with a user authentication system. It handles user accounts,
groups, permissions and cookie-based user sessions. This document explains how
things work.
The basics
==========
Django supports authentication out of the box. The ``django-admin.py init``
command, used to initialize a database with Django's core database tables,
creates the infrastructure for the auth system. You don't have to do anything
else to use authentication.
The auth system consists of:
* Users
* Permissions: Binary (yes/no) flags designating whether a user may perform
a certain task.
* Groups: A generic way of applying labels and permissions to more than one
user.
* Messages: A simple way to queue messages for given users.
Users
=====
Users are represented by a standard Django model, which lives in
`django/models/auth.py`_.
.. _django/models/auth.py: http://code.djangoproject.com/browser/django/trunk/django/models/auth.py
API reference
-------------
Fields
~~~~~~
``User`` objects have the following fields:
* ``username`` -- Required. 30 characters or fewer. Alphanumeric characters
only (letters, digits and underscores).
* ``first_name`` -- Optional. 30 characters or fewer.
* ``last_name`` -- Optional. 30 characters or fewer.
* ``email`` -- Optional. E-mail address.
* ``password_md5`` -- Required. An MD5 hash of the password. (Django
doesn't store the raw password.) Raw passwords can be arbitrarily long
and can contain any character.
* ``is_staff`` -- Boolean. Designates whether this user can access the
admin site.
* ``is_active`` -- Boolean. Designates whether this user account is valid.
Set this to ``False`` instead of deleting accounts.
* ``is_superuser`` -- Boolean. Designates whether this user has permission
to do anything (according to the permission system).
* ``last_login`` -- A datetime of the user's last login. Is set to the
current date/time by default.
* ``date_joined`` -- A datetime designating when the account was created.
Is set to the current date/time by default when the account is created.
Methods
~~~~~~~
``User`` objects have two many-to-many fields: ``groups`` and
``user_permissions``. Because of those relationships, ``User`` objects get
data-access methods like any other `Django model`_:
* ``get_group_list(**kwargs)``
* ``set_groups(id_list)``
* ``get_permission_list(**kwargs)``
* ``set_user_permissions(id_list)``
In addition to those automatic API methods, ``User`` objects have the following
methods:
* ``is_anonymous()`` -- Always returns ``False``. This is a way of
comparing ``User`` objects to anonymous users.
* ``get_full_name()`` -- Returns the ``first_name`` plus the ``last_name``,
with a space in between.
* ``set_password(raw_password)`` -- Sets the user's password to the given
raw string, taking care of the MD5 hashing. Doesn't save the ``User``
object.
* ``check_password(raw_password)`` -- Returns ``True`` if the given raw
string is the correct password for the user.
* ``get_group_permissions()`` -- Returns a list of permission strings that
the user has, through his/her groups.
* ``get_all_permissions()`` -- Returns a list of permission strings that
the user has, both through group and user permissions.
* ``has_perm(perm)`` -- Returns ``True`` if the user has the specified
permission.
* ``has_perms(perm_list)`` -- Returns ``True`` if the user has each of the
specified permissions.
* ``has_module_perms(package_name)`` -- Returns ``True`` if the user has
any permissions in the given package (the Django app label).
* ``get_and_delete_messages()`` -- Returns a list of ``Message`` objects in
the user's queue and deletes the messages from the queue.
* ``email_user(subject, message, from_email=None)`` -- Sends an e-mail to
the user. If ``from_email`` is ``None``, Django uses the
`DEFAULT_FROM_EMAIL`_ setting.
* ``get_profile()`` -- Returns a site-specific profile for this user.
Raises ``django.models.auth.SiteProfileNotAvailable`` if the current site
doesn't allow profiles.
.. _Django model: http://www.djangoproject.com/documentation/model_api/
.. _DEFAULT_FROM_EMAIL: http://www.djangoproject.com/documentation/settings/#default-from-email
Module functions
~~~~~~~~~~~~~~~~
The ``django.models.auth.users`` module has the following helper functions:
* ``create_user(username, email, password)`` -- Creates, saves and returns
a ``User``. The ``username``, ``email`` and ``password`` are set as
given, and the ``User`` gets ``is_active=True``.
* ``make_random_password(length=10, allowed_chars='abcdefghjkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789')``
-- Returns a random password with the given length and given string of
allowed characters. (Note that the default value of ``allowed_chars``
doesn't contain ``"I"`` or letters that look like it, to avoid user
confusion.
Basic usage
-----------
Creating users
~~~~~~~~~~~~~~
The most basic way to create users is to use the standard Django
`database API`_. Just create and save a ``User`` object::
>>> from django.models.auth import users
>>> import md5
>>> p = md5.new('johnpassword').hexdigest()
>>> u = users.User(username='john', first_name='John', last_name='lennon',
... email='lennon@thebeatles.com', password_md5=p, is_staff=True,
... is_active=True, is_superuser=False)
>>> u.save()
Note that ``password_md5`` requires the raw MD5 hash. Because that's a pain,
there's a ``create_user`` helper function::
>>> from django.models.auth import users
>>> u = users.create_user('john', 'lennon@thebeatles.com', 'johnpassword')
.. _database API: http://www.djangoproject.com/documentation/db_api/
Changing passwords
~~~~~~~~~~~~~~~~~~
Change a password with ``set_password()``::
>>> from django.models.auth import users
>>> u = users.get_object(username__exact='john')
>>> u.set_password('new password')
>>> u.save()
Anonymous users
---------------
``django.parts.auth.anonymoususers.AnonymousUser`` is a class that implements
the ``django.models.auth.users.User`` interface, with these differences:
* ``is_anonymous()`` returns ``True`` instead of ``False``.
* ``has_perm()`` always returns ``False``.
* ``set_password()``, ``check_password()``, ``set_groups()`` and
``set_permissions()`` raise ``NotImplementedError``.
In practice, you probably won't need to use ``AnonymousUser`` objects on your
own, but they're used by Web requests, as explained in the next section.
Authentication in Web requests
==============================
Until now, this document has dealt with the low-level APIs for manipulating
authentication-related objects. On a higher level, Django hooks this
authentication framework into its system of `request objects`_.
In any Django view, ``request.user`` will give you a ``User`` object
representing the currently logged-in user. If a user isn't currently logged in,
``request.user`` will be set to an instance of ``AnonymousUser`` (see the
previous section). You can tell them apart with ``is_anonymous()``, like so::
if request.user.is_anonymous():
# Do something for anonymous users.
else:
# Do something for logged-in users.
.. _request objects: http://www.djangoproject.com/documentation/request_response/#httprequest-objects
Limiting access to logged-in users
----------------------------------
The raw way
~~~~~~~~~~~
The simple, raw way to limit access to pages is to check
``request.user.is_anonymous()`` and either redirect to a login page::
from django.utils.httpwrappers import HttpResponseRedirect
def my_view(request):
if request.user.is_anonymous():
return HttpResponseRedirect('/login/?next=%s' % request.path)
# ...
...or display an error message::
def my_view(request):
if request.user.is_anonymous():
return render_to_response('myapp/login_error')
# ...
The login_required decorator
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
As a shortcut, you can use the convenient ``login_required`` decorator::
from django.views.decorators.auth import login_required
def my_view(request):
# ...
my_view = login_required(my_view)
Here's the same thing, using Python 2.4's decorator syntax::
from django.views.decorators.auth import login_required
@login_required
def my_view(request):
# ...
``login_required`` does the following:
* If the user isn't logged in, redirect to ``/accounts/login/``, passing
the current absolute URL in the query string as ``next``. For example:
``/accounts/login/?next=/polls/3/``.
* If the user is logged in, execute the view normally. The view code is
free to assume the user is logged in.
Limiting access to logged-in users that pass a test
---------------------------------------------------
To limit access based on certain permissions or another test, you'd do the same
thing as described in the previous section.
The simple way is to run your test on ``request.user`` in the view directly.
For example, this view checks to make sure the user is logged in and has the
permission ``polls.can_vote``::
def my_view(request):
if request.user.is_anonymous() or not request.user.has_perm('polls.can_vote'):
return HttpResponse("You can't vote in this poll.")
# ...
As a shortcut, you can use the convenient ``user_passes_test`` decorator::
from django.views.decorators.auth import user_passes_test
@user_passes_test(lambda u: u.has_perm('polls.can_vote'))
def my_view(request):
# ...
``user_passes_test`` takes a required argument: a callable that takes a
``User`` object and returns ``True`` if the user is allowed to view the page.
Note that ``user_passes_test`` does not automatically check that the ``User``
is not anonymous.
Permissions
===========
Groups
======
Messages
========

View File

@ -517,18 +517,18 @@ Built-in tag reference
n Month without leading zeros. ``'1'`` to ``'12'`` n Month without leading zeros. ``'1'`` to ``'12'``
N Month abbreviation in Associated Press ``'Jan.'``, ``'Feb.'``, ``'March'``, ``'May'`` N Month abbreviation in Associated Press ``'Jan.'``, ``'Feb.'``, ``'March'``, ``'May'``
style. Proprietary extension. style. Proprietary extension.
O Not implemented. O Difference to Greenwich time in hours. ``'+0200'``
P Time, in 12-hour hours, minutes and ``'1 a.m.'``, ``'1:30 p.m.'``, ``'midnight'``, ``'noon'``, ``'12:30 p.m.'`` P Time, in 12-hour hours, minutes and ``'1 a.m.'``, ``'1:30 p.m.'``, ``'midnight'``, ``'noon'``, ``'12:30 p.m.'``
'a.m.'/'p.m.', with minutes left off 'a.m.'/'p.m.', with minutes left off
if they're zero and the special-case if they're zero and the special-case
strings 'midnight' and 'noon' if strings 'midnight' and 'noon' if
appropriate. Proprietary extension. appropriate. Proprietary extension.
r Not implemented. r RFC 822 formatted date. ``'Thu, 21 Dec 2000 16:01:07 +0200'``
s Seconds, 2 digits with leading zeros. ``'00'`` to ``'59'`` s Seconds, 2 digits with leading zeros. ``'00'`` to ``'59'``
S English ordinal suffix for day of the ``'st'``, ``'nd'``, ``'rd'`` or ``'th'`` S English ordinal suffix for day of the ``'st'``, ``'nd'``, ``'rd'`` or ``'th'``
month, 2 characters. month, 2 characters.
t Not implemented. t Not implemented.
T Not implemented. T Time zone of this machine. ``'EST'``, ``'MDT'``
U Not implemented. U Not implemented.
w Day of the week, digits without ``'0'`` (Sunday) to ``'6'`` (Saturday) w Day of the week, digits without ``'0'`` (Sunday) to ``'6'`` (Saturday)
leading zeros. leading zeros.
@ -537,7 +537,10 @@ Built-in tag reference
y Year, 2 digits. ``'99'`` y Year, 2 digits. ``'99'``
Y Year, 4 digits. ``'1999'`` Y Year, 4 digits. ``'1999'``
z Day of the year. ``0`` to ``365`` z Day of the year. ``0`` to ``365``
Z Not implemented. Z Time zone offset in seconds. The ``-43200`` to ``43200``
offset for timezones west of UTC is
always negative, and for those east of
UTC is always positive.
================ ====================================== ===================== ================ ====================================== =====================
Example:: Example::

View File

@ -0,0 +1,75 @@
"""
>>> format(my_birthday, '')
''
>>> format(my_birthday, 'a')
'p.m.'
>>> format(my_birthday, 'A')
'PM'
>>> format(my_birthday, 'j')
'7'
>>> format(my_birthday, 'l')
'Saturday'
>>> format(my_birthday, 'L')
'False'
>>> format(my_birthday, 'm')
'07'
>>> format(my_birthday, 'M')
'Jul'
>>> format(my_birthday, 'n')
'7'
>>> format(my_birthday, 'N')
'July'
>>> format(my_birthday, 'O')
'+0100'
>>> format(my_birthday, 'P')
'10 p.m.'
>>> format(my_birthday, 'r')
'Sat, 7 Jul 1979 22:00:00 +0100'
>>> format(my_birthday, 's')
'00'
>>> format(my_birthday, 'S')
'th'
>>> format(my_birthday, 't')
Traceback (most recent call last):
...
NotImplementedError
>>> format(my_birthday, 'T')
'CET'
>>> format(my_birthday, 'U')
'300445200'
>>> format(my_birthday, 'w')
'6'
>>> format(my_birthday, 'W')
'27'
>>> format(my_birthday, 'y')
'79'
>>> format(my_birthday, 'Y')
'1979'
>>> format(my_birthday, 'z')
'188'
>>> format(my_birthday, 'Z')
'3600'
>>> format(summertime, 'I')
'1'
>>> format(summertime, 'O')
'+0200'
>>> format(wintertime, 'I')
'0'
>>> format(wintertime, 'O')
'+0100'
>>> format(my_birthday, 'Y z \\C\\E\\T')
'1979 188 CET'
"""
from django.utils import dateformat
format = dateformat.format
import datetime, os, time
os.environ['TZ'] = 'Europe/Copenhagen'
time.tzset()
my_birthday = datetime.datetime(1979, 7, 7, 22, 00)
summertime = datetime.datetime(2005, 10, 30, 1, 00)
wintertime = datetime.datetime(2005, 10, 30, 4, 00)

View File

@ -53,6 +53,8 @@ EmployeeDoesNotExist: Employee does not exist for {'pk': 'foo'}
>>> fran.save() >>> fran.save()
>>> employees.get_list(last_name__exact='Jones') >>> employees.get_list(last_name__exact='Jones')
[Dan Jones, Fran Jones] [Dan Jones, Fran Jones]
>>> employees.get_in_bulk(['ABC123', 'XYZ456'])
{'XYZ456': Fran Jones, 'ABC123': Dan Jones}
>>> b = businesses.Business(name='Sears') >>> b = businesses.Business(name='Sears')
>>> b.save() >>> b.save()
@ -62,4 +64,6 @@ True
[Dan Jones, Fran Jones] [Dan Jones, Fran Jones]
>>> fran.get_business_list() >>> fran.get_business_list()
[Sears] [Sears]
>>> businesses.get_in_bulk(['Sears'])
{'Sears': Sears}
""" """