Merge remote-tracking branch 'upstream/develop' into list_filter

Conflicts:
	djadmin2/views.py
This commit is contained in:
Michal Kuffa 2013-07-06 16:22:14 +02:00
commit d433013fcc
58 changed files with 2133 additions and 176 deletions

15
.coveragerc Normal file
View file

@ -0,0 +1,15 @@
[report]
# Regexes for lines to exclude from consideration
exclude_lines =
# Don't complain about missing debug-only code:
def __repr__
if self\.debug
# Don't complain if tests don't hit defensive assertion code:
raise AssertionError
raise NotImplementedError
# Don't complain if non-runnable code isn't run:
if 0:
if False:
if __name__ == .__main__.:

1
.gitignore vendored
View file

@ -42,7 +42,6 @@ coverage
# Sphinx
docs/_build
docs/_static
# Launchpad
lp-cache

View file

@ -8,3 +8,6 @@ install:
- pip install -r requirements.txt
script:
- python runtests.py
after_script:
- pip install --quiet --use-mirrors coveralls
- coveralls

View file

@ -1,12 +1,19 @@
CONTRIBUTORS
============
Project Lead
===============
------------
* Daniel Greenfeld (@pydanny / <pydanny@gmail.com>)
Translation Managers
--------------------
* Henri Colas (@NotSqrt)
* Danilo Bargen (@dbrgn)
Developers
=============
----------
* Audrey Roy (@audreyr)
* Peter Ingelsby (@inglesp)
@ -29,3 +36,15 @@ Developers
* Ryan Balfanz (@RyanBalfanz / <ryan@ryanbalfanz.net>)
* Tom Christie (@tomchristie)
* Chris Jones (@chrisjones-brack3t / <chris@brack3t.com>)
* Danilo Bargen (@dbrgn)
* Ignasi Fosch Alonso (@ifosch)
* Henri Colas (@NotSqrt)
* Andy Boot (@bootandy)
Translators
-----------
* Henri Colas (@NotSqrt)
* Danilo Bargen (@dbrgn)
* Ignasi Fosch Alonso (@ifosch)
* Margherita Zamponi (@Margherita-)

View file

@ -5,6 +5,9 @@ django-admin2
.. image:: https://travis-ci.org/pydanny/django-admin2.png
:alt: Build Status
:target: https://travis-ci.org/pydanny/django-admin2
.. image:: https://coveralls.io/repos/twoscoops/django-admin2/badge.png
:alt: Coverage Status
:target: https://coveralls.io/r/twoscoops/django-admin2
One of the most useful parts of ``django.contrib.admin`` is the ability to configure various views that touch and alter data. django-admin2 is a complete rewrite of that library using modern Class-Based Views and enjoying a design focused on extendibility and adaptability. By starting over, we can avoid the legacy code and make it easier to write extensions and themes.
@ -52,6 +55,7 @@ Requirements
Installation
============
Use pip to install from PyPI:
.. code-block:: python
@ -75,9 +79,9 @@ Add djadmin2 urls to your URLconf:
# urls.py
from django.conf.urls import patterns, include
import djadmin2
djadmin2.default.autodiscover()
@ -85,9 +89,6 @@ Add djadmin2 urls to your URLconf:
...
url(r'^admin2/', include(djadmin2.default.urls)),
)
How to write django-admin2 modules
@ -125,16 +126,16 @@ The default theme is whatever bootstrap is most current. Specifically:
.. code-block:: python
# settings.py
ADMIN2_THEME_DIRECTORY = "admin2/bootstrap/"
ADMIN2_THEME_DIRECTORY = "djadmin2/bootstrap/"
If you create a new theme, you define it thus:
.. code-block:: python
# settings.py
ADMIN2_THEME_DIRECTORY = "admin2/foundation/"
ADMIN2_THEME_DIRECTORY = "djadmin2/foundation/"
History
=========
@ -143,7 +144,7 @@ History
* Implemented both Function- and Class-based Action views
* Implemented ModelAdmin2.list_display
* Implemented ModelAdmin2.fieldsets
* Implemented ModelAdmin2.fieldsets
* Dropdown widget now displays the selected choice
* Added support for callables in ModelAdmin2.list_display
* Added screenshots to README

View file

@ -11,8 +11,10 @@ from .viewmixins import AdminModel2Mixin
def get_description(action):
if hasattr(action, 'description'):
# This is for classes
return action.description
else:
# This if for functions
return capfirst(action.__name__.replace('_', ' '))
@ -20,8 +22,11 @@ class BaseListAction(AdminModel2Mixin, TemplateView):
permission_classes = (permissions.IsStaffPermission,)
empty_message = 'Items must be selected in order to perform actions on them. No items have been changed.'
success_message = 'Successfully deleted %d %s'
empty_message = ugettext_lazy(
'Items must be selected in order to perform actions '
'on them. No items have been changed.'
)
success_message = ugettext_lazy('Successfully deleted %(count)s %(items)s')
queryset = None
@ -95,19 +100,21 @@ class BaseListAction(AdminModel2Mixin, TemplateView):
if request.POST.get('confirmed'):
if self.process_queryset() is None:
message = _(self.success_message % (
self.item_count, self.objects_name)
)
message = self.success_message % {
'count': self.item_count, 'items': self.objects_name
}
messages.add_message(request, messages.INFO, message)
return None
else:
# The user has not confirmed that they want to delete the objects, so
# render a template asking for their confirmation.
# The user has not confirmed that they want to delete the
# objects, so render a template asking for their confirmation.
return self.get(request)
def process_queryset(self):
raise NotImplementedError('Must be provided to do some actions with queryset')
raise NotImplementedError(
'Must be provided to do some actions with queryset'
)
class DeleteSelectedAction(BaseListAction):

View file

@ -124,7 +124,7 @@ class Admin2(object):
url(regex=r'^$',
view=self.index_view.as_view(**self.get_index_kwargs()),
name='dashboard'
),
),
url(regex='^auth/user/(?P<pk>\d+)/update/password/$',
view=views.PasswordChangeView.as_view(),
name='password_change'
@ -137,16 +137,14 @@ class Admin2(object):
view=views.LogoutView.as_view(),
name='logout'
),
url(
regex=r'^(?P<app_label>\w+)/$',
url(regex=r'^(?P<app_label>\w+)/$',
view=self.app_index_view.as_view(**self.get_app_index_kwargs()),
name='app_index'
),
url(
regex=r'^api/v0/$',
),
url(regex=r'^api/v0/$',
view=self.api_index_view.as_view(**self.get_api_index_kwargs()),
name='api_index'
),
),
)
for model, model_admin in self.registry.iteritems():

View file

@ -2,9 +2,8 @@ from __future__ import unicode_literals
from copy import deepcopy
from django.contrib.auth import authenticate
from django.contrib.auth.forms import (
AuthenticationForm, UserCreationForm, UserChangeForm
)
from django.contrib.auth.forms import AuthenticationForm
from django.contrib.auth.forms import UserCreationForm, UserChangeForm
import django.forms
import django.forms.models
import django.forms.extras.widgets
@ -225,7 +224,7 @@ def floppify_form(form_class):
def modelform_factory(model, form=django.forms.models.ModelForm, fields=None,
exclude=None, formfield_callback=None, widgets=None):
exclude=None, formfield_callback=None, widgets=None):
form_class = django.forms.models.modelform_factory(
model=model,
form=form,
@ -246,8 +245,11 @@ class AdminAuthenticationForm(AuthenticationForm):
Liberally copied from django.contrib.admin.forms.AdminAuthenticationForm
"""
this_is_the_login_form = django.forms.BooleanField(widget=floppyforms.HiddenInput, initial=1,
error_messages={'required': ugettext_lazy("Please log in again, because your session has expired.")})
error_messages = {
'required': ugettext_lazy("Please log in again, because your session has expired."),
}
this_is_the_login_form = django.forms.BooleanField(widget=floppyforms.HiddenInput,
initial=1, error_messages=error_messages)
def clean(self):
username = self.cleaned_data.get('username')

View file

@ -0,0 +1,226 @@
# This file is distributed under the same license as the django-admin2 package.
#
# Translators:
# Ignasi Fosch Alonso <natx@y10k.ws>, 2013.
msgid ""
msgstr ""
"Project-Id-Version: django-admin2\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2013-07-06 15:02+0200\n"
"PO-Revision-Date: 2013-07-06 14:47+0200\n"
"Last-Translator: Ignasi Fosch Alonso <natx@y10k.ws>\n"
"Language-Team: https://www.transifex.com/projects/p/django-admin2/language/"
"ca/\n"
"Language: ca\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#: actions.py:26
msgid ""
"Items must be selected in order to perform actions on them. No items have "
"been changed."
msgstr ""
#: actions.py:29
#, python-format
msgid "Successfully deleted %(count)s %(items)s"
msgstr ""
#: actions.py:127
msgid "Delete selected items"
msgstr ""
#: forms.py:238
#, python-format
msgid ""
"Please enter the correct %(username)s and password for a staff account. Note "
"that both fields may be case-sensitive."
msgstr ""
#: forms.py:249
msgid "Please log in again, because your session has expired."
msgstr ""
#: views.py:165 templates/admin2/bootstrap/model_update_form.html:29
#: templates/admin2/bootstrap/includes/app_model_list.html:38
msgid "Change"
msgstr ""
#: views.py:179 templates/admin2/bootstrap/includes/app_model_list.html:30
msgid "Add"
msgstr ""
#: templates/admin2/bootstrap/app_index.html:6
#: templates/admin2/bootstrap/base.html:55
#: templates/admin2/bootstrap/model_confirm_delete.html:10
#: templates/admin2/bootstrap/model_detail.html:11
#: templates/admin2/bootstrap/model_list.html:14
#: templates/admin2/bootstrap/model_update_form.html:11
#: templates/admin2/bootstrap/actions/delete_selected_confirmation.html:10
#: templates/admin2/bootstrap/auth/logout.html:8
#: templates/admin2/bootstrap/auth/password_change_done.html:11
#: templates/admin2/bootstrap/auth/password_change_form.html:10
msgid "Home"
msgstr ""
#: templates/admin2/bootstrap/app_index.html:12
#, python-format
msgid "%(app_label)s administration"
msgstr ""
#: templates/admin2/bootstrap/base.html:6
#: templates/admin2/bootstrap/base.html:71
#: templates/admin2/bootstrap/auth/login.html:15
msgid "Site administration"
msgstr ""
#: templates/admin2/bootstrap/base.html:22
msgid "API"
msgstr ""
#: templates/admin2/bootstrap/base.html:25
msgid "Documentation"
msgstr ""
#: templates/admin2/bootstrap/base.html:34
#, python-format
msgid "Logged in as %(user)s"
msgstr ""
#: templates/admin2/bootstrap/base.html:40
msgid "Change password"
msgstr ""
#: templates/admin2/bootstrap/base.html:42
#: templates/admin2/bootstrap/auth/logout.html:11
msgid "Log out"
msgstr ""
#: templates/admin2/bootstrap/index.html:13
msgid "Recent Actions"
msgstr ""
#: templates/admin2/bootstrap/index.html:14
msgid "My Actions"
msgstr ""
#: templates/admin2/bootstrap/model_confirm_delete.html:4
#: templates/admin2/bootstrap/model_confirm_delete.html:6
#: templates/admin2/bootstrap/actions/delete_selected_confirmation.html:4
#: templates/admin2/bootstrap/actions/delete_selected_confirmation.html:6
msgid "Are you sure?"
msgstr ""
#: templates/admin2/bootstrap/model_confirm_delete.html:25
#: templates/admin2/bootstrap/model_update_form.html:74
#: templates/admin2/bootstrap/actions/delete_selected_confirmation.html:21
msgid "Delete"
msgstr ""
#: templates/admin2/bootstrap/model_confirm_delete.html:30
#, python-format
msgid ""
"Are you sure you want to delete the %(model_name)s \"%(object)s\"? All of "
"the following items will be deleted:"
msgstr ""
#: templates/admin2/bootstrap/model_confirm_delete.html:40
#: templates/admin2/bootstrap/actions/delete_selected_confirmation.html:40
msgid "Yes, I'm sure"
msgstr ""
#: templates/admin2/bootstrap/model_list.html:4
#: templates/admin2/bootstrap/model_list.html:6
#, python-format
msgid "Select %(model_name)s to change"
msgstr ""
#: templates/admin2/bootstrap/model_list.html:31
msgid "Search Term"
msgstr ""
#: templates/admin2/bootstrap/model_list.html:32
msgid "Search"
msgstr ""
#: templates/admin2/bootstrap/model_list.html:59
#, python-format
msgid "%(selected)s of %(total)s selected"
msgstr ""
#: templates/admin2/bootstrap/model_list.html:63
#, python-format
msgid "Add %(model_verbose_name)s"
msgstr ""
#: templates/admin2/bootstrap/model_update_form.html:5
#: templates/admin2/bootstrap/model_update_form.html:7
#, python-format
msgid "%(action)s %(model_name)s"
msgstr ""
#: templates/admin2/bootstrap/model_update_form.html:78
msgid "Save and add another"
msgstr ""
#: templates/admin2/bootstrap/model_update_form.html:79
msgid "Save and continue editing"
msgstr ""
#: templates/admin2/bootstrap/model_update_form.html:80
msgid "Save"
msgstr ""
#: templates/admin2/bootstrap/actions/delete_selected_confirmation.html:27
#, python-format
msgid ""
"Are you sure you want to delete the selected %(objects_name)s? All of the "
"following items will be deleted:"
msgstr ""
#: templates/admin2/bootstrap/auth/login.html:15
#: templates/admin2/bootstrap/auth/login.html:52
msgid "Log in"
msgstr ""
#: templates/admin2/bootstrap/auth/login.html:27
#: templates/admin2/bootstrap/auth/password_change_form.html:24
msgid "Please correct the error below."
msgid_plural "Please correct the errors below."
msgstr[0] ""
msgstr[1] ""
#: templates/admin2/bootstrap/auth/logout.html:17
msgid "Thanks for spending some quality time with the Web site today."
msgstr ""
#: templates/admin2/bootstrap/auth/logout.html:18
msgid "Log in again"
msgstr ""
#: templates/admin2/bootstrap/auth/password_change_done.html:6
#: templates/admin2/bootstrap/auth/password_change_done.html:7
#: templates/admin2/bootstrap/auth/password_change_done.html:14
msgid "Password change successful"
msgstr ""
#: templates/admin2/bootstrap/auth/password_change_done.html:20
msgid "Your password was changed."
msgstr ""
#: templates/admin2/bootstrap/auth/password_change_form.html:6
#: templates/admin2/bootstrap/auth/password_change_form.html:13
msgid "Password change"
msgstr ""
#: templates/admin2/bootstrap/auth/password_change_form.html:20
msgid ""
"Please enter your old password, for security's sake, and then enter your new "
"password twice so we can verify you typed it in correctly."
msgstr ""
#: templates/admin2/bootstrap/auth/password_change_form.html:31
msgid "Change my password"
msgstr ""

View file

@ -0,0 +1,226 @@
# This file is distributed under the same license as the django-admin2 package.
#
# Translators:
# Danilo Bargen <gezuru@gmail.com>, 2013.
msgid ""
msgstr ""
"Project-Id-Version: django-admin2\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2013-07-06 15:02+0200\n"
"PO-Revision-Date: 2013-07-06 14:47+0200\n"
"Last-Translator: Danilo Bargen <gezuru@gmail.com>\n"
"Language-Team: https://www.transifex.com/projects/p/django-admin2/language/"
"de/\n"
"Language: de\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#: actions.py:26
msgid ""
"Items must be selected in order to perform actions on them. No items have "
"been changed."
msgstr ""
#: actions.py:29
#, python-format
msgid "Successfully deleted %(count)s %(items)s"
msgstr ""
#: actions.py:127
msgid "Delete selected items"
msgstr ""
#: forms.py:238
#, python-format
msgid ""
"Please enter the correct %(username)s and password for a staff account. Note "
"that both fields may be case-sensitive."
msgstr ""
#: forms.py:249
msgid "Please log in again, because your session has expired."
msgstr ""
#: views.py:165 templates/admin2/bootstrap/model_update_form.html:29
#: templates/admin2/bootstrap/includes/app_model_list.html:38
msgid "Change"
msgstr ""
#: views.py:179 templates/admin2/bootstrap/includes/app_model_list.html:30
msgid "Add"
msgstr ""
#: templates/admin2/bootstrap/app_index.html:6
#: templates/admin2/bootstrap/base.html:55
#: templates/admin2/bootstrap/model_confirm_delete.html:10
#: templates/admin2/bootstrap/model_detail.html:11
#: templates/admin2/bootstrap/model_list.html:14
#: templates/admin2/bootstrap/model_update_form.html:11
#: templates/admin2/bootstrap/actions/delete_selected_confirmation.html:10
#: templates/admin2/bootstrap/auth/logout.html:8
#: templates/admin2/bootstrap/auth/password_change_done.html:11
#: templates/admin2/bootstrap/auth/password_change_form.html:10
msgid "Home"
msgstr ""
#: templates/admin2/bootstrap/app_index.html:12
#, python-format
msgid "%(app_label)s administration"
msgstr ""
#: templates/admin2/bootstrap/base.html:6
#: templates/admin2/bootstrap/base.html:71
#: templates/admin2/bootstrap/auth/login.html:15
msgid "Site administration"
msgstr ""
#: templates/admin2/bootstrap/base.html:22
msgid "API"
msgstr ""
#: templates/admin2/bootstrap/base.html:25
msgid "Documentation"
msgstr ""
#: templates/admin2/bootstrap/base.html:34
#, python-format
msgid "Logged in as %(user)s"
msgstr ""
#: templates/admin2/bootstrap/base.html:40
msgid "Change password"
msgstr ""
#: templates/admin2/bootstrap/base.html:42
#: templates/admin2/bootstrap/auth/logout.html:11
msgid "Log out"
msgstr ""
#: templates/admin2/bootstrap/index.html:13
msgid "Recent Actions"
msgstr ""
#: templates/admin2/bootstrap/index.html:14
msgid "My Actions"
msgstr ""
#: templates/admin2/bootstrap/model_confirm_delete.html:4
#: templates/admin2/bootstrap/model_confirm_delete.html:6
#: templates/admin2/bootstrap/actions/delete_selected_confirmation.html:4
#: templates/admin2/bootstrap/actions/delete_selected_confirmation.html:6
msgid "Are you sure?"
msgstr ""
#: templates/admin2/bootstrap/model_confirm_delete.html:25
#: templates/admin2/bootstrap/model_update_form.html:74
#: templates/admin2/bootstrap/actions/delete_selected_confirmation.html:21
msgid "Delete"
msgstr ""
#: templates/admin2/bootstrap/model_confirm_delete.html:30
#, python-format
msgid ""
"Are you sure you want to delete the %(model_name)s \"%(object)s\"? All of "
"the following items will be deleted:"
msgstr ""
#: templates/admin2/bootstrap/model_confirm_delete.html:40
#: templates/admin2/bootstrap/actions/delete_selected_confirmation.html:40
msgid "Yes, I'm sure"
msgstr ""
#: templates/admin2/bootstrap/model_list.html:4
#: templates/admin2/bootstrap/model_list.html:6
#, python-format
msgid "Select %(model_name)s to change"
msgstr ""
#: templates/admin2/bootstrap/model_list.html:31
msgid "Search Term"
msgstr ""
#: templates/admin2/bootstrap/model_list.html:32
msgid "Search"
msgstr ""
#: templates/admin2/bootstrap/model_list.html:59
#, python-format
msgid "%(selected)s of %(total)s selected"
msgstr ""
#: templates/admin2/bootstrap/model_list.html:63
#, python-format
msgid "Add %(model_verbose_name)s"
msgstr ""
#: templates/admin2/bootstrap/model_update_form.html:5
#: templates/admin2/bootstrap/model_update_form.html:7
#, python-format
msgid "%(action)s %(model_name)s"
msgstr ""
#: templates/admin2/bootstrap/model_update_form.html:78
msgid "Save and add another"
msgstr ""
#: templates/admin2/bootstrap/model_update_form.html:79
msgid "Save and continue editing"
msgstr ""
#: templates/admin2/bootstrap/model_update_form.html:80
msgid "Save"
msgstr ""
#: templates/admin2/bootstrap/actions/delete_selected_confirmation.html:27
#, python-format
msgid ""
"Are you sure you want to delete the selected %(objects_name)s? All of the "
"following items will be deleted:"
msgstr ""
#: templates/admin2/bootstrap/auth/login.html:15
#: templates/admin2/bootstrap/auth/login.html:52
msgid "Log in"
msgstr ""
#: templates/admin2/bootstrap/auth/login.html:27
#: templates/admin2/bootstrap/auth/password_change_form.html:24
msgid "Please correct the error below."
msgid_plural "Please correct the errors below."
msgstr[0] ""
msgstr[1] ""
#: templates/admin2/bootstrap/auth/logout.html:17
msgid "Thanks for spending some quality time with the Web site today."
msgstr ""
#: templates/admin2/bootstrap/auth/logout.html:18
msgid "Log in again"
msgstr ""
#: templates/admin2/bootstrap/auth/password_change_done.html:6
#: templates/admin2/bootstrap/auth/password_change_done.html:7
#: templates/admin2/bootstrap/auth/password_change_done.html:14
msgid "Password change successful"
msgstr ""
#: templates/admin2/bootstrap/auth/password_change_done.html:20
msgid "Your password was changed."
msgstr ""
#: templates/admin2/bootstrap/auth/password_change_form.html:6
#: templates/admin2/bootstrap/auth/password_change_form.html:13
msgid "Password change"
msgstr ""
#: templates/admin2/bootstrap/auth/password_change_form.html:20
msgid ""
"Please enter your old password, for security's sake, and then enter your new "
"password twice so we can verify you typed it in correctly."
msgstr ""
#: templates/admin2/bootstrap/auth/password_change_form.html:31
msgid "Change my password"
msgstr ""

View file

@ -0,0 +1,240 @@
# This file is distributed under the same license as the django-admin2 package.
#
# Translators:
# NotSqrt <notsqrt@gmail.com>, 2013.
msgid ""
msgstr ""
"Project-Id-Version: django-admin2\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2013-07-06 15:02+0200\n"
"PO-Revision-Date: 2013-07-06 13:27+0200\n"
"Last-Translator: NotSqrt <notsqrt@gmail.com>\n"
"Language: en\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#: actions.py:26
msgid ""
"Items must be selected in order to perform actions on them. No items have "
"been changed."
msgstr ""
"Items must be selected in order to perform actions on them. No items have "
"been changed."
#: actions.py:29
#, python-format
msgid "Successfully deleted %(count)s %(items)s"
msgstr "Successfully deleted %(count)s %(items)s"
#: actions.py:127
msgid "Delete selected items"
msgstr "Delete selected items"
#: forms.py:238
#, python-format
msgid ""
"Please enter the correct %(username)s and password for a staff account. Note "
"that both fields may be case-sensitive."
msgstr ""
"Please enter the correct %(username)s and password for a staff account. Note "
"that both fields may be case-sensitive."
#: forms.py:249
msgid "Please log in again, because your session has expired."
msgstr "Please log in again, because your session has expired."
#: views.py:165 templates/djadmin2/bootstrap/model_update_form.html:29
#: templates/djadmin2/bootstrap/includes/app_model_list.html:38
msgid "Change"
msgstr "Change"
#: views.py:179 templates/djadmin2/bootstrap/includes/app_model_list.html:30
msgid "Add"
msgstr "Add"
#: templates/djadmin2/bootstrap/app_index.html:6
#: templates/djadmin2/bootstrap/base.html:55
#: templates/djadmin2/bootstrap/model_confirm_delete.html:10
#: templates/djadmin2/bootstrap/model_detail.html:11
#: templates/djadmin2/bootstrap/model_list.html:14
#: templates/djadmin2/bootstrap/model_update_form.html:11
#: templates/djadmin2/bootstrap/actions/delete_selected_confirmation.html:10
#: templates/djadmin2/bootstrap/auth/logout.html:8
#: templates/djadmin2/bootstrap/auth/password_change_done.html:11
#: templates/djadmin2/bootstrap/auth/password_change_form.html:10
msgid "Home"
msgstr "Home"
#: templates/djadmin2/bootstrap/app_index.html:12
#, python-format
msgid "%(app_label)s administration"
msgstr "%(app_label)s administration"
#: templates/djadmin2/bootstrap/base.html:6
#: templates/djadmin2/bootstrap/base.html:71
#: templates/djadmin2/bootstrap/auth/login.html:15
msgid "Site administration"
msgstr "Site administration"
#: templates/djadmin2/bootstrap/base.html:22
msgid "API"
msgstr "API"
#: templates/djadmin2/bootstrap/base.html:25
msgid "Documentation"
msgstr "Documentation"
#: templates/djadmin2/bootstrap/base.html:34
#, python-format
msgid "Logged in as %(user)s"
msgstr "Logged in as %(user)s"
#: templates/djadmin2/bootstrap/base.html:40
msgid "Change password"
msgstr "Change password"
#: templates/djadmin2/bootstrap/base.html:42
msgid "Log out"
msgstr "Log out"
#: templates/djadmin2/bootstrap/index.html:13
msgid "Recent Actions"
msgstr "Recent Actions"
#: templates/djadmin2/bootstrap/index.html:14
msgid "My Actions"
msgstr "My Actions"
#: templates/djadmin2/bootstrap/model_confirm_delete.html:4
#: templates/djadmin2/bootstrap/model_confirm_delete.html:6
#: templates/djadmin2/bootstrap/actions/delete_selected_confirmation.html:4
#: templates/djadmin2/bootstrap/actions/delete_selected_confirmation.html:6
msgid "Are you sure?"
msgstr "Are you sure?"
#: templates/djadmin2/bootstrap/model_confirm_delete.html:25
#: templates/djadmin2/bootstrap/model_update_form.html:74
#: templates/djadmin2/bootstrap/actions/delete_selected_confirmation.html:21
msgid "Delete"
msgstr "Delete"
#: templates/djadmin2/bootstrap/model_confirm_delete.html:30
#, python-format
msgid ""
"Are you sure you want to delete the %(model_name)s \"%(object)s\"? All of "
"the following items will be deleted:"
msgstr ""
"Are you sure you want to delete the %(model_name)s \"%(object)s\"? All of "
"the following items will be deleted:"
#: templates/djadmin2/bootstrap/model_confirm_delete.html:40
#: templates/djadmin2/bootstrap/actions/delete_selected_confirmation.html:40
msgid "Yes, I'm sure"
msgstr "Yes, I'm sure"
#: templates/djadmin2/bootstrap/model_list.html:4
#: templates/djadmin2/bootstrap/model_list.html:6
#, python-format
msgid "Select %(model_name)s to change"
msgstr "Select %(model_name)s to change"
#: templates/djadmin2/bootstrap/model_list.html:31
msgid "Search Term"
msgstr "Search Term"
#: templates/djadmin2/bootstrap/model_list.html:32
msgid "Search"
msgstr "Search"
#: templates/djadmin2/bootstrap/model_list.html:59
#, python-format
msgid "%(selected)s of %(total)s selected"
msgstr "%(selected)s of %(total)s selected"
#: templates/djadmin2/bootstrap/model_list.html:63
#, python-format
msgid "Add %(model_verbose_name)s"
msgstr "Add %(model_verbose_name)s"
#: templates/djadmin2/bootstrap/model_update_form.html:5
#: templates/djadmin2/bootstrap/model_update_form.html:7
#, python-format
msgid "%(action)s %(model_name)s"
msgstr "%(action)s %(model_name)s"
#: templates/djadmin2/bootstrap/model_update_form.html:78
msgid "Save and add another"
msgstr "Save and add another"
#: templates/djadmin2/bootstrap/model_update_form.html:79
msgid "Save and continue editing"
msgstr "Save and continue editing"
#: templates/djadmin2/bootstrap/model_update_form.html:80
msgid "Save"
msgstr "Save"
#: templates/djadmin2/bootstrap/actions/delete_selected_confirmation.html:27
#, python-format
msgid ""
"Are you sure you want to delete the selected %(objects_name)s? All of the "
"following items will be deleted:"
msgstr ""
"Are you sure you want to delete the selected %(objects_name)s? All of the "
"following items will be deleted:"
#: templates/djadmin2/bootstrap/auth/login.html:15
msgid "Login"
msgstr "Login"
#: templates/djadmin2/bootstrap/auth/login.html:27
#: templates/djadmin2/bootstrap/auth/password_change_form.html:24
msgid "Please correct the error below."
msgid_plural "Please correct the errors below."
msgstr[0] "Please correct the error below."
msgstr[1] "Please correct the errors below."
#: templates/djadmin2/bootstrap/auth/login.html:52
msgid "Log in"
msgstr "Log in"
#: templates/djadmin2/bootstrap/auth/logout.html:11
msgid "Logout"
msgstr "Logout"
#: templates/djadmin2/bootstrap/auth/logout.html:17
msgid "Thanks for spending some quality time with the Web site today."
msgstr "Thanks for spending some quality time with the Web site today."
#: templates/djadmin2/bootstrap/auth/logout.html:18
msgid "Log in again"
msgstr "Log in again"
#: templates/djadmin2/bootstrap/auth/password_change_done.html:6
#: templates/djadmin2/bootstrap/auth/password_change_done.html:7
#: templates/djadmin2/bootstrap/auth/password_change_done.html:14
msgid "Password change successful"
msgstr "Password change successful"
#: templates/djadmin2/bootstrap/auth/password_change_done.html:20
msgid "Your password was changed."
msgstr "Your password was changed."
#: templates/djadmin2/bootstrap/auth/password_change_form.html:6
#: templates/djadmin2/bootstrap/auth/password_change_form.html:13
msgid "Password change"
msgstr "Password change"
#: templates/djadmin2/bootstrap/auth/password_change_form.html:20
msgid ""
"Please enter your old password, for security's sake, and then enter your new "
"password twice so we can verify you typed it in correctly."
msgstr ""
"Please enter your old password, for security's sake, and then enter your new "
"password twice so we can verify you typed it in correctly."
#: templates/djadmin2/bootstrap/auth/password_change_form.html:31
msgid "Change my password"
msgstr "Change my password"

View file

@ -0,0 +1,226 @@
# This file is distributed under the same license as the django-admin2 package.
#
# Translators:
# Danilo Bargen <gezuru@gmail.com>, 2013.
msgid ""
msgstr ""
"Project-Id-Version: django-admin2\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2013-07-06 15:02+0200\n"
"PO-Revision-Date: 2013-07-06 14:47+0200\n"
"Last-Translator: Danilo Bargen <gezuru@gmail.com>\n"
"Language-Team: https://www.transifex.com/projects/p/django-admin2/language/"
"es/\n"
"Language: es\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#: actions.py:26
msgid ""
"Items must be selected in order to perform actions on them. No items have "
"been changed."
msgstr ""
#: actions.py:29
#, python-format
msgid "Successfully deleted %(count)s %(items)s"
msgstr ""
#: actions.py:127
msgid "Delete selected items"
msgstr ""
#: forms.py:238
#, python-format
msgid ""
"Please enter the correct %(username)s and password for a staff account. Note "
"that both fields may be case-sensitive."
msgstr ""
#: forms.py:249
msgid "Please log in again, because your session has expired."
msgstr ""
#: views.py:165 templates/admin2/bootstrap/model_update_form.html:29
#: templates/admin2/bootstrap/includes/app_model_list.html:38
msgid "Change"
msgstr ""
#: views.py:179 templates/admin2/bootstrap/includes/app_model_list.html:30
msgid "Add"
msgstr ""
#: templates/admin2/bootstrap/app_index.html:6
#: templates/admin2/bootstrap/base.html:55
#: templates/admin2/bootstrap/model_confirm_delete.html:10
#: templates/admin2/bootstrap/model_detail.html:11
#: templates/admin2/bootstrap/model_list.html:14
#: templates/admin2/bootstrap/model_update_form.html:11
#: templates/admin2/bootstrap/actions/delete_selected_confirmation.html:10
#: templates/admin2/bootstrap/auth/logout.html:8
#: templates/admin2/bootstrap/auth/password_change_done.html:11
#: templates/admin2/bootstrap/auth/password_change_form.html:10
msgid "Home"
msgstr ""
#: templates/admin2/bootstrap/app_index.html:12
#, python-format
msgid "%(app_label)s administration"
msgstr ""
#: templates/admin2/bootstrap/base.html:6
#: templates/admin2/bootstrap/base.html:71
#: templates/admin2/bootstrap/auth/login.html:15
msgid "Site administration"
msgstr ""
#: templates/admin2/bootstrap/base.html:22
msgid "API"
msgstr ""
#: templates/admin2/bootstrap/base.html:25
msgid "Documentation"
msgstr ""
#: templates/admin2/bootstrap/base.html:34
#, python-format
msgid "Logged in as %(user)s"
msgstr ""
#: templates/admin2/bootstrap/base.html:40
msgid "Change password"
msgstr ""
#: templates/admin2/bootstrap/base.html:42
#: templates/admin2/bootstrap/auth/logout.html:11
msgid "Log out"
msgstr ""
#: templates/admin2/bootstrap/index.html:13
msgid "Recent Actions"
msgstr ""
#: templates/admin2/bootstrap/index.html:14
msgid "My Actions"
msgstr ""
#: templates/admin2/bootstrap/model_confirm_delete.html:4
#: templates/admin2/bootstrap/model_confirm_delete.html:6
#: templates/admin2/bootstrap/actions/delete_selected_confirmation.html:4
#: templates/admin2/bootstrap/actions/delete_selected_confirmation.html:6
msgid "Are you sure?"
msgstr ""
#: templates/admin2/bootstrap/model_confirm_delete.html:25
#: templates/admin2/bootstrap/model_update_form.html:74
#: templates/admin2/bootstrap/actions/delete_selected_confirmation.html:21
msgid "Delete"
msgstr ""
#: templates/admin2/bootstrap/model_confirm_delete.html:30
#, python-format
msgid ""
"Are you sure you want to delete the %(model_name)s \"%(object)s\"? All of "
"the following items will be deleted:"
msgstr ""
#: templates/admin2/bootstrap/model_confirm_delete.html:40
#: templates/admin2/bootstrap/actions/delete_selected_confirmation.html:40
msgid "Yes, I'm sure"
msgstr ""
#: templates/admin2/bootstrap/model_list.html:4
#: templates/admin2/bootstrap/model_list.html:6
#, python-format
msgid "Select %(model_name)s to change"
msgstr ""
#: templates/admin2/bootstrap/model_list.html:31
msgid "Search Term"
msgstr ""
#: templates/admin2/bootstrap/model_list.html:32
msgid "Search"
msgstr ""
#: templates/admin2/bootstrap/model_list.html:59
#, python-format
msgid "%(selected)s of %(total)s selected"
msgstr ""
#: templates/admin2/bootstrap/model_list.html:63
#, python-format
msgid "Add %(model_verbose_name)s"
msgstr ""
#: templates/admin2/bootstrap/model_update_form.html:5
#: templates/admin2/bootstrap/model_update_form.html:7
#, python-format
msgid "%(action)s %(model_name)s"
msgstr ""
#: templates/admin2/bootstrap/model_update_form.html:78
msgid "Save and add another"
msgstr ""
#: templates/admin2/bootstrap/model_update_form.html:79
msgid "Save and continue editing"
msgstr ""
#: templates/admin2/bootstrap/model_update_form.html:80
msgid "Save"
msgstr ""
#: templates/admin2/bootstrap/actions/delete_selected_confirmation.html:27
#, python-format
msgid ""
"Are you sure you want to delete the selected %(objects_name)s? All of the "
"following items will be deleted:"
msgstr ""
#: templates/admin2/bootstrap/auth/login.html:15
#: templates/admin2/bootstrap/auth/login.html:52
msgid "Log in"
msgstr ""
#: templates/admin2/bootstrap/auth/login.html:27
#: templates/admin2/bootstrap/auth/password_change_form.html:24
msgid "Please correct the error below."
msgid_plural "Please correct the errors below."
msgstr[0] ""
msgstr[1] ""
#: templates/admin2/bootstrap/auth/logout.html:17
msgid "Thanks for spending some quality time with the Web site today."
msgstr ""
#: templates/admin2/bootstrap/auth/logout.html:18
msgid "Log in again"
msgstr ""
#: templates/admin2/bootstrap/auth/password_change_done.html:6
#: templates/admin2/bootstrap/auth/password_change_done.html:7
#: templates/admin2/bootstrap/auth/password_change_done.html:14
msgid "Password change successful"
msgstr ""
#: templates/admin2/bootstrap/auth/password_change_done.html:20
msgid "Your password was changed."
msgstr ""
#: templates/admin2/bootstrap/auth/password_change_form.html:6
#: templates/admin2/bootstrap/auth/password_change_form.html:13
msgid "Password change"
msgstr ""
#: templates/admin2/bootstrap/auth/password_change_form.html:20
msgid ""
"Please enter your old password, for security's sake, and then enter your new "
"password twice so we can verify you typed it in correctly."
msgstr ""
#: templates/admin2/bootstrap/auth/password_change_form.html:31
msgid "Change my password"
msgstr ""

View file

@ -0,0 +1,244 @@
# This file is distributed under the same license as the django-admin2 package.
#
# Translators:
# NotSqrt <notsqrt@gmail.com>, 2013.
msgid ""
msgstr ""
"Project-Id-Version: django-admin2\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2013-07-06 15:02+0200\n"
"PO-Revision-Date: 2013-07-06 13:27+0200\n"
"Last-Translator: NotSqrt <notsqrt@gmail.com>\n"
"Language-Team: https://www.transifex.com/projects/p/django-admin2/language/"
"fr/\n"
"Language: fr\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n>1;\n"
#: actions.py:26
msgid ""
"Items must be selected in order to perform actions on them. No items have "
"been changed."
msgstr ""
"Des éléments doivent être sélectionnés afin d'appliquer les actions. Aucun "
"élément n'a été modifié."
#: actions.py:29
#, python-format
msgid "Successfully deleted %(count)s %(items)s"
msgstr "La suppression de %(count)s %(items)s a réussi."
#: actions.py:127
msgid "Delete selected items"
msgstr "Supprimer les objets sélectionnés"
#: forms.py:238
#, python-format
msgid ""
"Please enter the correct %(username)s and password for a staff account. Note "
"that both fields may be case-sensitive."
msgstr ""
"Veuillez compléter correctement les champs « %(username)s » et « mot de "
"passe » d'un compte autorisé. Sachez que les deux champs peuvent être "
"sensibles à la casse."
#: forms.py:249
msgid "Please log in again, because your session has expired."
msgstr "Reconnectez-vous car votre session a expiré."
#: views.py:165 templates/djadmin2/bootstrap/model_update_form.html:29
#: templates/djadmin2/bootstrap/includes/app_model_list.html:38
msgid "Change"
msgstr "Modifier"
#: views.py:179 templates/djadmin2/bootstrap/includes/app_model_list.html:30
msgid "Add"
msgstr "Ajouter"
#: templates/djadmin2/bootstrap/app_index.html:6
#: templates/djadmin2/bootstrap/base.html:55
#: templates/djadmin2/bootstrap/model_confirm_delete.html:10
#: templates/djadmin2/bootstrap/model_detail.html:11
#: templates/djadmin2/bootstrap/model_list.html:14
#: templates/djadmin2/bootstrap/model_update_form.html:11
#: templates/djadmin2/bootstrap/actions/delete_selected_confirmation.html:10
#: templates/djadmin2/bootstrap/auth/logout.html:8
#: templates/djadmin2/bootstrap/auth/password_change_done.html:11
#: templates/djadmin2/bootstrap/auth/password_change_form.html:10
msgid "Home"
msgstr "Accueil"
#: templates/djadmin2/bootstrap/app_index.html:12
#, python-format
msgid "%(app_label)s administration"
msgstr "Administration de %(app_label)s"
#: templates/djadmin2/bootstrap/base.html:6
#: templates/djadmin2/bootstrap/base.html:71
#: templates/djadmin2/bootstrap/auth/login.html:15
msgid "Site administration"
msgstr "Administration du site"
#: templates/djadmin2/bootstrap/base.html:22
msgid "API"
msgstr "API"
#: templates/djadmin2/bootstrap/base.html:25
msgid "Documentation"
msgstr "Documentation"
#: templates/djadmin2/bootstrap/base.html:34
#, python-format
msgid "Logged in as %(user)s"
msgstr "Connecté en tant que %(user)s"
#: templates/djadmin2/bootstrap/base.html:40
msgid "Change password"
msgstr "Modifier votre mot de passe"
#: templates/djadmin2/bootstrap/base.html:42
msgid "Log out"
msgstr "Déconnexion"
#: templates/djadmin2/bootstrap/index.html:13
msgid "Recent Actions"
msgstr "Actions récentes"
#: templates/djadmin2/bootstrap/index.html:14
msgid "My Actions"
msgstr "Mes actions"
#: templates/djadmin2/bootstrap/model_confirm_delete.html:4
#: templates/djadmin2/bootstrap/model_confirm_delete.html:6
#: templates/djadmin2/bootstrap/actions/delete_selected_confirmation.html:4
#: templates/djadmin2/bootstrap/actions/delete_selected_confirmation.html:6
msgid "Are you sure?"
msgstr "Êtes-vous sûr ?"
#: templates/djadmin2/bootstrap/model_confirm_delete.html:25
#: templates/djadmin2/bootstrap/model_update_form.html:74
#: templates/djadmin2/bootstrap/actions/delete_selected_confirmation.html:21
msgid "Delete"
msgstr "Supprimer"
#: templates/djadmin2/bootstrap/model_confirm_delete.html:30
#, python-format
msgid ""
"Are you sure you want to delete the %(model_name)s \"%(object)s\"? All of "
"the following items will be deleted:"
msgstr ""
"Voulez-vous vraiment supprimer l'objet %(model_name)s « %(object)s » ? Les "
"éléments suivants seront supprimés :"
#: templates/djadmin2/bootstrap/model_confirm_delete.html:40
#: templates/djadmin2/bootstrap/actions/delete_selected_confirmation.html:40
msgid "Yes, I'm sure"
msgstr "Oui, je suis sûr"
#: templates/djadmin2/bootstrap/model_list.html:4
#: templates/djadmin2/bootstrap/model_list.html:6
#, python-format
msgid "Select %(model_name)s to change"
msgstr "Sélectionnez l'objet %(model_name)s à modifier"
#: templates/djadmin2/bootstrap/model_list.html:31
msgid "Search Term"
msgstr "Terme à rechercher"
#: templates/djadmin2/bootstrap/model_list.html:32
msgid "Search"
msgstr "Recherche"
#: templates/djadmin2/bootstrap/model_list.html:59
#, python-format
msgid "%(selected)s of %(total)s selected"
msgstr "%(selected)s sur %(total)s sélectionnés"
#: templates/djadmin2/bootstrap/model_list.html:63
#, python-format
msgid "Add %(model_verbose_name)s"
msgstr "Ajouter %(model_verbose_name)s"
#: templates/djadmin2/bootstrap/model_update_form.html:5
#: templates/djadmin2/bootstrap/model_update_form.html:7
#, python-format
msgid "%(action)s %(model_name)s"
msgstr "%(action)s %(model_name)s"
#: templates/djadmin2/bootstrap/model_update_form.html:78
msgid "Save and add another"
msgstr "Enregistrer et ajouter un nouveau"
#: templates/djadmin2/bootstrap/model_update_form.html:79
msgid "Save and continue editing"
msgstr "Enregistrer et continuer les modifications"
#: templates/djadmin2/bootstrap/model_update_form.html:80
msgid "Save"
msgstr "Enregistrer"
#: templates/djadmin2/bootstrap/actions/delete_selected_confirmation.html:27
#, python-format
msgid ""
"Are you sure you want to delete the selected %(objects_name)s? All of the "
"following items will be deleted:"
msgstr ""
"Voulez-vous vraiment supprimer les objets %(objects_name)s sélectionnés ? "
"Les éléments suivants seront supprimés :"
#: templates/djadmin2/bootstrap/auth/login.html:15
msgid "Login"
msgstr "Connexion"
#: templates/djadmin2/bootstrap/auth/login.html:27
#: templates/djadmin2/bootstrap/auth/password_change_form.html:24
msgid "Please correct the error below."
msgid_plural "Please correct the errors below."
msgstr[0] "Corrigez l'erreur suivante."
msgstr[1] "Corrigez les erreurs suivantes."
#: templates/djadmin2/bootstrap/auth/login.html:52
msgid "Log in"
msgstr "Connexion"
#: templates/djadmin2/bootstrap/auth/logout.html:11
msgid "Logout"
msgstr "Déconnexion"
#: templates/djadmin2/bootstrap/auth/logout.html:17
msgid "Thanks for spending some quality time with the Web site today."
msgstr "Merci pour le temps que vous avez accordé à ce site aujourd'hui."
#: templates/djadmin2/bootstrap/auth/logout.html:18
msgid "Log in again"
msgstr "Connectez-vous à nouveau"
#: templates/djadmin2/bootstrap/auth/password_change_done.html:6
#: templates/djadmin2/bootstrap/auth/password_change_done.html:7
#: templates/djadmin2/bootstrap/auth/password_change_done.html:14
msgid "Password change successful"
msgstr "Mot de passe modifié avec succès"
#: templates/djadmin2/bootstrap/auth/password_change_done.html:20
msgid "Your password was changed."
msgstr "Votre mot de passe a été modifié."
#: templates/djadmin2/bootstrap/auth/password_change_form.html:6
#: templates/djadmin2/bootstrap/auth/password_change_form.html:13
msgid "Password change"
msgstr "Modification de votre mot de passe"
#: templates/djadmin2/bootstrap/auth/password_change_form.html:20
msgid ""
"Please enter your old password, for security's sake, and then enter your new "
"password twice so we can verify you typed it in correctly."
msgstr ""
"Pour des raisons de sécurité, saisissez votre ancien mot de passe puis votre "
"nouveau mot de passe à deux reprises afin de vérifier qu'il est correctement "
"saisi."
#: templates/djadmin2/bootstrap/auth/password_change_form.html:31
msgid "Change my password"
msgstr "Modifier mon mot de passe"

View file

@ -0,0 +1,226 @@
# This file is distributed under the same license as the django-admin2 package.
#
# Translators:
# Margherita Zamponi <margherita.zamponi@gmail.com>
msgid ""
msgstr ""
"Project-Id-Version: django-admin2\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2013-07-06 15:02+0200\n"
"PO-Revision-Date: 2013-07-06 14:47+0200\n"
"Last-Translator: Margherita Zamponi <margherita.zamponi@gmail.com>\n"
"Language-Team: https://www.transifex.com/projects/p/django-admin2/language/"
"it/\n"
"Language: it\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#: actions.py:26
msgid ""
"Items must be selected in order to perform actions on them. No items have "
"been changed."
msgstr ""
#: actions.py:29
#, python-format
msgid "Successfully deleted %(count)s %(items)s"
msgstr ""
#: actions.py:127
msgid "Delete selected items"
msgstr ""
#: forms.py:238
#, python-format
msgid ""
"Please enter the correct %(username)s and password for a staff account. Note "
"that both fields may be case-sensitive."
msgstr ""
#: forms.py:249
msgid "Please log in again, because your session has expired."
msgstr ""
#: views.py:165 templates/admin2/bootstrap/model_update_form.html:29
#: templates/admin2/bootstrap/includes/app_model_list.html:38
msgid "Change"
msgstr ""
#: views.py:179 templates/admin2/bootstrap/includes/app_model_list.html:30
msgid "Add"
msgstr ""
#: templates/admin2/bootstrap/app_index.html:6
#: templates/admin2/bootstrap/base.html:55
#: templates/admin2/bootstrap/model_confirm_delete.html:10
#: templates/admin2/bootstrap/model_detail.html:11
#: templates/admin2/bootstrap/model_list.html:14
#: templates/admin2/bootstrap/model_update_form.html:11
#: templates/admin2/bootstrap/actions/delete_selected_confirmation.html:10
#: templates/admin2/bootstrap/auth/logout.html:8
#: templates/admin2/bootstrap/auth/password_change_done.html:11
#: templates/admin2/bootstrap/auth/password_change_form.html:10
msgid "Home"
msgstr ""
#: templates/admin2/bootstrap/app_index.html:12
#, python-format
msgid "%(app_label)s administration"
msgstr ""
#: templates/admin2/bootstrap/base.html:6
#: templates/admin2/bootstrap/base.html:71
#: templates/admin2/bootstrap/auth/login.html:15
msgid "Site administration"
msgstr ""
#: templates/admin2/bootstrap/base.html:22
msgid "API"
msgstr ""
#: templates/admin2/bootstrap/base.html:25
msgid "Documentation"
msgstr ""
#: templates/admin2/bootstrap/base.html:34
#, python-format
msgid "Logged in as %(user)s"
msgstr ""
#: templates/admin2/bootstrap/base.html:40
msgid "Change password"
msgstr ""
#: templates/admin2/bootstrap/base.html:42
#: templates/admin2/bootstrap/auth/logout.html:11
msgid "Log out"
msgstr ""
#: templates/admin2/bootstrap/index.html:13
msgid "Recent Actions"
msgstr ""
#: templates/admin2/bootstrap/index.html:14
msgid "My Actions"
msgstr ""
#: templates/admin2/bootstrap/model_confirm_delete.html:4
#: templates/admin2/bootstrap/model_confirm_delete.html:6
#: templates/admin2/bootstrap/actions/delete_selected_confirmation.html:4
#: templates/admin2/bootstrap/actions/delete_selected_confirmation.html:6
msgid "Are you sure?"
msgstr ""
#: templates/admin2/bootstrap/model_confirm_delete.html:25
#: templates/admin2/bootstrap/model_update_form.html:74
#: templates/admin2/bootstrap/actions/delete_selected_confirmation.html:21
msgid "Delete"
msgstr ""
#: templates/admin2/bootstrap/model_confirm_delete.html:30
#, python-format
msgid ""
"Are you sure you want to delete the %(model_name)s \"%(object)s\"? All of "
"the following items will be deleted:"
msgstr ""
#: templates/admin2/bootstrap/model_confirm_delete.html:40
#: templates/admin2/bootstrap/actions/delete_selected_confirmation.html:40
msgid "Yes, I'm sure"
msgstr ""
#: templates/admin2/bootstrap/model_list.html:4
#: templates/admin2/bootstrap/model_list.html:6
#, python-format
msgid "Select %(model_name)s to change"
msgstr ""
#: templates/admin2/bootstrap/model_list.html:31
msgid "Search Term"
msgstr ""
#: templates/admin2/bootstrap/model_list.html:32
msgid "Search"
msgstr ""
#: templates/admin2/bootstrap/model_list.html:59
#, python-format
msgid "%(selected)s of %(total)s selected"
msgstr ""
#: templates/admin2/bootstrap/model_list.html:63
#, python-format
msgid "Add %(model_verbose_name)s"
msgstr ""
#: templates/admin2/bootstrap/model_update_form.html:5
#: templates/admin2/bootstrap/model_update_form.html:7
#, python-format
msgid "%(action)s %(model_name)s"
msgstr ""
#: templates/admin2/bootstrap/model_update_form.html:78
msgid "Save and add another"
msgstr ""
#: templates/admin2/bootstrap/model_update_form.html:79
msgid "Save and continue editing"
msgstr ""
#: templates/admin2/bootstrap/model_update_form.html:80
msgid "Save"
msgstr ""
#: templates/admin2/bootstrap/actions/delete_selected_confirmation.html:27
#, python-format
msgid ""
"Are you sure you want to delete the selected %(objects_name)s? All of the "
"following items will be deleted:"
msgstr ""
#: templates/admin2/bootstrap/auth/login.html:15
#: templates/admin2/bootstrap/auth/login.html:52
msgid "Log in"
msgstr ""
#: templates/admin2/bootstrap/auth/login.html:27
#: templates/admin2/bootstrap/auth/password_change_form.html:24
msgid "Please correct the error below."
msgid_plural "Please correct the errors below."
msgstr[0] ""
msgstr[1] ""
#: templates/admin2/bootstrap/auth/logout.html:17
msgid "Thanks for spending some quality time with the Web site today."
msgstr ""
#: templates/admin2/bootstrap/auth/logout.html:18
msgid "Log in again"
msgstr ""
#: templates/admin2/bootstrap/auth/password_change_done.html:6
#: templates/admin2/bootstrap/auth/password_change_done.html:7
#: templates/admin2/bootstrap/auth/password_change_done.html:14
msgid "Password change successful"
msgstr ""
#: templates/admin2/bootstrap/auth/password_change_done.html:20
msgid "Your password was changed."
msgstr ""
#: templates/admin2/bootstrap/auth/password_change_form.html:6
#: templates/admin2/bootstrap/auth/password_change_form.html:13
msgid "Password change"
msgstr ""
#: templates/admin2/bootstrap/auth/password_change_form.html:20
msgid ""
"Please enter your old password, for security's sake, and then enter your new "
"password twice so we can verify you typed it in correctly."
msgstr ""
#: templates/admin2/bootstrap/auth/password_change_form.html:31
msgid "Change my password"
msgstr ""

View file

@ -6,4 +6,4 @@ MODEL_ADMIN_ATTRS = (
'index_view', 'detail_view', 'create_view', 'update_view', 'delete_view',
'get_default_view_kwargs', 'get_list_actions')
ADMIN2_THEME_DIRECTORY = getattr(settings, "ADMIN2_THEME_DIRECTORY", "admin2/bootstrap")
ADMIN2_THEME_DIRECTORY = getattr(settings, "ADMIN2_THEME_DIRECTORY", "djadmin2/bootstrap")

View file

@ -1,13 +1,13 @@
{% extends "admin2/bootstrap/base.html" %}
{% extends "djadmin2/bootstrap/base.html" %}
{% load admin2_tags i18n %}
{% block title %}Are you sure?{% endblock title %}
{% block title %}{% trans "Are you sure?" %}{% endblock title %}
{% block page_title %}Are you sure?{% endblock page_title %}
{% block page_title %}{% trans "Are you sure?" %}{% endblock page_title %}
{% block breadcrumbs %}
<li>
<a href="{% url "admin2:dashboard" %}">Home</a>
<a href="{% url "admin2:dashboard" %}">{% trans "Home" %}</a>
<span class="divider">/</span>
</li>
<li>

View file

@ -1,9 +1,9 @@
{% extends "admin2/bootstrap/base.html" %}
{% extends "djadmin2/bootstrap/base.html" %}
{% load admin2_tags i18n %}
{% block breadcrumbs %}
<li>
<a href="{% url "admin2:dashboard" %}">Home</a>
<a href="{% url "admin2:dashboard" %}">{% trans "Home" %}</a>
<span class="divider">/</span>
</li>
<li class="active">{{ app_label|title }}</li>
@ -14,7 +14,7 @@
{% block content %}
<div class="row">
<div class="span7">
{% include 'admin2/bootstrap/includes/app_model_list.html' %}
{% include 'djadmin2/bootstrap/includes/app_model_list.html' %}
</div>
</div>
{% endblock content %}

View file

@ -1,4 +1,4 @@
{% extends "admin2/bootstrap/base.html" %}
{% extends "djadmin2/bootstrap/base.html" %}
{% load i18n %}
{% load admin2_tags %}
@ -12,7 +12,7 @@
{% block breacrumbs %}{% endblock breacrumbs %}
{% block class_page_title %}span12 login-title{% endblock class_page_title %}
{% block page_title %}{% trans "Site administration" %} - Login{% endblock page_title %}
{% block page_title %}{% trans "Site administration" %} - {% trans "Log in" %}{% endblock page_title %}
{% block content %}
<div class="row-fluid">

View file

@ -1,14 +1,14 @@
{% extends "admin2/bootstrap/base.html" %}
{% extends "djadmin2/bootstrap/base.html" %}
{% load i18n %}
{% load admin2_tags %}
{% block breadcrumbs %}
<li>
<a href="{% url "admin2:dashboard" %}">Home</a>
<a href="{% url "admin2:dashboard" %}">{% trans "Home" %}</a>
<span class="divider">/</span>
</li>
<li class="active">{% trans "Logout" %}</li>
<li class="active">{% trans "Log out" %}</li>
{% endblock breadcrumbs %}
{% block content %}

View file

@ -1,4 +1,4 @@
{% extends "admin2/bootstrap/base.html" %}
{% extends "djadmin2/bootstrap/base.html" %}
{% load i18n %}
{% load admin2_tags %}
@ -8,7 +8,7 @@
{% block breadcrumbs %}
<li>
<a href="{% url "admin2:dashboard" %}">Home</a>
<a href="{% url "admin2:dashboard" %}">{% trans "Home" %}</a>
<span class="divider">/</span>
</li>
<li class="active">{% trans "Password change successful" %}</li>

View file

@ -1,4 +1,4 @@
{% extends "admin2/bootstrap/base.html" %}
{% extends "djadmin2/bootstrap/base.html" %}
{% load i18n %}
{% load admin2_tags %}
@ -7,7 +7,7 @@
{% block breadcrumbs %}
<li>
<a href="{% url "admin2:dashboard" %}">Home</a>
<a href="{% url "admin2:dashboard" %}">{% trans "Home" %}</a>
<span class="divider">/</span>
</li>
<li class="active">{% trans "Password change" %} <span class="divider">/</span></li>
@ -17,7 +17,7 @@
{% block content %}
<div class="row">
<div class="span12">
<p>Please enter your old password, for security's sake, and then enter your new password twice so we can verify you typed it in correctly.</p>
<p>{% trans "Please enter your old password, for security's sake, and then enter your new password twice so we can verify you typed it in correctly." %}</p>
{% if form.errors %}
<p class="error-note">

View file

@ -3,7 +3,7 @@
<head>
<meta charset="utf-8">
<title>{% block title %}Site administration{% endblock title %} | django-admin2</title>
<title>{% block title %}{% trans "Site administration" %}{% endblock title %} | django-admin2</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- Bootstrap -->
{% block css %}
@ -31,9 +31,7 @@
{% if user.get_full_name %}
{{ user.get_full_name }}
{% else %}
{% blocktrans with user=user.username %}
Logged in as {{ user }}
{% endblocktrans %}
{% blocktrans with user=user.username %}Logged in as {{ user }}{% endblocktrans %}
{% endif %}
<b class="caret"></b>
</a>
@ -54,7 +52,7 @@
{% block breacrumbs %}
<ul class="breadcrumb">
{% block breadcrumbs %}
<li class="active">Home</li>
<li class="active">{% trans "Home" %}</li>
{% endblock breadcrumbs %}
</ul>
{% endblock breacrumbs %}

View file

@ -1,4 +1,4 @@
{% extends "admin2/bootstrap/base.html" %}
{% extends "djadmin2/bootstrap/base.html" %}
{% load admin2_tags i18n %}
{% block content %}
@ -6,7 +6,7 @@
<div class="row">
<div class="span7">
{% for app_label, registry in apps.items %}
{% include 'admin2/bootstrap/includes/app_model_list.html' %}
{% include 'djadmin2/bootstrap/includes/app_model_list.html' %}
{% endfor %}
</div>
<div class="span5">

View file

@ -1,4 +1,4 @@
{% extends "admin2/bootstrap/base.html" %}
{% extends "djadmin2/bootstrap/base.html" %}
{% load admin2_tags i18n %}
{% block title %}{% trans "Are you sure?" %}{% endblock title %}
@ -7,7 +7,7 @@
{% block breadcrumbs %}
<li>
<a href="{% url "admin2:dashboard" %}">Home</a>
<a href="{% url "admin2:dashboard" %}">{% trans "Home" %}</a>
<span class="divider">/</span>
</li>
<li>

View file

@ -1,6 +1,6 @@
{% extends "admin2/bootstrap/base.html" %}
{% extends "djadmin2/bootstrap/base.html" %}
{% load admin2_tags %}
{% load admin2_tags i18n %}
{% block title %}{{ object }}{% endblock title %}
@ -8,7 +8,7 @@
{% block breadcrumbs %}
<li>
<a href="{% url "admin2:dashboard" %}">Home</a>
<a href="{% url "admin2:dashboard" %}">{% trans "Home" %}</a>
<span class="divider">/</span>
</li>
<li>

View file

@ -1,4 +1,4 @@
{% extends "admin2/bootstrap/base.html" %}
{% extends "djadmin2/bootstrap/base.html" %}
{% load admin2_tags i18n %}
{% block title %}{% blocktrans with model_name=model_name %}Select {{ model_name }} to change{% endblocktrans %}{% endblock title %}
@ -11,7 +11,7 @@
{% block breadcrumbs %}
<li>
<a href="{% url "admin2:dashboard" %}">Home</a>
<a href="{% url "admin2:dashboard" %}">{% trans "Home" %}</a>
<span class="divider">/</span>
</li>
<li>
@ -28,8 +28,8 @@
<div class="span12">
<form method="get" class="form-search">
<div class="input-append">
<input type="text" class="input-medium search-query" placeholder="Search Term" name="q" value="{{search_term}}"/>
<button class="btn" type="button"><i class="icon-search"></i> Search</button>
<input type="text" class="input-medium search-query" placeholder="{% trans 'Search Term' %}" name="q" value="{{search_term}}"/>
<button class="btn" type="button"><i class="icon-search"></i> {% trans "Search" %}</button>
</div>
</form>
</div>
@ -55,7 +55,9 @@
</ul>
</div>
<input type="hidden" name="action" value="" />
<small class="muted"><span id="selected-count">0</span> of {{ object_list|length }} selected</small>
<small class="muted">
{% blocktrans with selected='<span id="selected-count">0</span>' total=object_list|length %}{{selected}} of {{total}} selected{% endblocktrans %}
</small>
<div class="pull-right">
{% if permissions.has_add_permission %}
<a href="{% url view|admin2_urlname:'create' %}" class="btn"><i class="icon-plus"></i> {% blocktrans with model_verbose_name=model|model_verbose_name %}Add {{ model_verbose_name }}{% endblocktrans %}</a>
@ -71,7 +73,7 @@
{% if forloop.first and attr == "__str__" %}
<th>{{ model_name|capfirst }}</th>
{% else %}
<th>{{ attr }}</th>
<th>{{ model|model_attr_verbose_name:attr|capfirst }}</th>
{% endif%}
{% endfor %}
</thead>

View file

@ -1,4 +1,4 @@
{% extends "admin2/bootstrap/base.html" %}
{% extends "djadmin2/bootstrap/base.html" %}
{% load admin2_tags i18n %}
@ -8,7 +8,7 @@
{% block breadcrumbs %}
<li>
<a href="{% url "admin2:dashboard" %}">Home</a>
<a href="{% url "admin2:dashboard" %}">{% trans "Home" %}</a>
<span class="divider">/</span>
</li>
<li>

View file

@ -1,4 +1,5 @@
from django import template
from django.db.models.fields import FieldDoesNotExist
register = template.Library()
@ -37,6 +38,17 @@ def model_verbose_name_plural(obj):
return utils.model_verbose_name_plural(obj)
@register.filter
def model_attr_verbose_name(obj, attr):
"""
Returns the verbose name of a model field or method.
"""
try:
return utils.model_field_verbose_name(obj, attr)
except FieldDoesNotExist:
return utils.model_method_verbose_name(obj, attr)
@register.filter
def formset_visible_fieldlist(formset):
"""

View file

@ -3,3 +3,4 @@ from test_types import *
from test_utils import *
from test_views import *
from test_core import *
from test_actions import *

View file

@ -0,0 +1,49 @@
from django.db import models
from django.test import TestCase
from ..core import Admin2
from ..actions import get_description
class Thing(models.Model):
pass
class TestAction(object):
description = "Test Action Class"
def test_function():
pass
class ActionTest(TestCase):
def setUp(self):
self.admin2 = Admin2()
def test_action_description(self):
self.admin2.register(Thing)
self.admin2.registry[Thing].list_actions.extend([
TestAction,
test_function,
])
self.assertEquals(
get_description(
self.admin2.registry[Thing].list_actions[0]
),
'Delete selected items'
)
self.assertEquals(
get_description(
self.admin2.registry[Thing].list_actions[1]
),
'Test Action Class'
)
self.assertEquals(
get_description(
self.admin2.registry[Thing].list_actions[2]
),
'Test function'
)
self.admin2.registry[Thing].list_actions.remove(TestAction)
self.admin2.registry[Thing].list_actions.remove(test_function)

View file

@ -9,6 +9,14 @@ from ..views import IndexView
class TagsTestsModel(models.Model):
field1 = models.CharField(max_length=23)
field2 = models.CharField('second field', max_length=42)
def was_published_recently(self):
return True
was_published_recently.boolean = True
was_published_recently.short_description = 'Published recently?'
class Meta:
verbose_name = "Tags Test Model"
verbose_name_plural = "Tags Test Models"
@ -58,6 +66,24 @@ class TagsTests(TestCase):
admin2_tags.model_verbose_name_plural(self.instance)
)
def test_model_field_verbose_name_autogenerated(self):
self.assertEquals(
'field1',
admin2_tags.model_attr_verbose_name(self.instance, 'field1')
)
def test_model_field_verbose_name_overridden(self):
self.assertEquals(
'second field',
admin2_tags.model_attr_verbose_name(self.instance, 'field2')
)
def test_model_method_verbose_name(self):
self.assertEquals(
'Published recently?',
admin2_tags.model_attr_verbose_name(self.instance, 'was_published_recently')
)
def test_formset_visible_fieldlist(self):
formset = TagsTestFormSet()
self.assertEquals(

View file

@ -7,6 +7,17 @@ from ..views import IndexView
class UtilsTestModel(models.Model):
field1 = models.CharField(max_length=23)
field2 = models.CharField('second field', max_length=42)
def simple_method(self):
return 42
def was_published_recently(self):
return True
was_published_recently.boolean = True
was_published_recently.short_description = 'Published recently?'
class Meta:
verbose_name = "Utils Test Model"
verbose_name_plural = "Utils Test Models"
@ -71,6 +82,30 @@ class UtilsTest(TestCase):
utils.model_verbose_name_plural(self.instance)
)
def test_model_field_verbose_name_autogenerated(self):
self.assertEquals(
'field1',
utils.model_field_verbose_name(self.instance, 'field1')
)
def test_model_field_verbose_name_overridden(self):
self.assertEquals(
'second field',
utils.model_field_verbose_name(self.instance, 'field2')
)
def test_model_method_verbose_name(self):
self.assertEquals(
'Published recently?',
utils.model_method_verbose_name(self.instance, 'was_published_recently')
)
def test_model_method_verbose_name_fallback(self):
self.assertEquals(
'simple_method',
utils.model_method_verbose_name(self.instance, 'simple_method')
)
def test_app_label_as_model_class(self):
self.assertEquals(
UtilsTestModel._meta.app_label,

View file

@ -22,6 +22,7 @@ def lookup_needs_distinct(opts, lookup_path):
return True
return False
def model_options(model):
"""
Wrapper for accessing model._meta. If this access point changes in core
@ -40,18 +41,39 @@ def admin2_urlname(view, action):
return 'admin2:%s_%s_%s' % (view.app_label, view.model_name, action)
def model_verbose_name(obj):
def model_verbose_name(model):
"""
Returns the verbose name of a model instance or class.
"""
return model_options(obj).verbose_name
return model_options(model).verbose_name
def model_verbose_name_plural(obj):
def model_verbose_name_plural(model):
"""
Returns the pluralized verbose name of a model instance or class.
"""
return model_options(obj).verbose_name_plural
return model_options(model).verbose_name_plural
def model_field_verbose_name(model, field_name):
"""
Returns the verbose name of a model field.
"""
meta = model_options(model)
field = meta.get_field_by_name(field_name)[0]
return field.verbose_name
def model_method_verbose_name(model, method_name):
"""
Returns the verbose name / short description of a model field.
"""
meta = model_options(model)
method = getattr(model, method_name)
try:
return method.short_description
except AttributeError:
return method_name
def model_app_label(obj):

View file

@ -4,6 +4,7 @@ from django.contrib.auth.views import (logout as auth_logout,
login as auth_login)
from django.contrib.auth import get_user_model
from django.core.urlresolvers import reverse, reverse_lazy
from django.utils.translation import ugettext_lazy
from django.db import models
from django.http import HttpResponseRedirect
from django.utils.encoding import force_text
@ -25,21 +26,17 @@ from .filters import build_list_filter
class IndexView(Admin2Mixin, generic.TemplateView):
"""
Context Variables
"""Context Variables
:apps: A dictionary of apps, each app being a dictionary with keys
being models and the value being djadmin2.types.ModelAdmin2
objects.
:request.user: The user object representing the current user.
:apps: A dictionary of apps, each app being a dictionary with keys
being models and the value being djadmin2.types.ModelAdmin2
objects.
"""
default_template_name = "index.html"
registry = None
apps = None
def get_context_data(self, **kwargs):
data = super(IndexView, self).get_context_data(**kwargs)
data.update({
'apps': self.apps,
@ -65,6 +62,13 @@ class AppIndexView(Admin2Mixin, generic.TemplateView):
class ModelListView(AdminModel2Mixin, generic.ListView):
"""Context Variables
:is_paginated: If the page is paginated (page has a next button)
:model: Type of object you are editing
:model_name: Name of the object you are editing
:app_label: Name of your app
"""
default_template_name = "model_list.html"
permission_classes = (
permissions.IsStaffPermission,
@ -167,6 +171,12 @@ class ModelListView(AdminModel2Mixin, generic.ListView):
class ModelDetailView(AdminModel2Mixin, generic.DetailView):
"""Context Variables
:model: Type of object you are editing
:model_name: Name of the object you are editing
:app_label: Name of your app
"""
default_template_name = "model_detail.html"
permission_classes = (
permissions.IsStaffPermission,
@ -174,6 +184,12 @@ class ModelDetailView(AdminModel2Mixin, generic.DetailView):
class ModelEditFormView(AdminModel2Mixin, Admin2ModelFormMixin, extra_views.UpdateWithInlinesView):
"""Context Variables
:model: Type of object you are editing
:model_name: Name of the object you are editing
:app_label: Name of your app
"""
form_class = None
default_template_name = "model_update_form.html"
permission_classes = (
@ -183,11 +199,17 @@ class ModelEditFormView(AdminModel2Mixin, Admin2ModelFormMixin, extra_views.Upda
def get_context_data(self, **kwargs):
context = super(ModelEditFormView, self).get_context_data(**kwargs)
context['model'] = self.get_model()
context['action'] = "Change"
context['action'] = ugettext_lazy("Change")
return context
class ModelAddFormView(AdminModel2Mixin, Admin2ModelFormMixin, extra_views.CreateWithInlinesView):
"""Context Variables
:model: Type of object you are editing
:model_name: Name of the object you are editing
:app_label: Name of your app
"""
form_class = None
default_template_name = "model_update_form.html"
permission_classes = (
@ -197,11 +219,18 @@ class ModelAddFormView(AdminModel2Mixin, Admin2ModelFormMixin, extra_views.Creat
def get_context_data(self, **kwargs):
context = super(ModelAddFormView, self).get_context_data(**kwargs)
context['model'] = self.get_model()
context['action'] = "Add"
context['action'] = ugettext_lazy("Add")
return context
class ModelDeleteView(AdminModel2Mixin, generic.DeleteView):
"""Context Variables
:model: Type of object you are editing
:model_name: Name of the object you are editing
:app_label: Name of your app
:deletable_objects: Objects to delete
"""
success_url = "../../" # TODO - fix this!
default_template_name = "model_confirm_delete.html"
permission_classes = (
@ -254,6 +283,10 @@ class PasswordChangeDoneView(Admin2Mixin, generic.TemplateView):
class LoginView(Admin2Mixin, generic.TemplateView):
"""Context Variables
:site_name: Name of the site
"""
default_template_name = 'auth/login.html'
authentication_form = AdminAuthenticationForm
@ -266,6 +299,10 @@ class LoginView(Admin2Mixin, generic.TemplateView):
class LogoutView(Admin2Mixin, generic.TemplateView):
"""Context Variables
:site_name: Name of the site
"""
default_template_name = 'auth/logout.html'

81
docs/_ext/djangodocs.py Normal file
View file

@ -0,0 +1,81 @@
# Taken from https://github.com/django/django/blob/master/docs/_ext/djangodocs.py
import re
from sphinx import addnodes
# RE for option descriptions without a '--' prefix
simple_option_desc_re = re.compile(
r'([-_a-zA-Z0-9]+)(\s*.*?)(?=,\s+(?:/|-|--)|$)')
def setup(app):
app.add_crossref_type(
directivename="setting",
rolename="setting",
indextemplate="pair: %s; setting",
)
app.add_crossref_type(
directivename="templatetag",
rolename="ttag",
indextemplate="pair: %s; template tag"
)
app.add_crossref_type(
directivename="templatefilter",
rolename="tfilter",
indextemplate="pair: %s; template filter"
)
app.add_crossref_type(
directivename="fieldlookup",
rolename="lookup",
indextemplate="pair: %s; field lookup type",
)
app.add_description_unit(
directivename="django-admin",
rolename="djadmin",
indextemplate="pair: %s; django-admin command",
parse_node=parse_django_admin_node,
)
app.add_description_unit(
directivename="django-admin-option",
rolename="djadminopt",
indextemplate="pair: %s; django-admin command-line option",
parse_node=parse_django_adminopt_node,
)
def parse_django_admin_node(env, sig, signode):
command = sig.split(' ')[0]
env._django_curr_admin_command = command
title = "django-admin.py %s" % sig
signode += addnodes.desc_name(title, title)
return sig
def parse_django_adminopt_node(env, sig, signode):
"""A copy of sphinx.directives.CmdoptionDesc.parse_signature()"""
from sphinx.domains.std import option_desc_re
count = 0
firstname = ''
for m in option_desc_re.finditer(sig):
optname, args = m.groups()
if count:
signode += addnodes.desc_addname(', ', ', ')
signode += addnodes.desc_name(optname, optname)
signode += addnodes.desc_addname(args, args)
if not count:
firstname = optname
count += 1
if not count:
for m in simple_option_desc_re.finditer(sig):
optname, args = m.groups()
if count:
signode += addnodes.desc_addname(', ', ', ')
signode += addnodes.desc_name(optname, optname)
signode += addnodes.desc_addname(args, args)
if not count:
firstname = optname
count += 1
if not firstname:
raise ValueError
return firstname

1
docs/_static/README vendored Normal file
View file

@ -0,0 +1 @@
Put static files for Sphinx in here.

View file

@ -1,22 +0,0 @@
================
Architecture
================
.. warning:: This is out of date and will be updated shortly.
Workflow Pieces
----------------
* Apps
* Apps.models
* AdminObj
* Appstore
Workflow
----------------
1. Instantiate Appstore
2. Loop through the Apps then models per App
3. Admin2s are created from models: djadmin2.models.register(Poll)
4. Admin2s contain methods/properties necessaey for UI
5. Views

View file

@ -11,7 +11,8 @@
# All configuration values have a default; values that are commented out
# serve to show the default.
import sys, os
import os
import sys
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
@ -32,6 +33,10 @@ from example.example import settings
from django.core.management import setup_environ
setup_environ(settings)
# For intersphinx
ext_path = os.path.abspath(os.path.join(os.path.dirname(__file__), "_ext"))
sys.path.append(ext_path)
# -- General configuration -----------------------------------------------------
# If your documentation needs a minimal Sphinx version, state it here.
@ -39,7 +44,8 @@ setup_environ(settings)
# Add any Sphinx extension module names here, as strings. They can be extensions
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
extensions = ['sphinx.ext.autodoc', 'sphinx.ext.intersphinx']
extensions = ['djangodocs', 'sphinx.ext.autodoc', 'sphinx.ext.intersphinx',
'sphinx.ext.todo']
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
@ -62,9 +68,9 @@ copyright = u'2013, Daniel Greenfeld'
# built documents.
#
# The short X.Y version.
version = '0.4'
version = '0.5'
# The full version, including alpha/beta/rc tags.
release = '0.4.0'
release = '0.5.0'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
@ -264,7 +270,9 @@ texinfo_documents = [
# Example configuration for intersphinx: refer to the Python standard library.
intersphinx_mapping = {
'python': ('http://python.readthedocs.org/en/v2.7.2/', None),
'django': (
'http://docs.djangoproject.com/en/dev/',
'http://docs.djangoproject.com/en/dev/_objects/'),
'http://docs.djangoproject.com/en/dev/_objects/'
),
}

View file

@ -27,7 +27,7 @@ Local Installation
1. Create a virtualenv_ (or use virtualenvwrapper_). Activate it.
2. cd into django-admin2
3. type ``$ pip install -r requirements.txt``
4. type ``$ python setup.py develop``
4. type ``$ python setup.py develop``
Try the example projects
--------------------------
@ -37,7 +37,7 @@ Try the example projects
3. run the dev server: ``$ python manage.py runserver``
.. _virtualenv: http://www.virtualenv.org/en/latest/
.. _virtualenvwrapper: http://virtualenvwrapper.readthedocs.org/en/latest/
.. _virtualenvwrapper: http://virtualenvwrapper.readthedocs.org/en/latest/
Issues!
=======
@ -61,7 +61,7 @@ Setting up topic branches and generating pull requests
While it's handy to provide useful code snippets in an issue, it is better for
you as a developer to submit pull requests. By submitting pull request your
contribution to django-admin2 will be recorded by Github.
contribution to django-admin2 will be recorded by Github.
In git it is best to isolate each topic or feature into a "topic branch". While
individual commits allow you control over how small individual changes are made
@ -113,23 +113,24 @@ add a comment to the discussion section of the pull request.
Pull upstream changes into your fork regularly
==================================================
**django-admin2** is advancing quickly. It is therefore critical that you pull upstream changes from master into your fork on a regular basis. Nothing is worse than putting in a day of hard work into a pull request only to have it rejected because it has diverged too far from master.
**django-admin2** is advancing quickly. It is therefore critical that you pull upstream changes from master into your fork on a regular basis. Nothing is worse than putting in a day of hard work into a pull request only to have it rejected because it has diverged too far from master.
To pull in upstream changes::
git remote add upstream https://github.com/twoscoops/django-admin2.git
git fetch upstream develop
Check the log to be sure that you actually want the changes, before merging::
git log upstream/develop
Then merge the changes that you fetched::
git merge upstream/develop
git pull upstream develop
For more info, see http://help.github.com/fork-a-repo/
Advanced git users: Pull with rebase
------------------------------------
This will pull and then reapply your work on top of the upcoming changes::
git pull --rebase upstream develop
It saves you from an extra merge, keeping the history cleaner, but it's potentially dangerous because you're rewriting history. For more info, see http://gitready.com/advanced/2009/02/11/pull-with-rebase.html
How to get your pull request accepted
=====================================
@ -207,7 +208,7 @@ As much as possible, we follow the advice of the `Two Scoops of Django`_ book. P
Templates
~~~~~~~~~
Follow bootstrap's coding standards for HTML_ and CSS_. Use two spaces for indentation, and write so the templates are readable (not for the generated html).
Follow bootstrap's coding standards for HTML_ and CSS_. Use two spaces for indentation, and write so the templates are readable (not for the generated html).
.. _HTML: https://github.com/twitter/bootstrap/blob/master/CONTRIBUTING.md#coding-standards-html
.. _CSS: https://github.com/twitter/bootstrap/blob/master/CONTRIBUTING.md#coding-standards-css

View file

@ -1,29 +1,33 @@
=========================================
Welcome to django-admin2's documentation!
=========================================
.. image:: https://travis-ci.org/pydanny/django-admin2.png
:alt: Build Status
:target: https://travis-ci.org/pydanny/django-admin2
**Warning:** This project is currently in an **alpha** state and currently not meant for real projects.
One of the most useful parts of ``django.contrib.admin`` is the ability to configure various views that touch and alter data. django-admin2 is a complete rewrite of that library using modern Class-Based Views and enjoying a design focused on extendibility and adaptability. By starting over, we can avoid the legacy code and make it easier to write extensions and themes.
**django-admin2** aims to replace django's built-in admin that lives in
``django.contrib.admin``. Come and help us, have a look at the
:doc:`contributing` page and see our `GitHub`_ page.
``django.contrib.admin``. Come and help us, read the :doc:`design` and
:doc:`contributing` pages, and visit the `GitHub`_ project.
This project is intentionally backwards-incompatible with ``django.contrib.admin``.
Requirements
Features
=============
* Django 1.5+
* Python 2.7+ or Python 3.3+
* django-braces
* django-extra-views
* django-floppyforms
* django-rest-framework
* Sphinx (for documentation)
* Rewrite of the Django Admin backend
* Drop-in themes
* Built-in RESTful API
Basic API
==============
Our goal is to make this API work:
If you've worked with Django, this implementation should look familiar:
.. code-block:: python
@ -56,34 +60,30 @@ Content
.. toctree::
:maxdepth: 2
installation
contributing
design
architecture
api
themes
built-in-views
meta
tutorial
internationalization
Reference
-----------
Most of django-admin2 is designed to be extensible, which means with a little bit of Python code you can do amazing things. You can easily create custom actions, implement alternative forms, set permissions per view, add new views, and even trivially replace the base views with those of your own design. Combined with the REST API, django-admin2 provides a wealth of customization options.
One of the core design goals of django-admin2 is to embrace object-oriented design, making it easy to take one of the built-in classes and extend it to suit your needs.
.. toctree::
:maxdepth: 2
ref/themes
ref/api
ref/actions
ref/forms
ref/permissions
ref/views
ref/built-in-views
ref/meta
Indices and tables
==================
* :ref:`genindex`
* :ref:`modindex`
* :ref:`search`

48
docs/installation.rst Normal file
View file

@ -0,0 +1,48 @@
============
Installation
============
.. index:: installation
Adding django-admin2 to your project
====================================
Use pip to install from PyPI:
.. code-block:: python
pip install django-admin2
Add djadmin2 and rest_framework to your settings file:
.. code-block:: python
INSTALLED_APPS = (
...
'djadmin2',
'rest_framework', # for the browsable API templates
...
)
Add djadmin2 urls to your URLconf:
.. code-block:: python
# urls.py
from django.conf.urls import patterns, include
import djadmin2
djadmin2.default.autodiscover()
urlpatterns = patterns(
...
url(r'^admin2/', include(djadmin2.default.urls)),
)
Development Installation
=========================
See :doc:`contributing`.

View file

@ -0,0 +1,83 @@
=====================================
Internationalization and localization
=====================================
.. index:: internationalization
Refer to the `Django i18n documentation`_ to get started.
.. _`Django i18n documentation`: https://docs.djangoproject.com/en/dev/topics/i18n/
Using internationalization in your project
==========================================
Make sure you've activated translation for your project
(the fastest way is to check in your ``settings.py`` file if ``MIDDLEWARE_CLASSES`` includes
``django.middleware.locale.LocaleMiddleware``).
Then compile the messages so they can be used by Django.
.. code-block:: bash
python manage.py compilemessages
It should get you started !
Contributing to localization
============================
Django-admin2 has adopted `Transifex`_ to manage the localization process, `join and
help us`_ making django-admin2 available for everyone !
.. _Transifex: https://www.transifex.com
.. _`join and help us`: https://www.transifex.com/projects/p/django-admin2/
Using internationalization in the django-admin2 project development
===================================================================
Internationalization
--------------------
Python code
###########
Make sure to use ugettext or ugettext_lazy on strings that will be shown to the users,
with string interpolation ( "%(name_of_variable)s" instead of "%s" ) where needed.
Remember that all languages do not use the same word order, so try to provide flexible strings to translate !
Templates
#########
Make sure to load the i18n tags and put ``trans`` tags and ``blocktrans`` blocks where needed.
Block variables are very useful to keep the strings simple.
Adding a new locale
-------------------
.. code-block:: bash
cd djadmin2
django-admin.py makemessages -l $LOCALE_CODE
A new file will be created under ``locale/$LOCALE_CODE/LC_MESSAGES/django.po``
Update the headers of the newly created file to match existing files and start the translation !
Updating existing locales
-------------------------
.. code-block:: bash
cd djadmin2 # or any other package, for instance example/blog
django-admin.py makemessages -a
# update the translations
# make sure to fix all fuzzy translations
django-admin.py compilemessages

View file

@ -2,6 +2,8 @@
Actions
=======
.. index:: Actions
Actions are defined to work on a single view type. Currently, actions are only implemented against the ``ModelListView``. This view contains the default ``DeleteSelectedAction`` method, which in end functionality mirrors ``django.contrib.admin.delete_selected``.
However, under the hood, django-admin2's actions work very differently. Instead of functions with assigned attributes, they can either be functions or full fledged objects. Which means you can more easily extend them to suit your needs.
@ -39,6 +41,9 @@ The documentation works off a simple set of models, as listed below:
Writing List Actions
-----------------------
.. index::
single: Actions; Writing List Actions
The basic workflow of Djangos admin is, in a nutshell, “select an object, then change it.” This works well for a majority of use cases. However, if you need to make the same change to many objects at once, this workflow can be quite tedious.
In these cases, Djangos admin lets you write and register “actions” simple functions that get called with a list of objects selected on the change list page.

View file

@ -1,5 +1,5 @@
API
===
RESTful API
=============
**django-admin2** comes with a builtin REST-API for accessing all the
resources you can get from the frontend via JSON.

View file

@ -1,12 +1,27 @@
Built-In Views
===============
Each of these views contains the list of context variables that are included in their templates.
Each of these views contains the list of context variables that are included in
their templates.
TODO: Provide a list of template context variables for each view per GitHub issue in view class' top-level docstring `#220`_
TODO: Provide a list of template context variables for each view per GitHub
issue in view class' top-level docstring `#220`_
.. _`#220`: https://github.com/twoscoops/django-admin2/issues/220
View Constants
---------------
The following are available in every view:
:next: The page to redirect the user to after login
:MEDIA_URL: Specify a directory where file uploads for users who use your site go
:STATIC_URL: Specify a directory for JavaScript, CSS and image files.
:user: Currently logged in user
View Descriptions
------------------
.. autoclass:: djadmin2.views.IndexView
:members:
@ -27,11 +42,9 @@ TODO: Provide a list of template context variables for each view per GitHub issu
.. autoclass:: djadmin2.views.ModelAddFormView
:members:
.. autoclass:: djadmin2.views.ModelDeleteView
:members:
.. autoclass:: djadmin2.views.PasswordChangeView
:members:

View file

@ -48,7 +48,8 @@ Attributes copied from ``Meta``
Some of ``_meta``'s attributes are just copied from the ``Meta`` options. The
following attributes are those. Their behaviour is more detailed described in
the :doc:`django documentation <django:/ref/models/options>`.
the `django documentation
<https://docs.djangoproject.com/en/dev/ref/models/options/>`__.
``abstract``
A boolean value.
@ -87,7 +88,9 @@ the :doc:`django documentation <django:/ref/models/options>`.
:attr:`~django.db.models.Options.get_latest_by`.
``managed``
If ``managed`` is ``True`` then the :djadmin:`syncdb` management command will take care of creating the database tables. Defaults to ``True``.
If ``managed`` is ``True`` then the :django:djadmin:`syncdb` management
command will take care of creating the database tables. Defaults to
``True``.
Also see the django documentation about
:attr:`~django.db.models.Options.managed`.

View file

@ -1,6 +1,8 @@
Permissions
===========
.. index:: Permissions
Permissions are handled on a per view basis. So basically each admin view can
hold its own permissions. That way you are very flexible in defining
who is allowed to access which view. For example, the edit view might need some
@ -28,8 +30,11 @@ attribute:
See the following sections on which permission classes ship with
**django-admin2**, ready to use and how you can roll your own.
Builtin permission classes
--------------------------
Built-in permission classes
---------------------------
.. index::
single: Permissions; Built-In Permission Classes
You can use the following permission classes directly in you views.
@ -48,6 +53,9 @@ You can use the following permission classes directly in you views.
Writing your own permission class
---------------------------------
.. index::
single: Permissions; Custom Permission Classes
If you need it, writing your own permission class is really easy. You just need
to subclass the :class:`djadmin2.permissions.BasePermission` class and
overwrite the :meth:`~djadmin2.permissions.BasePermission.has_permission`
@ -89,9 +97,12 @@ Here is an example implementation of a custom permission class:
return False
return True
Permissions in templates
Permissions in Templates
------------------------
.. index::
single: Permissions; Permissions in Templates
Since the permission handling is designed around views, the permission checks
in the template will also always access a view and return either ``True`` or
``False`` if the user has access to the given view. There is a ``{{ permissions
@ -128,9 +139,12 @@ At the moment we can check for the following four basic permissions:
``has_delete_permission``
This will check the permissions against the current admin's ``delete_view``.
Object-level permissions
Object-Level Permissions
~~~~~~~~~~~~~~~~~~~~~~~~
.. index::
single: Permissions; Object-Level Permissions
The permission handling in templates also support checking for object-level
permissions. To do so, you can use the ``for_object`` filter implemented in the
``admin2_tags`` templatetag library:
@ -181,9 +195,12 @@ permissions as well:
{% include "list_of_model_actions.html" with permissions=object_permissions %}
{% endwith %}
Checking for permissions on other models
Checking for Permissions on Other Models
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. index::
single: Permissions; Checking for Permissions on Other Models
Sometimes you just need to check the permissions for that particular model. In
that case, you can access its permissions like this:
@ -214,9 +231,12 @@ to a model admin, you can use the ``for_admin`` filter:
{% endwith %}
{% endfor %}
Dynamically check for a specific permission name
Dynamically Check for a Specific Permission Name
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. index::
single: Permissions; Dynamically Check for a Specific Permission Name
Just like you can bind a permission dynamically to a model admin, you can also
specify the actual permission name on the fly. There is the ``for_view`` filter
to do so.

View file

@ -138,12 +138,12 @@ In the settings module, place the theme right after djadmin2 (change the highlig
)
########### END DJANGO-ADMIN2 CONFIGURATION
.. TODO:: Have someone besides pydanny test this!
.. todo:: Have someone besides pydanny test this!
Views and their Templates
-------------------------
See :ref:`Built-In Views`
See doc:`built-in-views`
Available Themes
@ -156,4 +156,4 @@ If you'd like to experiment with UI design that differs from the original Django
Future
------
Keep in mind that this project is an experiment just to get our ideas down. We are looking at other similar projects to see if we can merge or borrow things.
Keep in mind that this project is an experiment just to get our ideas down. We are looking at other similar projects to see if we can merge or borrow things.

View file

@ -11,7 +11,7 @@ class CustomPublishAction(BaseListAction):
)
description = ugettext_lazy('Publish selected items')
success_message = 'Successfully published %d %s'
success_message = ugettext_lazy('Successfully published %(count)s %(items)s')
default_template_name = "actions/publish_selected_items.html"

View file

@ -0,0 +1,30 @@
{% load i18n %}<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Example.com</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- Bootstrap -->
{% block css %}
<link href="{{ STATIC_URL }}themes/bootstrap/css/bootstrap.min.css" rel="stylesheet" media="screen">
<link href="{{ STATIC_URL }}themes/bootstrap/css/bootstrap-custom.css" rel="stylesheet" media="screen">
{% endblock css %}
</head>
<body>
<div class="container-fluid">
<div class="row-fluid">
<div class="{% block class_page_title %}span10{% endblock class_page_title %}">
<h3></h3>
</div>
</div>
{% block content %}{% endblock content %}
</div>
{% block javascript %}
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.1/jquery.min.js"></script>
<script>window.jQuery || document.write('<script src="{{ STATIC_URL }}themes/bootstrap/js/jquery.min.js">\x3C/script>')</script>
<script src="{{ STATIC_URL }}themes/bootstrap/js/bootstrap.min.js"></script>
{% endblock javascript %}
</body>
</html>

View file

@ -1,10 +1,48 @@
{% extends "admin2/bootstrap/base.html" %}
{% extends "base.html" %}
{% load staticfiles %}
{% block content %}
<h1>Example Home</h1>
<div class="row-fluid">
<div class="span10">
<h1>Example.com</h1>
<ul>
<li><a href="/admin2/">django-admin2</a></li>
<li><a href="/admin/">django.contrib.admin</a> (for reference)</li>
</ul>
<h3>Imagine that this is a real site</h3>
<p>Pretend that this is the homepage of a big Django site.</p>
<p>Imagine lots of things are here:</p>
<ul>
<li>A blog</li>
<li>Comments</li>
<li>And so on...</li>
</ul>
<p>In other words, these are items that we can introspect through the Django admin.</p>
<h3>Under the hood</h3>
<p>Now, explore the Django admin for example.com. Click on either of the following:</p>
</div>
</div>
<div class="row-fluid">
<div class="span5">
<h4>The original <a href="/admin/">Django Admin</a></h4>
<a href="/admin/">
<img class="img-polaroid" src="{% static 'img/admin.png' %}" />
</a>
<p>Powered by django.contrib.admin. This is just here for reference.</p>
</div>
<div class="offset1 span5">
<h4>The new <a href="/admin2/">Admin2</a></h4>
<a href="/admin2/">
<img class="img-polaroid" src="{% static 'img/admin2.png' %}" />
</a>
<p>Powered by django-admin2.</p>
</div>
</div>
{% endblock %}

View file

@ -1,4 +1,4 @@
{% extends "admin2/bootstrap/base.html" %}
{% extends "djadmin2/bootstrap/base.html" %}
{% load admin2_tags i18n %}
{% block title %}Are you sure?{% endblock title %}

View file

@ -1,4 +1,7 @@
# Django settings for example project.
import os
BASE_DIR = os.path.dirname(os.path.dirname(__file__))
DEBUG = True
TEMPLATE_DEBUG = DEBUG
@ -67,6 +70,7 @@ STATICFILES_DIRS = (
# Put strings here, like "/home/html/static" or "C:/www/django/static".
# Always use forward slashes, even on Windows.
# Don't forget to use absolute paths, not relative paths.
os.path.join(BASE_DIR, "static"),
)
# List of finder classes that know how to find static files in
@ -89,6 +93,7 @@ TEMPLATE_LOADERS = (
MIDDLEWARE_CLASSES = (
'django.middleware.common.CommonMiddleware',
'django.middleware.locale.LocaleMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
@ -157,7 +162,7 @@ LOGGING = {
}
ADMIN2_THEME_DIRECTORY = "admin2/bootstrap/"
ADMIN2_THEME_DIRECTORY = "djadmin2/bootstrap/"
########## TOOLBAR CONFIGURATION

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

View file

@ -88,6 +88,7 @@ TEMPLATE_LOADERS = (
)
MIDDLEWARE_CLASSES = (
'django.middleware.locale.LocaleMiddleware',
'django.middleware.common.CommonMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
@ -124,6 +125,14 @@ INSTALLED_APPS = (
'polls',
)
try:
import django_extensions
INSTALLED_APPS += (
'django_extensions',
)
except ImportError:
pass
# A sample logging configuration. The only tangible logging
# performed by this configuration is to send an email to
# the site admins on every HTTP 500 error when DEBUG=False.
@ -154,4 +163,24 @@ LOGGING = {
}
ADMIN2_THEME_DIRECTORY = "admin2/bootstrap/"
ADMIN2_THEME_DIRECTORY = "djadmin2/bootstrap/"
########## TOOLBAR CONFIGURATION
# See: https://github.com/django-debug-toolbar/django-debug-toolbar#installation
INSTALLED_APPS += (
'debug_toolbar',
)
# See: https://github.com/django-debug-toolbar/django-debug-toolbar#installation
INTERNAL_IPS = ('127.0.0.1',)
# See: https://github.com/django-debug-toolbar/django-debug-toolbar#installation
MIDDLEWARE_CLASSES += (
'debug_toolbar.middleware.DebugToolbarMiddleware',
)
DEBUG_TOOLBAR_CONFIG = {
'INTERCEPT_REDIRECTS': False,
'SHOW_TEMPLATE_CONTEXT': True,
}
########## END TOOLBAR CONFIGURATION

View file

@ -1,4 +1,4 @@
{% extends "admin2/bootstrap/base.html" %}
{% extends "djadmin2/bootstrap/base.html" %}
{% block content %}
<h1>Example Home</h1>