mirror of
https://github.com/jazzband/django-admin2.git
synced 2026-04-21 23:24:42 +00:00
Merge branch 'inline-formsets' of git://github.com/AndrewIngram/django-admin2 into AndrewIngram-inline-formsets
This commit is contained in:
commit
bb3d4712b9
7 changed files with 123 additions and 15 deletions
|
|
@ -11,6 +11,8 @@ from django.conf.urls import patterns, url
|
|||
from django.contrib.auth import models as auth_app
|
||||
from django.db.models import get_models, signals
|
||||
|
||||
import extra_views
|
||||
|
||||
from djadmin2 import apiviews
|
||||
from djadmin2 import views
|
||||
|
||||
|
|
@ -112,6 +114,8 @@ class ModelAdmin2(BaseAdmin2):
|
|||
create_form_class = None
|
||||
update_form_class = None
|
||||
|
||||
inlines = []
|
||||
|
||||
# Views
|
||||
index_view = views.ModelListView
|
||||
create_view = views.ModelAddFormView
|
||||
|
|
@ -161,6 +165,7 @@ class ModelAdmin2(BaseAdmin2):
|
|||
def get_create_kwargs(self):
|
||||
kwargs = self.get_default_view_kwargs()
|
||||
kwargs.update({
|
||||
'inlines': self.inlines,
|
||||
'form_class': self.create_form_class if self.create_form_class else self.form_class,
|
||||
})
|
||||
return kwargs
|
||||
|
|
@ -168,6 +173,7 @@ class ModelAdmin2(BaseAdmin2):
|
|||
def get_update_kwargs(self):
|
||||
kwargs = self.get_default_view_kwargs()
|
||||
kwargs.update({
|
||||
'inlines': self.inlines,
|
||||
'form_class': self.update_form_class if self.update_form_class else self.form_class,
|
||||
})
|
||||
return kwargs
|
||||
|
|
@ -244,6 +250,23 @@ class ModelAdmin2(BaseAdmin2):
|
|||
return self.get_api_urls(), None, None
|
||||
|
||||
|
||||
|
||||
class Admin2Inline(extra_views.InlineFormSet):
|
||||
"""
|
||||
A simple extension of django-extra-view's InlineFormSet that
|
||||
adds some useful functionality.
|
||||
"""
|
||||
|
||||
def construct_formset(self):
|
||||
"""
|
||||
Overrides construct_formset to attach the model class as
|
||||
an attribute of the returned formset instance.
|
||||
"""
|
||||
formset = super(Admin2Inline, self).construct_formset()
|
||||
formset.model = self.inline_model
|
||||
return formset
|
||||
|
||||
|
||||
class ImmutableAdmin(object):
|
||||
"""
|
||||
Only __init__ allows setting of attributes
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
{% extends "admin2/bootstrap/base.html" %}
|
||||
|
||||
{% load admin2_tags %}
|
||||
|
||||
{% block title %}{{ action }} {{ model }}{% endblock %}
|
||||
|
||||
{% block page_title %}{{ action }} {{ model }}{% endblock %}
|
||||
|
|
@ -12,6 +14,36 @@
|
|||
{% csrf_token %}
|
||||
{{ form.as_p }}
|
||||
|
||||
{% for formset in inlines %}
|
||||
<h4>{{ formset.model|model_verbose_name_plural|capfirst }}</h4>
|
||||
{{ formset.management_form }}
|
||||
<table class="table table-striped table-bordered">
|
||||
<thead>
|
||||
<tr>
|
||||
{% for field in formset|formset_visible_fieldlist %}
|
||||
<th>{{ field }}</th>
|
||||
{% endfor %}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for inline_form in formset %}
|
||||
<tr>
|
||||
{% for field in inline_form.visible_fields %}
|
||||
<td>
|
||||
{% if forloop.first %}
|
||||
{% for hidden_field in inline_form.hidden_fields %}
|
||||
{{ hidden_field }}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{{ field }}
|
||||
</td>
|
||||
{% endfor %}
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
{% endfor %}
|
||||
|
||||
<button class="btn btn-small" type="submit" name="_addanother">Save and add another</button>
|
||||
<button class="btn btn-small" type="submit" name="_continue">Save and continue editing</button>
|
||||
<button class="btn btn-small btn-success" type="submit" name="_save">Save</button>
|
||||
|
|
|
|||
|
|
@ -9,3 +9,27 @@ 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)
|
||||
|
||||
|
||||
@register.filter
|
||||
def model_verbose_name(obj):
|
||||
"""
|
||||
Returns the verbose name of a model instance or class.
|
||||
"""
|
||||
return obj._meta.verbose_name
|
||||
|
||||
|
||||
@register.filter
|
||||
def model_verbose_name_plural(obj):
|
||||
"""
|
||||
Returns the pluralized verbose name of a model instance or class.
|
||||
"""
|
||||
return obj._meta.verbose_name_plural
|
||||
|
||||
|
||||
@register.filter
|
||||
def formset_visible_fieldlist(formset):
|
||||
"""
|
||||
Returns the labels of a formset's visible fields as an array.
|
||||
"""
|
||||
return [f.label for f in formset.forms[0].visible_fields()]
|
||||
|
|
@ -9,7 +9,9 @@ from django.views import generic
|
|||
|
||||
from braces.views import AccessMixin
|
||||
|
||||
from templatetags.admin2_tags import admin2_urlname
|
||||
import extra_views
|
||||
|
||||
from .templatetags.admin2_tags import admin2_urlname
|
||||
|
||||
|
||||
ADMIN2_THEME_DIRECTORY = getattr(settings, "ADMIN2_THEME_DIRECTORY", "admin2/bootstrap")
|
||||
|
|
@ -121,7 +123,7 @@ class ModelDetailView(AdminModel2Mixin, generic.DetailView):
|
|||
permission_type = 'view'
|
||||
|
||||
|
||||
class ModelEditFormView(AdminModel2Mixin, Admin2ModelFormMixin, generic.UpdateView):
|
||||
class ModelEditFormView(AdminModel2Mixin, Admin2ModelFormMixin, extra_views.UpdateWithInlinesView):
|
||||
form_class = None
|
||||
default_template_name = "model_update_form.html"
|
||||
permission_type = 'change'
|
||||
|
|
@ -133,7 +135,7 @@ class ModelEditFormView(AdminModel2Mixin, Admin2ModelFormMixin, generic.UpdateVi
|
|||
return context
|
||||
|
||||
|
||||
class ModelAddFormView(AdminModel2Mixin, Admin2ModelFormMixin, generic.CreateView):
|
||||
class ModelAddFormView(AdminModel2Mixin, Admin2ModelFormMixin, extra_views.CreateWithInlinesView):
|
||||
form_class = None
|
||||
default_template_name = "model_update_form.html"
|
||||
permission_type = 'add'
|
||||
|
|
|
|||
|
|
@ -5,9 +5,8 @@ from django.contrib.auth.forms import UserCreationForm, UserChangeForm
|
|||
from django.contrib.auth.models import Group, User
|
||||
from rest_framework.relations import PrimaryKeyRelatedField
|
||||
|
||||
|
||||
import djadmin2
|
||||
from djadmin2.models import ModelAdmin2
|
||||
from djadmin2.models import ModelAdmin2, Admin2Inline
|
||||
from djadmin2.apiviews import Admin2APISerializer
|
||||
|
||||
|
||||
|
|
@ -30,6 +29,14 @@ class UserSerializer(Admin2APISerializer):
|
|||
exclude = ('passwords',)
|
||||
|
||||
|
||||
class CommentInline(Admin2Inline):
|
||||
model = Comment
|
||||
|
||||
|
||||
class PostAdmin(ModelAdmin2):
|
||||
inlines = [CommentInline]
|
||||
|
||||
|
||||
class UserAdmin2(ModelAdmin2):
|
||||
create_form_class = UserCreationForm
|
||||
update_form_class = UserChangeForm
|
||||
|
|
@ -38,7 +45,7 @@ class UserAdmin2(ModelAdmin2):
|
|||
|
||||
|
||||
# Register each model with the admin
|
||||
djadmin2.default.register(Post)
|
||||
djadmin2.default.register(Post, PostAdmin)
|
||||
djadmin2.default.register(Comment)
|
||||
djadmin2.default.register(User, UserAdmin2)
|
||||
djadmin2.default.register(Group, GroupAdmin2)
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ from django.contrib.auth import get_user_model
|
|||
from django.core.urlresolvers import reverse
|
||||
from django.test import TestCase, Client
|
||||
|
||||
from ..models import Post
|
||||
from ..models import Post, Comment
|
||||
|
||||
|
||||
class BaseIntegrationTest(TestCase):
|
||||
|
|
@ -45,12 +45,21 @@ class PostCreateViewTest(BaseIntegrationTest):
|
|||
self.assertEqual(response.status_code, 200)
|
||||
|
||||
def test_create_post(self):
|
||||
post_data = {
|
||||
"comment_set-TOTAL_FORMS": u'2',
|
||||
"comment_set-INITIAL_FORMS": u'0',
|
||||
"comment_set-MAX_NUM_FORMS": u'',
|
||||
"comment_set-0-body": u'Comment Body',
|
||||
"title": "a_post_title",
|
||||
"body": "a_post_body",
|
||||
}
|
||||
|
||||
response = self.client.post(reverse("admin2:blog_post_create"),
|
||||
{"title": "a_post_title",
|
||||
"body": "a_post_body"},
|
||||
post_data,
|
||||
follow=True)
|
||||
self.assertTrue(Post.objects.filter(title="a_post_title").exists())
|
||||
post = Post.objects.get(title="a_post_title")
|
||||
comment = Comment.objects.get(body="Comment Body")
|
||||
self.assertRedirects(response, reverse("admin2:blog_post_index"))
|
||||
|
||||
def test_save_and_add_another_redirects_to_create(self):
|
||||
|
|
@ -58,9 +67,14 @@ class PostCreateViewTest(BaseIntegrationTest):
|
|||
Tests that choosing 'Save and add another' from the model create
|
||||
page redirects the user to the model create page.
|
||||
"""
|
||||
post_data = {"title": "a_post_title",
|
||||
"body": "a_post_body",
|
||||
"_addanother": ""}
|
||||
post_data = {
|
||||
"comment_set-TOTAL_FORMS": u'2',
|
||||
"comment_set-INITIAL_FORMS": u'0',
|
||||
"comment_set-MAX_NUM_FORMS": u'',
|
||||
"title": "a_post_title",
|
||||
"body": "a_post_body",
|
||||
"_addanother": ""
|
||||
}
|
||||
self.client.login(username='admin', password='password')
|
||||
response = self.client.post(reverse("admin2:blog_post_create"),
|
||||
post_data)
|
||||
|
|
@ -72,9 +86,14 @@ class PostCreateViewTest(BaseIntegrationTest):
|
|||
Tests that choosing "Save and continue editing" redirects
|
||||
the user to the model update form.
|
||||
"""
|
||||
post_data = {"title": "Unique",
|
||||
"body": "a_post_body",
|
||||
"_continue": ""}
|
||||
post_data = {
|
||||
"comment_set-TOTAL_FORMS": u'2',
|
||||
"comment_set-INITIAL_FORMS": u'0',
|
||||
"comment_set-MAX_NUM_FORMS": u'',
|
||||
"title": "Unique",
|
||||
"body": "a_post_body",
|
||||
"_continue": ""
|
||||
}
|
||||
response = self.client.post(reverse("admin2:blog_post_create"),
|
||||
post_data)
|
||||
post = Post.objects.get(title="Unique")
|
||||
|
|
|
|||
1
setup.py
1
setup.py
|
|
@ -90,6 +90,7 @@ setup(
|
|||
install_requires=[
|
||||
'django>=1.5.0',
|
||||
'django-braces==1.0.0',
|
||||
'django-extra-views==0.6.2',
|
||||
'djangorestframework==2.3.3'
|
||||
],
|
||||
zip_safe=False,
|
||||
|
|
|
|||
Loading…
Reference in a new issue