mirror of
https://github.com/jazzband/django-admin2.git
synced 2026-04-21 07:11:07 +00:00
Merge remote-tracking branch 'origin/develop' into inline-formsets
This commit is contained in:
commit
c051b8807a
18 changed files with 170 additions and 57 deletions
|
|
@ -15,3 +15,4 @@ Developers
|
|||
* Andrew Ingram (@AndrewIngram)
|
||||
* Gregor Müllegger (@gregmuellegger)
|
||||
* Rivo Laks (@rivol)
|
||||
* Chris Lawlor (@chrislawlor)
|
||||
|
|
|
|||
10
README.rst
10
README.rst
|
|
@ -10,6 +10,11 @@ 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.
|
||||
|
||||
Contributing
|
||||
=============
|
||||
|
||||
Yes please! Please read our formal contributing document at: https://django-admin2.readthedocs.org/en/latest/contributing.html
|
||||
|
||||
Features (current)
|
||||
====================
|
||||
|
||||
|
|
@ -39,11 +44,6 @@ Requirements
|
|||
* django-floppyforms
|
||||
* Sphinx (for documentation)
|
||||
|
||||
Contributing
|
||||
=============
|
||||
|
||||
Yes please! Please read our formal contributing document at: https://github.com/pydanny/django-admin2/blob/master/docs/contributing.rst
|
||||
|
||||
Basic Pattern
|
||||
==============
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
"""
|
||||
WARNING: This file about to undergo major refactoring by @pydanny per Issue #99.
|
||||
"""
|
||||
|
||||
from django.conf.urls import patterns, include, url
|
||||
from django.conf import settings
|
||||
from django.core.exceptions import ImproperlyConfigured
|
||||
|
|
@ -79,7 +83,6 @@ class Admin2(object):
|
|||
Autodiscovers all admin2.py modules for apps in INSTALLED_APPS by
|
||||
trying to import them.
|
||||
"""
|
||||
apps = []
|
||||
for app_name in [x for x in settings.INSTALLED_APPS]:
|
||||
try:
|
||||
import_module("%s.admin2" % app_name)
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
"""
|
||||
WARNING: This file about to undergo major refactoring by @pydanny per Issue #99.
|
||||
|
||||
For wont of a better name, this module is called 'models'. It's role is
|
||||
synonymous with the django.contrib.admin.sites model.
|
||||
|
|
@ -13,10 +14,11 @@ from django.db.models import get_models, signals
|
|||
from djadmin2 import apiviews
|
||||
from djadmin2 import views
|
||||
|
||||
try:
|
||||
import floppyforms as forms
|
||||
except ImportError:
|
||||
from django import forms
|
||||
MODEL_ADMIN_ATTRS = (
|
||||
'list_display', 'list_display_links', 'list_filter',
|
||||
'admin', 'has_permission', 'has_add_permission',
|
||||
'has_edit_permission', 'has_delete_permission',
|
||||
)
|
||||
|
||||
|
||||
class BaseAdmin2(object):
|
||||
|
|
@ -92,6 +94,7 @@ class ModelAdmin2(BaseAdmin2):
|
|||
Warning: This class is targeted for reduction.
|
||||
It's bloated and ugly.
|
||||
"""
|
||||
|
||||
list_display = ('__str__',)
|
||||
list_display_links = ()
|
||||
list_filter = ()
|
||||
|
|
@ -104,6 +107,7 @@ class ModelAdmin2(BaseAdmin2):
|
|||
save_on_top = False
|
||||
verbose_name = None
|
||||
verbose_name_plural = None
|
||||
model_admin_attributes = MODEL_ADMIN_ATTRS
|
||||
|
||||
create_form_class = None
|
||||
update_form_class = None
|
||||
|
|
@ -140,7 +144,7 @@ class ModelAdmin2(BaseAdmin2):
|
|||
'app_label': self.app_label,
|
||||
'model': self.model,
|
||||
'model_name': self.model_name,
|
||||
'model_admin': self,
|
||||
'model_admin': ImmutableAdmin(self),
|
||||
}
|
||||
|
||||
def get_default_api_view_kwargs(self):
|
||||
|
|
@ -243,6 +247,26 @@ class ModelAdmin2(BaseAdmin2):
|
|||
def api_urls(self):
|
||||
return self.get_api_urls(), None, None
|
||||
|
||||
|
||||
class ImmutableAdmin(object):
|
||||
"""
|
||||
Only __init__ allows setting of attributes
|
||||
"""
|
||||
|
||||
def __init__(self, model_admin):
|
||||
""" The __init__ is the only method where the ImmutableModelAdmin allows
|
||||
for setting of values.
|
||||
"""
|
||||
for attr_name in model_admin.model_admin_attributes:
|
||||
setattr(self, attr_name, getattr(model_admin, attr_name))
|
||||
|
||||
self.__delattr__ = self._immutable
|
||||
self.__setattr__ = self._immutable
|
||||
|
||||
def _immutable(self, name, value):
|
||||
raise TypeError("Can't modify immutable model admin")
|
||||
|
||||
|
||||
def create_extra_permissions(app, created_models, verbosity, **kwargs):
|
||||
"""
|
||||
Creates 'view' permissions for all models.
|
||||
|
|
@ -288,4 +312,4 @@ def create_extra_permissions(app, created_models, verbosity, **kwargs):
|
|||
|
||||
|
||||
signals.post_syncdb.connect(create_extra_permissions,
|
||||
dispatch_uid = "django-admin2.djadmin2.models.create_extra_permissions")
|
||||
dispatch_uid="django-admin2.djadmin2.models.create_extra_permissions")
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
<!DOCTYPE html>
|
||||
{% load i18n %}<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
|
||||
<title>django-admin2</title>
|
||||
<title>{% block title %}Site administration{% endblock %} | django-admin2</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<!-- Bootstrap -->
|
||||
<link href="{{ STATIC_URL }}themes/bootstrap/css/bootstrap.min.css" rel="stylesheet" media="screen">
|
||||
|
|
@ -16,14 +16,41 @@
|
|||
<a class="brand" href="{% url 'admin2:dashboard' %}">Django-Admin2</a>
|
||||
|
||||
<ul class="nav pull-right">
|
||||
<li><a href="{% url 'admin2:api-index' %}">API</a></li>
|
||||
<li><a href="TODO">Log out</a></li>
|
||||
<li><a tabindex="-1" href="{% url 'admin2:api-index' %}">{% trans "API" %}</a></li>
|
||||
|
||||
{% if docsroot %}
|
||||
<li><a href="{{ docsroot }}">{% trans 'Documentation' %}</a></li>
|
||||
{% endif %}
|
||||
<li class="dropdown">
|
||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown">
|
||||
{% if user.get_full_name %}
|
||||
{{ user.get_full_name }}
|
||||
{% else %}
|
||||
{% blocktrans with user=user.username %}
|
||||
Logged in as {{ user }}
|
||||
{% endblocktrans %}
|
||||
{% endif %}
|
||||
<b class="caret"></b>
|
||||
</a>
|
||||
<ul class="dropdown-menu">
|
||||
</strong>
|
||||
{% if user.has_usable_password %}
|
||||
<li><a tabindex="-1" href="TODO">{% trans "Change password" %}</a></li>
|
||||
{% endif %}
|
||||
<li><a tabindex="-1" href="TODO">{% trans "Log out" %}</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<div class="span10">
|
||||
<h3>{% block page_title %}Site administration{% endblock %}</h3>
|
||||
</div>
|
||||
</div>
|
||||
{% block content %}{% endblock %}
|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@
|
|||
{% load admin2_urls %}
|
||||
|
||||
{% block content %}
|
||||
<h3>Site administration</h3>
|
||||
|
||||
<div class="row">
|
||||
<div class="span7">
|
||||
|
|
|
|||
|
|
@ -1,5 +1,9 @@
|
|||
{% extends "admin2/bootstrap/base.html" %}
|
||||
|
||||
{% block title %}Add {{ model }}{% endblock %}
|
||||
|
||||
{% block page_title %}Add {{ model }}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<form method="post">
|
||||
|
|
|
|||
|
|
@ -1,10 +1,16 @@
|
|||
{% extends "admin2/bootstrap/base.html" %}
|
||||
|
||||
{% block title %}Are you sure?{% endblock %}
|
||||
|
||||
{% block page_title %}Are you sure?{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<p>Are you sure you want to delete the {{ model }} "{{ object }}"? All of the following related items will be deleted:</p>
|
||||
|
||||
TODO
|
||||
|
||||
<form method="post">
|
||||
{% csrf_token %}
|
||||
delete {{ object }}
|
||||
{{ form.as_p }}
|
||||
<input type="submit"/>
|
||||
</form>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,9 @@
|
|||
{% extends "admin2/bootstrap/base.html" %}
|
||||
|
||||
{% block title %}{{ object }}{% endblock %}
|
||||
|
||||
{% block page_title %}{{ object }}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
{{ object }}
|
||||
|
|
|
|||
|
|
@ -1,14 +1,11 @@
|
|||
{% extends "admin2/bootstrap/base.html" %}
|
||||
|
||||
{% block title %}Change {{ model }}{% endblock %}
|
||||
|
||||
{% block page_title %}Change {{ model }}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<div class="row">
|
||||
<div class="span10">
|
||||
<h3>Change {{ model }}</h3>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="row">
|
||||
<div class="span12">
|
||||
<form method="post">
|
||||
|
|
|
|||
|
|
@ -1,13 +1,11 @@
|
|||
{% extends "admin2/bootstrap/base.html" %}
|
||||
{% load admin2_urls %}
|
||||
|
||||
{% block content %}
|
||||
<div class="row">
|
||||
<div class="span10">
|
||||
<h3>Select {{ model }} to change</h3>
|
||||
</div>
|
||||
</div>
|
||||
{% block title %}Select {{ model }} to change{% endblock %}
|
||||
|
||||
{% block page_title %}Select {{ model }} to change{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<div class="row">
|
||||
<div class="span12">
|
||||
|
|
@ -36,10 +34,12 @@
|
|||
</thead>
|
||||
<tbody>
|
||||
{% for obj in object_list %}
|
||||
<td><input type="checkbox"></td>
|
||||
<td>
|
||||
<a href="{% url view|admin2_urlname:'update' pk=obj.pk %}">{{ obj }}</a>
|
||||
</td>
|
||||
<tr>
|
||||
<td><input type="checkbox"></td>
|
||||
<td>
|
||||
<a href="{% url view|admin2_urlname:'update' pk=obj.pk %}">{{ obj }}</a>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
|
|
|
|||
|
|
@ -9,4 +9,3 @@ def admin2_urlname(view, action):
|
|||
Converts the view and the specified action into a valid namespaced URLConf name.
|
||||
"""
|
||||
return 'admin2:%s_%s_%s' % (view.app_label, view.model_name, action)
|
||||
|
||||
|
|
|
|||
|
|
@ -60,6 +60,8 @@ class AdminModel2Mixin(Admin2Mixin, AccessMixin):
|
|||
'has_add_permission': self.model_admin.has_add_permission(self.request),
|
||||
'has_edit_permission': self.model_admin.has_edit_permission(self.request),
|
||||
'has_delete_permission': self.model_admin.has_delete_permission(self.request),
|
||||
'model': self.get_model()._meta.verbose_name,
|
||||
'model_pluralized': self.get_model()._meta.verbose_name_plural
|
||||
})
|
||||
return context
|
||||
|
||||
|
|
@ -90,7 +92,6 @@ class IndexView(Admin2Mixin, generic.TemplateView):
|
|||
|
||||
|
||||
class ModelListView(Admin2Mixin, generic.ListView):
|
||||
|
||||
default_template_name = "model_list.html"
|
||||
permission_type = 'view'
|
||||
|
||||
|
|
@ -116,17 +117,17 @@ class ModelEditFormView(AdminModel2Mixin, extra_views.UpdateWithInlinesView):
|
|||
default_template_name = "model_edit_form.html"
|
||||
permission_type = 'change'
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super(ModelEditFormView, self).get_context_data(**kwargs)
|
||||
context['model'] = self.get_model()._meta.verbose_name
|
||||
return context
|
||||
|
||||
|
||||
class ModelAddFormView(AdminModel2Mixin, extra_views.CreateWithInlinesView):
|
||||
form_class = None
|
||||
default_template_name = "model_add_form.html"
|
||||
permission_type = 'add'
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super(ModelAddFormView, self).get_context_data(**kwargs)
|
||||
context['model'] = self.get_model()._meta.verbose_name
|
||||
return context
|
||||
|
||||
def get_success_url(self):
|
||||
view_name = 'admin2:{}_{}_detail'.format(self.app_label, self.model_name)
|
||||
return reverse(view_name, kwargs={'pk': self.object.pk})
|
||||
|
|
|
|||
22
docs/architecture.rst
Normal file
22
docs/architecture.rst
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
================
|
||||
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
|
||||
|
|
@ -48,9 +48,9 @@ copyright = u'2013, Daniel Greenfeld'
|
|||
# built documents.
|
||||
#
|
||||
# The short X.Y version.
|
||||
version = '0.1'
|
||||
version = '0.2'
|
||||
# The full version, including alpha/beta/rc tags.
|
||||
release = '0.1.0'
|
||||
release = '0.2.0'
|
||||
|
||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||
# for a list of supported languages.
|
||||
|
|
|
|||
|
|
@ -2,6 +2,10 @@
|
|||
Contributing
|
||||
============
|
||||
|
||||
.. note:: Before you begin working on your contribution, please read and become familiar with the design_ of ``django-admin2``. The design_ document should hopefully make it clear what our constraints and goals are for the project.
|
||||
|
||||
.. _design: https://django-admin2.readthedocs.org/en/latest/design.html
|
||||
|
||||
Setup
|
||||
=====
|
||||
|
||||
|
|
|
|||
|
|
@ -2,22 +2,42 @@
|
|||
Design
|
||||
======
|
||||
|
||||
Workflow Pieces
|
||||
Constraints
|
||||
------------
|
||||
|
||||
This section outlines the design constraints that django-admin2 follows:
|
||||
|
||||
1. There will be nothing imported from ``django.contrib.admin``.
|
||||
2. The original bootstrap/ theme shall contain no UI enhancements beyond the original ``django.contrib.admin`` UI. (However, future themes can and should be experimental.)
|
||||
3. External package dependencies are allowed but should be very limited.
|
||||
4. Building a django-admin2 theme cannot involve learning Python, which explains why we are not using tools like django-crispy-forms. (One of our goals is to make it easier for designers to explore theming django-admin2).
|
||||
|
||||
Backend Goals
|
||||
---------------
|
||||
|
||||
Rather than creating yet another project that skins ``django.contrib.admin``, our goal is to rewrite ``django.contrib.admin`` from the ground up using Class-Based Views, better state management, and attention to all the lessons learned from difficult admin customizations over the years.
|
||||
|
||||
While the internal API for the backend may be drastically different, the end goal is to achieve relative parity with existing functionality in an extendable way:
|
||||
|
||||
* Relative functional parity with ``django.contrib.admin``. This is our desire to replicate much of the existing functionality, but not have to worry too much about coding ourselves into an overly-architected corner.
|
||||
* Extensible presentation and data views in such a way that it does not violate Constraint #4. To cover many cases, we will provide instructions on how to use the REST API to fetch data rather than create overly complex backend code.
|
||||
|
||||
Clean code with substantial documentation is also a goal:
|
||||
|
||||
1. Create a clearly understandable/testable code base.
|
||||
2. All classes/methods/functions documented.
|
||||
3. Provide a wealth of in-line code documentation.
|
||||
|
||||
REST API Goals
|
||||
----------------
|
||||
|
||||
* Apps
|
||||
* Apps.models
|
||||
* AdminObj
|
||||
* Appstore
|
||||
There are a lot of various cases that are hard to handle with pure HTML projects, but are trivial to resolve if a REST API is available. For example, using unmodified ``django.contrib.admin`` on projects with millions of database records combined with foreign key lookups. In order to handle these cases, rather than explore each edge case, ``django-admin2`` provides a RESTFUL API as of version 0.2.0.
|
||||
|
||||
Workflow
|
||||
----------------
|
||||
Goals:
|
||||
|
||||
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
|
||||
1. Provide a extendable self-documenting API (django-rest-framework).
|
||||
2. Reuse components from the HTML view.
|
||||
3. Backwards compatibility: Use a easily understood API versioning system so we can expand functionality of the API without breaking existing themes.
|
||||
|
||||
UI Goals
|
||||
---------
|
||||
|
|
@ -25,3 +45,4 @@ UI Goals
|
|||
1. Replicate the old admin UI as closely as possible in the bootstrap/ theme. This helps us ensure that admin2/ functionality has parity with admin/.
|
||||
|
||||
2. Once (1) is complete and we have a stable underlying API, experiment with more interesting UI variations.
|
||||
|
||||
|
|
|
|||
|
|
@ -53,8 +53,9 @@ Content
|
|||
:maxdepth: 2
|
||||
|
||||
contributing
|
||||
api
|
||||
design
|
||||
architecture
|
||||
api
|
||||
themes
|
||||
meta
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue