From 7827bf0003d9812fcf542e9d7c4b2ca29620e056 Mon Sep 17 00:00:00 2001 From: Daniel Greenfeld Date: Sat, 1 Jun 2013 18:02:01 +0200 Subject: [PATCH] fixes #159 and lays the ground for more things --- djadmin2/forms.py | 8 +- docs/index.rst | 16 +++- docs/ref/actions.rst | 58 ++++++++++++ docs/ref/forms.rst | 100 ++++++++++++++++++++ docs/{reference.rst => ref/permissions.rst} | 64 ------------- example/blog/admin2.py | 8 +- 6 files changed, 181 insertions(+), 73 deletions(-) create mode 100644 docs/ref/actions.rst create mode 100644 docs/ref/forms.rst rename docs/{reference.rst => ref/permissions.rst} (82%) diff --git a/djadmin2/forms.py b/djadmin2/forms.py index c990c90..d34d828 100644 --- a/djadmin2/forms.py +++ b/djadmin2/forms.py @@ -2,7 +2,9 @@ from __future__ import unicode_literals from copy import deepcopy from django.contrib.auth import authenticate -from django.contrib.auth.forms import AuthenticationForm +from django.contrib.auth.forms import ( + AuthenticationForm, UserCreationForm, UserChangeForm + ) import django.forms import django.forms.models import django.forms.extras.widgets @@ -261,3 +263,7 @@ class AdminAuthenticationForm(AuthenticationForm): 'username': self.username_field.verbose_name }) return self.cleaned_data + + +UserCreationForm = floppify_form(UserCreationForm) +UserChangeForm = floppify_form(UserChangeForm) diff --git a/docs/index.rst b/docs/index.rst index b76eea3..befdfce 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -61,9 +61,23 @@ Content api themes meta - reference tutorial +Reference +----------- + +This is where the developer API is in the process of being documented. + +.. note:: For developers of django-admin2 + + All functionality listed here must not only be listed, but also demonstrated with simple but functional code examples. + +.. toctree:: + :maxdepth: 2 + + ref/actions + ref/forms + ref/permissions Indices and tables ================== diff --git a/docs/ref/actions.rst b/docs/ref/actions.rst new file mode 100644 index 0000000..54f787b --- /dev/null +++ b/docs/ref/actions.rst @@ -0,0 +1,58 @@ +Actions +======= + +.. warning:: Incomplete and innaccurate! In the process of revising. -- pydanny + +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 are full fledged objects. Which means you can more easily extend them to suit your needs. + +The documentation works off a simple set of models, as listed below: + +.. code-block:: python + + # blog/models.py + from django.db import models + + STATUS_CHOICES = ( + ('d', 'Draft'), + ('p', 'Published'), + ('w', 'Withdrawn'), + ) + + + class Post(models.Model): + title = models.CharField(max_length=255) + body = models.TextField() + status = models.CharField(max_length=1, choices=STATUS_CHOICES) + + def __unicode__(self): + return self.title + + + class Comment(models.Model): + post = models.ForeignKey(Post) + body = models.TextField() + + def __unicode__(self): + return self.body + +Writing List Actions +----------------------- + +Using our sample models, let's pretend we wrote a blog article about Django and our mother put in a whole bunch of embarressing comments. Rather than cherry-pick the comments, we want to delete the whole batch. + +In our blog/admin.py module we write: + +.. code-block:: python + + import djadmin2 + + from .models import Post, Comment + + class DeleteAllComments(BaseListAction): + description = ugettext_lazy("Delete selected items") + + djadmin2.default.register(Post, PostAdmin) + djadmin2.default.register(Comment) + diff --git a/docs/ref/forms.rst b/docs/ref/forms.rst new file mode 100644 index 0000000..3e349ae --- /dev/null +++ b/docs/ref/forms.rst @@ -0,0 +1,100 @@ +===== +Forms +===== + +Replicating `django.contrib.admin`'s user management +====================================================== + +If you have users, it's assumed you will have a Django app to manage them, called something like `accounts`, `users`, or `profiles`. For this exercise, we'll assume the app is called `accounts`. + +Step 1 - The admin2.py module +----------------------------- + +In the `accounts` app, create an ``admin2.py`` module. + +Step 2 - Web Integration +------------------------ + +Enter the following code in ``accounts/admin2.py``: + +.. code-block:: python + + # Import the User and Group model from django.contrib.auth + from django.contrib.auth import get_user_model + from django.contrib.auth.models import Group + + import djadmin2 + + # fetch the User model + User = get_user_model() + + # Incorporate the + class UserAdmin2(djadmin2.ModelAdmin2): + create_form_class = djadmin2.forms.UserCreationForm + update_form_class = djadmin2.forms.UserChangeForm + + djadmin2.default.register(User, UserAdmin2) + djadmin2.default.register(Group) + +Done! The User and Group controls will appear in your django-admin2 dashboard. + +Well... almost. We still need to incorporate the API components. + +Step 3 - API Integration +------------------------ + +Change ``accounts/admin2.py`` to the following: + +.. code-block:: python + + # Import the User and Group model from django.contrib.auth + from django.contrib.auth import get_user_model + from django.contrib.auth.models import Group + + from rest_framework.relations import PrimaryKeyRelatedField + + import djadmin2 + + # fetch the User model + User = get_user_model() + + + # Serialize the groups + class GroupSerializer(Admin2APISerializer): + permissions = PrimaryKeyRelatedField(many=True) + + class Meta: + model = Group + + # The GroupAdmin2 object is synonymous with GroupAdmin + class GroupAdmin2(djadmin2.ModelAdmin2): + api_serializer_class = GroupSerializer + + + # Serialize the users, excluding password data + class UserSerializer(djadmin2.apiviews.Admin2APISerializer): + user_permissions = PrimaryKeyRelatedField(many=True) + + class Meta: + model = User + exclude = ('passwords',) + + + # The UserAdmin2 object is synonymous with UserAdmin + class UserAdmin2(djadmin2.ModelAdmin2): + create_form_class = UserCreationForm + update_form_class = UserChangeForm + + api_serializer_class = UserSerializer + + djadmin2.default.register(User, UserAdmin2) + djadmin2.default.register(Group, GroupAdmin2) + +Things to Do +================= + + +* Consider breaking the user management reference into more steps +* Create default UserAdmin2 and GroupAdmin2 classes +* Demonstrate how to easy it is to customize and HTML5-ize forms +* Demonstrate how easy it is to customize widgets \ No newline at end of file diff --git a/docs/reference.rst b/docs/ref/permissions.rst similarity index 82% rename from docs/reference.rst rename to docs/ref/permissions.rst index 5a3995f..4d0b106 100644 --- a/docs/reference.rst +++ b/docs/ref/permissions.rst @@ -1,67 +1,3 @@ -=============== -Reference -=============== - -This is where the developer API is in the process of being documented. - -.. note:: For developers of django-admin2 - - All functionality listed here must not only be listed, but also demonstrated with simple but functional code examples. - -Baseline Model -================= - -The documentation works off a simple set of models, as listed below. - -.. code-block:: python - - # blog/models.py - from django.db import models - - - class Post(models.Model): - title = models.CharField(max_length=255) - body = models.TextField() - - def __unicode__(self): - return self.title - - - class Comment(models.Model): - post = models.ForeignKey(Post) - body = models.TextField() - - def __unicode__(self): - return self.body - -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 are full fledged objects. Which means you can more easily extend them to suit your needs. - -Writing List Actions ------------------------ - -Using our sample models, let's pretend we wrote a blog article about Django and our mother put in a whole bunch of embarressing comments. Rather than cherry-pick the comments, we want to delete the whole batch. - -In our blog/admin.py module we write: - -.. code-block:: python - - import djadmin2 - - from .models import Post, Comment - - class DeleteAllComments(BaseListAction): - description = ugettext_lazy("Delete selected items") - - djadmin2.default.register(Post, PostAdmin) - djadmin2.default.register(Comment) - -TODO - FINISH AFTER CHECKING THE MODEL CONTROL BUG!!! - Permissions =========== diff --git a/example/blog/admin2.py b/example/blog/admin2.py index 556d61f..4bdefa8 100644 --- a/example/blog/admin2.py +++ b/example/blog/admin2.py @@ -1,21 +1,15 @@ - # Import your custom models -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.forms import floppify_form +from djadmin2.forms import UserCreationForm, UserChangeForm from djadmin2.apiviews import Admin2APISerializer from .models import Post, Comment -UserCreationForm = floppify_form(UserCreationForm) -UserChangeForm = floppify_form(UserChangeForm) - - class GroupSerializer(Admin2APISerializer): permissions = PrimaryKeyRelatedField(many=True)