mirror of
https://github.com/jazzband/django-admin2.git
synced 2026-03-26 19:10:26 +00:00
Merge remote-tracking branch 'upstream/master'
This commit is contained in:
commit
bbb8207217
7 changed files with 188 additions and 42 deletions
|
|
@ -14,4 +14,4 @@ Developers
|
|||
* Raphael Kimmig (@RaphaelKimmig)
|
||||
* Andrew Ingram (@AndrewIngram)
|
||||
* Gregor Müllegger (@gregmuellegger)
|
||||
|
||||
* Rivo Laks (@rivol)
|
||||
|
|
|
|||
|
|
@ -5,6 +5,8 @@ synonymous with the django.contrib.admin.sites model.
|
|||
|
||||
"""
|
||||
from django.conf.urls import patterns, include, url
|
||||
from django.contrib.auth import models as auth_app
|
||||
from django.db.models import get_models, signals
|
||||
|
||||
from djadmin2 import views
|
||||
|
||||
|
|
@ -44,24 +46,42 @@ class BaseAdmin2(object):
|
|||
readonly_fields = ()
|
||||
ordering = None
|
||||
|
||||
def has_view_permission(self, request):
|
||||
"""
|
||||
Returns True if the given HttpRequest has permission to view
|
||||
*at least one* page in the mongonaut site.
|
||||
"""
|
||||
return request.user.is_authenticated() and request.user.is_active
|
||||
|
||||
def has_edit_permission(self, request):
|
||||
def __init__(self, model):
|
||||
super(BaseAdmin2, self).__init__()
|
||||
|
||||
self.model = model
|
||||
|
||||
|
||||
def _user_has_permission(self, user, permission_type, obj=None):
|
||||
""" Generic method for checking whether the user has permission of specified type for the model.
|
||||
Type can be one of view, add, change, delete.
|
||||
You can also specify instance of the model for object-specific permission check.
|
||||
"""
|
||||
if not user.is_authenticated() or not user.is_staff:
|
||||
return False
|
||||
opts = self.model._meta
|
||||
full_permission_name = '%s.%s_%s' % (opts.app_label, permission_type, opts.object_name.lower())
|
||||
return user.has_perm(full_permission_name, obj)
|
||||
|
||||
def has_permission(self, request, permission_type, obj=None):
|
||||
return self._user_has_permission(request.user, permission_type, obj)
|
||||
|
||||
def has_view_permission(self, request, obj=None):
|
||||
""" Can view this object """
|
||||
return self.has_permission(request, 'view', obj)
|
||||
|
||||
def has_edit_permission(self, request, obj=None):
|
||||
""" Can edit this object """
|
||||
return request.user.is_authenticated() and request.user.is_active and request.user.is_staff
|
||||
return self.has_permission(request, 'change', obj)
|
||||
|
||||
def has_add_permission(self, request):
|
||||
def has_add_permission(self, request, obj=None):
|
||||
""" Can add this object """
|
||||
return request.user.is_authenticated() and request.user.is_active and request.user.is_staff
|
||||
return self.has_permission(request, 'add', obj)
|
||||
|
||||
def has_delete_permission(self, request):
|
||||
def has_delete_permission(self, request, obj=None):
|
||||
""" Can delete this object """
|
||||
return request.user.is_authenticated() and request.user.is_active and request.user.is_superuser
|
||||
return self.has_permission(request, 'delete', obj)
|
||||
|
||||
|
||||
class ModelAdmin2(BaseAdmin2):
|
||||
|
|
@ -134,12 +154,12 @@ class ModelAdmin2(BaseAdmin2):
|
|||
),
|
||||
url(
|
||||
regex=r'^create/$',
|
||||
view=self.create_view.as_view(**self.get_create_kwargs()),
|
||||
view=self.create_view.as_view(**self.get_create_kwargs()),
|
||||
name='create'
|
||||
),
|
||||
url(
|
||||
regex=r'^(?P<pk>[0-9]+)/$',
|
||||
view=self.detail_view.as_view(**self.get_detail_kwargs()),
|
||||
view=self.detail_view.as_view(**self.get_detail_kwargs()),
|
||||
name='detail'
|
||||
),
|
||||
url(
|
||||
|
|
@ -158,3 +178,55 @@ class ModelAdmin2(BaseAdmin2):
|
|||
def urls(self):
|
||||
# We set the application and instance namespace here
|
||||
return self.get_urls(), None, None
|
||||
|
||||
|
||||
|
||||
def create_permissions(app, created_models, verbosity, **kwargs):
|
||||
"""
|
||||
Creates 'view' permissions for all models.
|
||||
django.contrib.auth only creates add, change and delete permissions. Since we also support read-only views, we need
|
||||
to add our own extra permission.
|
||||
Copied from django.contrib.auth.management.create_permissions
|
||||
"""
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
|
||||
def _get_permission_codename(action, opts):
|
||||
return u'%s_%s' % (action, opts.object_name.lower())
|
||||
|
||||
app_models = get_models(app)
|
||||
|
||||
# This will hold the permissions we're looking for as
|
||||
# (content_type, (codename, name))
|
||||
searched_perms = list()
|
||||
# The codenames and ctypes that should exist.
|
||||
ctypes = set()
|
||||
for klass in app_models:
|
||||
ctype = ContentType.objects.get_for_model(klass)
|
||||
ctypes.add(ctype)
|
||||
|
||||
opts = klass._meta
|
||||
perm = (_get_permission_codename('view', opts), u'Can view %s' % opts.verbose_name_raw)
|
||||
searched_perms.append((ctype, perm))
|
||||
|
||||
# Find all the Permissions that have a context_type for a model we're
|
||||
# looking for. We don't need to check for codenames since we already have
|
||||
# a list of the ones we're going to create.
|
||||
all_perms = set(auth_app.Permission.objects.filter(
|
||||
content_type__in=ctypes,
|
||||
).values_list(
|
||||
"content_type", "codename"
|
||||
))
|
||||
|
||||
objs = [
|
||||
auth_app.Permission(codename=codename, name=name, content_type=ctype)
|
||||
for ctype, (codename, name) in searched_perms
|
||||
if (ctype.pk, codename) not in all_perms
|
||||
]
|
||||
auth_app.Permission.objects.bulk_create(objs)
|
||||
if verbosity >= 2:
|
||||
for obj in objs:
|
||||
print "Adding permission '%s'" % obj
|
||||
|
||||
|
||||
signals.post_syncdb.connect(create_permissions,
|
||||
dispatch_uid = "django-admin2.djadmin2.models.create_permissions")
|
||||
|
|
|
|||
|
|
@ -1,11 +1,42 @@
|
|||
{% extends "admin2/bootstrap/base.html" %}
|
||||
|
||||
{% block content %}
|
||||
<a href="./create/">add</a>
|
||||
<hr/>
|
||||
{% for obj in object_list %}
|
||||
{{ obj }} <a href="./{{ obj.pk }}/">detail</a> <a href="./{{ obj.pk }}/update/">edit</a> <a href="./{{ obj.pk }}/delete/">delete</a><br/>
|
||||
{% endfor %}
|
||||
<div class="row">
|
||||
<div class="span10">
|
||||
<h3>Select {{ model }} to change</h3>
|
||||
</div>
|
||||
<div class="span2">
|
||||
{% if has_add_permission %}
|
||||
<a class="btn" href="./create/">Add {{ model|title }} <i class=" icon-plus-sign"></i></a>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
||||
<div class="row">
|
||||
<div class="span12">
|
||||
<table class="table table-bordered table-striped">
|
||||
<thead>
|
||||
<th><input type="checkbox"></th>
|
||||
<th>{{ model|title}}</th>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for obj in object_list %}
|
||||
<td><input type="checkbox"></td>
|
||||
<td>
|
||||
{{ obj }} <a href="./{{ obj.pk }}/">detail</a>
|
||||
{% if has_edit_permission %}
|
||||
<a href="./{{ obj.pk }}/update/">edit</a>
|
||||
{% endif %}
|
||||
{% if has_delete_permission %}
|
||||
<a href="./{{ obj.pk }}/delete/">delete</a>
|
||||
{% endif %}
|
||||
</td>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endblock content %}
|
||||
|
|
|
|||
|
|
@ -1,21 +1,52 @@
|
|||
import os
|
||||
|
||||
from django.conf import settings
|
||||
from django.contrib.auth.views import redirect_to_login
|
||||
from django.core.exceptions import PermissionDenied
|
||||
from django.forms.models import modelform_factory
|
||||
from django.views import generic
|
||||
from django.db import models
|
||||
|
||||
from braces.views import LoginRequiredMixin, StaffuserRequiredMixin
|
||||
from braces.views import LoginRequiredMixin, StaffuserRequiredMixin, AccessMixin
|
||||
|
||||
|
||||
ADMIN2_THEME_DIRECTORY = getattr(settings, "ADMIN2_THEME_DIRECTORY", "admin2/bootstrap")
|
||||
|
||||
class Admin2Mixin(object):
|
||||
modeladmin = None
|
||||
|
||||
class Admin2Mixin(object):
|
||||
def get_template_names(self):
|
||||
return [os.path.join(ADMIN2_THEME_DIRECTORY, self.default_template_name)]
|
||||
|
||||
|
||||
class AdminModel2Mixin(Admin2Mixin, AccessMixin):
|
||||
modeladmin = None
|
||||
# Permission type to check for when a request is sent to this view.
|
||||
permission_type = None
|
||||
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
# Check if user has necessary permissions. If the permission_type isn't specified then check for staff status.
|
||||
print "distpatch perm check:", self.permission_type
|
||||
has_permission = self.modeladmin.has_permission(request, self.permission_type) \
|
||||
if self.permission_type else request.user.is_staff
|
||||
# Raise exception or redirect to login if user doesn't have permissions.
|
||||
if not has_permission:
|
||||
if self.raise_exception:
|
||||
raise PermissionDenied # return a forbidden response
|
||||
else:
|
||||
return redirect_to_login(request.get_full_path(),
|
||||
self.get_login_url(), self.get_redirect_field_name())
|
||||
|
||||
return super(AdminModel2Mixin, self).dispatch(request, *args, **kwargs)
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super(AdminModel2Mixin, self).get_context_data(**kwargs)
|
||||
context.update({
|
||||
'has_add_permission': self.modeladmin.has_add_permission(self.request),
|
||||
'has_edit_permission': self.modeladmin.has_edit_permission(self.request),
|
||||
'has_delete_permission': self.modeladmin.has_delete_permission(self.request),
|
||||
})
|
||||
return context
|
||||
|
||||
def get_model(self):
|
||||
return self.model
|
||||
|
||||
|
|
@ -39,26 +70,37 @@ class IndexView(Admin2Mixin, generic.TemplateView):
|
|||
})
|
||||
return data
|
||||
|
||||
class ModelListView(Admin2Mixin, generic.ListView):
|
||||
class ModelListView(AdminModel2Mixin, generic.ListView):
|
||||
default_template_name = "model_list.html"
|
||||
permission_type = 'view'
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super(ModelListView, self).get_context_data(**kwargs)
|
||||
context['model'] = self.get_model()._meta.verbose_name
|
||||
context['model_pluralized'] = self.get_model()._meta.verbose_name_plural
|
||||
return context
|
||||
|
||||
|
||||
class ModelDetailView(Admin2Mixin, generic.DetailView):
|
||||
class ModelDetailView(AdminModel2Mixin, generic.DetailView):
|
||||
default_template_name = "model_detail.html"
|
||||
permission_type = 'view'
|
||||
|
||||
|
||||
class ModelEditFormView(Admin2Mixin, generic.UpdateView):
|
||||
class ModelEditFormView(AdminModel2Mixin, generic.UpdateView):
|
||||
form_class = None
|
||||
success_url = "../../"
|
||||
default_template_name = "model_edit_form.html"
|
||||
permission_type = 'change'
|
||||
|
||||
|
||||
class ModelAddFormView(Admin2Mixin, generic.CreateView):
|
||||
class ModelAddFormView(AdminModel2Mixin, generic.CreateView):
|
||||
form_class = None
|
||||
success_url = "../"
|
||||
default_template_name = "model_add_form.html"
|
||||
permission_type = 'add'
|
||||
|
||||
|
||||
class ModelDeleteView(Admin2Mixin, generic.DeleteView):
|
||||
class ModelDeleteView(AdminModel2Mixin, generic.DeleteView):
|
||||
success_url = "../../"
|
||||
default_template_name = "model_delete.html"
|
||||
permission_type = 'delete'
|
||||
|
|
|
|||
|
|
@ -12,17 +12,24 @@ Our goal is to make this API work:
|
|||
|
||||
.. code-block:: python
|
||||
|
||||
# myapp/admin2.py
|
||||
# Import your custom models
|
||||
from .models import Post, Comment
|
||||
from django.contrib.auth.forms import UserCreationForm, UserChangeForm
|
||||
from django.contrib.auth.models import User
|
||||
|
||||
# Import the Admin2 base class
|
||||
from djadmin2.models import Admin2
|
||||
import djadmin2
|
||||
from djadmin2.models import ModelAdmin2
|
||||
|
||||
# Import your custom models
|
||||
from blog.models import Post
|
||||
|
||||
# Instantiate the Admin2 class
|
||||
# Then attach the admin2 object to your model
|
||||
Post.admin2 = Admin2()
|
||||
class UserAdmin2(ModelAdmin2):
|
||||
create_form_class = UserCreationForm
|
||||
update_form_class = UserChangeForm
|
||||
|
||||
|
||||
# Register each model with the admin
|
||||
djadmin2.default.register(Post)
|
||||
djadmin2.default.register(Comment)
|
||||
djadmin2.default.register(User, UserAdmin2)
|
||||
|
||||
|
||||
.. _GitHub: https://github.com/pydanny/django-admin2
|
||||
|
|
|
|||
|
|
@ -8,12 +8,6 @@ import djadmin2
|
|||
djadmin2.default.autodiscover()
|
||||
|
||||
urlpatterns = patterns('',
|
||||
# Examples:
|
||||
url(r'^admin2/', include(djadmin2.default.urls)),
|
||||
# url(r'^example/', include('example.foo.urls')),
|
||||
|
||||
# Uncomment the admin/doc line below to enable admin documentation:
|
||||
# url(r'^admin/doc/', include('django.contrib.admindocs.urls')),
|
||||
|
||||
url(r'^admin/', include(admin.site.urls)),
|
||||
)
|
||||
|
|
|
|||
Loading…
Reference in a new issue