Index: admin/options.py
===================================================================
--- admin/options.py	(revision 9296)
+++ admin/options.py	(working copy)
@@ -1,8 +1,11 @@
 from django import forms, template
 from django.forms.formsets import all_valid
-from django.forms.models import modelform_factory, inlineformset_factory
+#from django.forms.models import modelform_factory, inlineformset_factory
+#from google.appengine.ext.db.djangoforms import modelform_factory  modelform_factory was removed 1.12
+from django.forms.models import modelform_factory
+from google.appengine.ext import db
 from django.forms.models import BaseInlineFormSet
-from django.contrib.contenttypes.models import ContentType
+#from django.contrib.contenttypes.models import ContentType
 from django.contrib.admin import widgets
 from django.contrib.admin import helpers
 from django.contrib.admin.util import quote, unquote, flatten_fieldsets, get_deleted_objects
@@ -46,7 +49,7 @@
 
         If kwargs are given, they're passed to the form Field's constructor.
         """
-        
+
         # If the field specifies choices, we don't need to look for special
         # admin widgets - we just need to use a select widget of some kind.
         if db_field.choices:
@@ -76,35 +79,35 @@
             return db_field.formfield(**kwargs)
 
         # For TimeFields, add a custom CSS class.
-        if isinstance(db_field, models.TimeField):
+        if isinstance(db_field, (models.TimeField,db.TimeProperty)):
             kwargs['widget'] = widgets.AdminTimeWidget
             return db_field.formfield(**kwargs)
-        
+
         # For TextFields, add a custom CSS class.
-        if isinstance(db_field, models.TextField):
+        if isinstance(db_field, (models.TextField,db.TextProperty)):
             kwargs['widget'] = widgets.AdminTextareaWidget
             return db_field.formfield(**kwargs)
-        
+
         # For URLFields, add a custom CSS class.
-        if isinstance(db_field, models.URLField):
+        if isinstance(db_field, (models.URLField,db.URLProperty)):
             kwargs['widget'] = widgets.AdminURLFieldWidget
             return db_field.formfield(**kwargs)
-        
+
         # For IntegerFields, add a custom CSS class.
-        if isinstance(db_field, models.IntegerField):
+        if isinstance(db_field, (models.IntegerField,db.IntegerProperty)):
             kwargs['widget'] = widgets.AdminIntegerFieldWidget
             return db_field.formfield(**kwargs)
 
         # For CommaSeparatedIntegerFields, add a custom CSS class.
-        if isinstance(db_field, models.CommaSeparatedIntegerField):
+        if isinstance(db_field, (models.CommaSeparatedIntegerField,db.ListProperty,db.StringListProperty)):
             kwargs['widget'] = widgets.AdminCommaSeparatedIntegerFieldWidget
             return db_field.formfield(**kwargs)
 
         # For TextInputs, add a custom CSS class.
-        if isinstance(db_field, models.CharField):
+        if isinstance(db_field, (models.CharField,db.StringProperty)):
             kwargs['widget'] = widgets.AdminTextInputWidget
             return db_field.formfield(**kwargs)
-    
+
         # For FileFields and ImageFields add a link to the current file.
         if isinstance(db_field, models.ImageField) or isinstance(db_field, models.FileField):
             kwargs['widget'] = widgets.AdminFileWidget
@@ -143,6 +146,120 @@
         # For any other type of field, just call its formfield() method.
         return db_field.formfield(**kwargs)
 
+    def formfield_for_dbfield_gae(self, db_field, **kwargs):
+        """
+        Hook for specifying the form Field instance for a given database Field
+        instance.
+
+        If kwargs are given, they're passed to the form Field's constructor.
+        """
+
+        # If the field specifies choices, we don't need to look for special
+        # admin widgets - we just need to use a select widget of some kind.
+        if db_field.choices:
+            if db_field.name in self.radio_fields:
+                # If the field is named as a radio_field, use a RadioSelect
+                kwargs['widget'] = widgets.AdminRadioSelect(attrs={
+                    'class': get_ul_class(self.radio_fields[db_field.name]),
+                })
+                kwargs['choices'] = db_field.get_choices(
+                    include_blank = db_field.blank,
+                    blank_choice=[('', _('None'))]
+                )
+                return db_field.get_form_field(**kwargs)
+            else:
+                # Otherwise, use the default select widget.
+                return db_field.get_form_field(**kwargs)
+
+        #GAE DateProperty is subclass of DateTimeProperty
+        #Django DateTimeField is subclass of DateField
+        if isinstance(db_field, db.DateProperty):
+            kwargs['widget'] = widgets.AdminDateWidget
+            return db_field.formfield(**kwargs)
+
+        if isinstance(db_field, db.DateTimeProperty):
+            kwargs['form_class'] = forms.SplitDateTimeField
+            kwargs['widget'] = widgets.AdminSplitDateTime()
+            return db_field.formfield(**kwargs)
+
+        # For DateTimeFields, use a special field and widget.
+        if isinstance(db_field, (models.DateTimeField,db.DateTimeProperty)):
+            kwargs['form_class'] = forms.SplitDateTimeField
+            kwargs['widget'] = widgets.AdminSplitDateTime()
+            return db_field.get_form_field(**kwargs)
+
+        # For DateFields, add a custom CSS class.
+        if isinstance(db_field, (models.DateField,db.DateProperty)):
+            kwargs['widget'] = widgets.AdminDateWidget
+            return db_field.get_form_field(**kwargs)
+
+        # For TimeFields, add a custom CSS class.
+        if isinstance(db_field, (models.TimeField,db.TimeProperty)):
+            kwargs['widget'] = widgets.AdminTimeWidget
+            return db_field.get_form_field(**kwargs)
+
+        # For TextFields, add a custom CSS class.
+        if isinstance(db_field, (models.TextField,db.TextProperty)):
+            kwargs['widget'] = widgets.AdminTextareaWidget
+            return db_field.get_form_field(**kwargs)
+
+        # For URLFields, add a custom CSS class.
+        if isinstance(db_field, (models.URLField,db.URLProperty)):
+            kwargs['widget'] = widgets.AdminURLFieldWidget
+            return db_field.get_form_field(**kwargs)
+
+        # For IntegerFields, add a custom CSS class.
+        if isinstance(db_field, (models.IntegerField,db.IntegerProperty)):
+            kwargs['widget'] = widgets.AdminIntegerFieldWidget
+            return db_field.get_form_field(**kwargs)
+
+        # For CommaSeparatedIntegerFields, add a custom CSS class.
+        if isinstance(db_field, (models.CommaSeparatedIntegerField,db.ListProperty)):
+            kwargs['widget'] = widgets.AdminCommaSeparatedIntegerFieldWidget
+            return db_field.get_form_field(**kwargs)
+
+        # For TextInputs, add a custom CSS class.
+        if isinstance(db_field, (models.CharField,db.StringProperty)):
+            kwargs['widget'] = widgets.AdminTextInputWidget
+            return db_field.get_form_field(**kwargs)
+
+        # For FileFields and ImageFields add a link to the current file.
+        if isinstance(db_field, models.ImageField) or isinstance(db_field, models.FileField):
+            kwargs['widget'] = widgets.AdminFileWidget
+            return db_field.get_form_field(**kwargs)
+
+        # For ForeignKey or ManyToManyFields, use a special widget.
+        if isinstance(db_field, (models.ForeignKey, models.ManyToManyField)):
+            if isinstance(db_field, models.ForeignKey) and db_field.name in self.raw_id_fields:
+                kwargs['widget'] = widgets.ForeignKeyRawIdWidget(db_field.rel)
+            elif isinstance(db_field, models.ForeignKey) and db_field.name in self.radio_fields:
+                kwargs['widget'] = widgets.AdminRadioSelect(attrs={
+                    'class': get_ul_class(self.radio_fields[db_field.name]),
+                })
+                kwargs['empty_label'] = db_field.blank and _('None') or None
+            else:
+                if isinstance(db_field, models.ManyToManyField):
+                    # If it uses an intermediary model, don't show field in admin.
+                    if db_field.rel.through is not None:
+                        return None
+                    elif db_field.name in self.raw_id_fields:
+                        kwargs['widget'] = widgets.ManyToManyRawIdWidget(db_field.rel)
+                        kwargs['help_text'] = ''
+                    elif db_field.name in (list(self.filter_vertical) + list(self.filter_horizontal)):
+                        kwargs['widget'] = widgets.FilteredSelectMultiple(db_field.verbose_name, (db_field.name in self.filter_vertical))
+            # Wrap the widget's render() method with a method that adds
+            # extra HTML to the end of the rendered output.
+            formfield = db_field.get_form_field(**kwargs)
+            # Don't wrap raw_id fields. Their add function is in the popup window.
+            if not db_field.name in self.raw_id_fields:
+                # formfield can be None if it came from a OneToOneField with
+                # parent_link=True
+                if formfield is not None:
+                    formfield.widget = widgets.RelatedFieldWidgetWrapper(formfield.widget, db_field.rel, self.admin_site)
+            return formfield
+
+        # For any other type of field, just call its formfield() method.
+        return db_field.get_form_field(**kwargs)
     def _declared_fieldsets(self):
         if self.fieldsets:
             return self.fieldsets
@@ -155,7 +272,7 @@
     "Encapsulates all admin options and functionality for a given model."
     __metaclass__ = forms.MediaDefiningClass
 
-    list_display = ('__str__',)
+    list_display = ('__unicode__',)
     list_display_links = ()
     list_filter = ()
     list_select_related = False
@@ -210,10 +327,12 @@
 
     def has_add_permission(self, request):
         "Returns True if the given request has permission to add an object."
+        return True
         opts = self.opts
         return request.user.has_perm(opts.app_label + '.' + opts.get_add_permission())
 
     def has_change_permission(self, request, obj=None):
+        return True
         """
         Returns True if the given request has permission to change the given
         Django model instance.
@@ -225,6 +344,7 @@
         return request.user.has_perm(opts.app_label + '.' + opts.get_change_permission())
 
     def has_delete_permission(self, request, obj=None):
+        return True
         """
         Returns True if the given request has permission to change the given
         Django model instance.
@@ -240,11 +360,15 @@
         Returns a QuerySet of all model instances that can be edited by the
         admin site. This is used by changelist_view.
         """
-        qs = self.model._default_manager.get_query_set()
-        # TODO: this should be handled by some parameter to the ChangeList.
-        ordering = self.ordering or () # otherwise we might try to *None, which is bad ;)
-        if ordering:
-            qs = qs.order_by(*ordering)
+#        qs = self.model._default_manager.get_query_set()
+#        # TODO: this should be handled by some parameter to the ChangeList.
+#        ordering = self.ordering or () # otherwise we might try to *None, which is bad ;)
+#        if ordering:
+#            qs = qs.order_by(*ordering)
+        qs = self.model.all()
+        ordering = self.ordering or ()
+        for order in ordering:
+          qs = qs.order(order)
         return qs
 
     def get_fieldsets(self, request, obj=None):
@@ -264,14 +388,14 @@
         else:
             fields = None
         if self.exclude is None:
-            exclude = []
+            exclude = ()
         else:
             exclude = list(self.exclude)
         defaults = {
             "form": self.form,
             "fields": fields,
-            "exclude": exclude + kwargs.get("exclude", []),
-            "formfield_callback": self.formfield_for_dbfield,
+            "exclude": exclude + kwargs.get("exclude", ()),
+            "formfield_callback": self.formfield_for_dbfield_gae,
         }
         defaults.update(kwargs)
         return modelform_factory(self.model, **defaults)
@@ -279,56 +403,59 @@
     def get_formsets(self, request, obj=None):
         for inline in self.inline_instances:
             yield inline.get_formset(request, obj)
-            
+
     def log_addition(self, request, object):
+        pass
         """
-        Log that an object has been successfully added. 
-        
+        Log that an object has been successfully added.
+
         The default implementation creates an admin LogEntry object.
         """
-        from django.contrib.admin.models import LogEntry, ADDITION
-        LogEntry.objects.log_action(
-            user_id         = request.user.pk, 
-            content_type_id = ContentType.objects.get_for_model(object).pk,
-            object_id       = object.pk,
-            object_repr     = force_unicode(object), 
-            action_flag     = ADDITION
-        )
-        
+#        from django.contrib.admin.models import LogEntry, ADDITION
+#        LogEntry.objects.log_action(
+#            user_id         = request.user.pk,
+#            content_type_id = ContentType.objects.get_for_model(object).pk,
+#            object_id       = object.pk,
+#            object_repr     = force_unicode(object),
+#            action_flag     = ADDITION
+#        )
+
     def log_change(self, request, object, message):
+        pass
         """
-        Log that an object has been successfully changed. 
-        
+        Log that an object has been successfully changed.
+
         The default implementation creates an admin LogEntry object.
         """
-        from django.contrib.admin.models import LogEntry, CHANGE
-        LogEntry.objects.log_action(
-            user_id         = request.user.pk, 
-            content_type_id = ContentType.objects.get_for_model(object).pk, 
-            object_id       = object.pk, 
-            object_repr     = force_unicode(object), 
-            action_flag     = CHANGE, 
-            change_message  = message
-        )
-        
+#        from django.contrib.admin.models import LogEntry, CHANGE
+#        LogEntry.objects.log_action(
+#            user_id         = request.user.pk,
+#            content_type_id = ContentType.objects.get_for_model(object).pk,
+#            object_id       = object.pk,
+#            object_repr     = force_unicode(object),
+#            action_flag     = CHANGE,
+#            change_message  = message
+#        )
+
     def log_deletion(self, request, object, object_repr):
+        pass
         """
         Log that an object has been successfully deleted. Note that since the
         object is deleted, it might no longer be safe to call *any* methods
         on the object, hence this method getting object_repr.
-        
+
         The default implementation creates an admin LogEntry object.
         """
-        from django.contrib.admin.models import LogEntry, DELETION
-        LogEntry.objects.log_action(
-            user_id         = request.user.id, 
-            content_type_id = ContentType.objects.get_for_model(self.model).pk, 
-            object_id       = object.pk, 
-            object_repr     = object_repr,
-            action_flag     = DELETION
-        )
-        
-    
+#        from django.contrib.admin.models import LogEntry, DELETION
+#        LogEntry.objects.log_action(
+#            user_id         = request.user.id,
+#            content_type_id = ContentType.objects.get_for_model(self.model).pk,
+#            object_id       = object.pk,
+#            object_repr     = object_repr,
+#            action_flag     = DELETION
+#        )
+
+
     def construct_change_message(self, request, form, formsets):
         """
         Construct a change message from a changed object.
@@ -354,13 +481,16 @@
                                              'object': deleted_object})
         change_message = ' '.join(change_message)
         return change_message or _('No fields changed.')
-    
+
     def message_user(self, request, message):
         """
-        Send a message to the user. The default implementation 
+        Send a message to the user. The default implementation
         posts a message using the auth Message object.
         """
-        request.user.message_set.create(message=message)
+#        request.user.message_set.create(message=message)
+        from django.contrib.auth.models import Message
+        message = Message(user=request.user,message=message)
+        message.put()
 
     def save_form(self, request, form, change):
         """
@@ -368,7 +498,7 @@
         the object is being changed, and False if it's being added.
         """
         return form.save(commit=False)
-    
+
     def save_model(self, request, obj, form, change):
         """
         Given a model instance save it to the database.
@@ -396,7 +526,7 @@
             'ordered_objects': ordered_objects,
             'form_url': mark_safe(form_url),
             'opts': opts,
-            'content_type_id': ContentType.objects.get_for_model(self.model).id,
+            'content_type_id': None, #ContentType.objects.get_for_model(self.model).id,
             'save_as': self.save_as,
             'save_on_top': self.save_on_top,
             'root_path': self.admin_site.root_path,
@@ -406,14 +536,14 @@
             "admin/%s/change_form.html" % app_label,
             "admin/change_form.html"
         ], context, context_instance=template.RequestContext(request))
-    
+
     def response_add(self, request, obj, post_url_continue='../%s/'):
         """
         Determines the HttpResponse for the add_view stage.
         """
         opts = obj._meta
         pk_value = obj._get_pk_val()
-        
+
         msg = _('The %(name)s "%(obj)s" was added successfully.') % {'name': force_unicode(opts.verbose_name), 'obj': force_unicode(obj)}
         # Here, we distinguish between different save types by checking for
         # the presence of keys in request.POST.
@@ -422,7 +552,7 @@
             if request.POST.has_key("_popup"):
                 post_url_continue += "?_popup=1"
             return HttpResponseRedirect(post_url_continue % pk_value)
-        
+
         if request.POST.has_key("_popup"):
             return HttpResponse('<script type="text/javascript">opener.dismissAddAnotherPopup(window, "%s", "%s");</script>' % \
                 # escape() calls force_unicode.
@@ -441,14 +571,14 @@
             else:
                 post_url = '../../../'
             return HttpResponseRedirect(post_url)
-    
+
     def response_change(self, request, obj):
         """
         Determines the HttpResponse for the change_view stage.
         """
         opts = obj._meta
         pk_value = obj._get_pk_val()
-        
+
         msg = _('The %(name)s "%(obj)s" was changed successfully.') % {'name': force_unicode(opts.verbose_name), 'obj': force_unicode(obj)}
         if request.POST.has_key("_continue"):
             self.message_user(request, msg + ' ' + _("You may edit it again below."))
@@ -484,7 +614,7 @@
                 new_object = self.save_form(request, form, change=False)
             else:
                 form_validated = False
-                new_object = self.model()
+                #new_object = self.model()
             for FormSet in self.get_formsets(request):
                 formset = FormSet(data=request.POST, files=request.FILES,
                                   instance=new_object,
@@ -492,10 +622,10 @@
                 formsets.append(formset)
             if all_valid(formsets) and form_validated:
                 self.save_model(request, new_object, form, change=False)
-                form.save_m2m()
+                #form.save_m2m()
                 for formset in formsets:
                     self.save_formset(request, form, formset, change=False)
-                
+
                 self.log_addition(request, new_object)
                 return self.response_add(request, new_object)
         else:
@@ -545,7 +675,8 @@
         opts = model._meta
 
         try:
-            obj = model._default_manager.get(pk=object_id)
+            #obj = model._default_manager.get(pk=object_id)
+            obj = db.get(object_id)
         except model.DoesNotExist:
             # Don't raise Http404 just yet, because we haven't checked
             # permissions yet. We don't want an unauthenticated user to be able
@@ -578,14 +709,14 @@
 
             if all_valid(formsets) and form_validated:
                 self.save_model(request, new_object, form, change=True)
-                form.save_m2m()
+                #form.save_m2m()
                 for formset in formsets:
                     self.save_formset(request, form, formset, change=True)
-                
+
                 change_message = self.construct_change_message(request, form, formsets)
                 self.log_change(request, new_object, change_message)
                 return self.response_change(request, new_object)
-                
+
         else:
             form = ModelForm(instance=obj)
             for FormSet in self.get_formsets(request, obj):
@@ -601,7 +732,7 @@
             inline_admin_formset = helpers.InlineAdminFormSet(inline, formset, fieldsets)
             inline_admin_formsets.append(inline_admin_formset)
             media = media + inline_admin_formset.media
-        
+
         context = {
             'title': _('Change %s') % force_unicode(opts.verbose_name),
             'adminform': adminForm,
@@ -659,7 +790,8 @@
         app_label = opts.app_label
 
         try:
-            obj = self.model._default_manager.get(pk=object_id)
+            #obj = self.model._default_manager.get(pk=object_id)
+            obj = db.get(object_id)
         except self.model.DoesNotExist:
             # Don't raise Http404 just yet, because we haven't checked
             # permissions yet. We don't want an unauthenticated user to be able
@@ -675,18 +807,18 @@
         # Populate deleted_objects, a data structure of all related objects that
         # will also be deleted.
         deleted_objects = [mark_safe(u'%s: <a href="../../%s/">%s</a>' % (escape(force_unicode(capfirst(opts.verbose_name))), quote(object_id), escape(obj))), []]
-        perms_needed = set()
-        get_deleted_objects(deleted_objects, perms_needed, request.user, obj, opts, 1, self.admin_site)
+#        perms_needed = set()
+#        get_deleted_objects(deleted_objects, perms_needed, request.user, obj, opts, 1, self.admin_site)
 
         if request.POST: # The user has already confirmed the deletion.
-            if perms_needed:
-                raise PermissionDenied
+#            if perms_needed:
+#                raise PermissionDenied
             obj_display = force_unicode(obj)
             obj.delete()
-            
+
             self.log_deletion(request, obj, obj_display)
             self.message_user(request, _('The %(name)s "%(obj)s" was deleted successfully.') % {'name': force_unicode(opts.verbose_name), 'obj': force_unicode(obj_display)})
-            
+
             if not self.has_change_permission(request, None):
                 return HttpResponseRedirect("../../../../")
             return HttpResponseRedirect("../../")
@@ -696,7 +828,7 @@
             "object_name": force_unicode(opts.verbose_name),
             "object": obj,
             "deleted_objects": deleted_objects,
-            "perms_lacking": perms_needed,
+            "perms_lacking": None, # perms_needed,
             "opts": opts,
             "root_path": self.admin_site.root_path,
             "app_label": app_label,
@@ -761,7 +893,7 @@
             self.verbose_name = self.model._meta.verbose_name
         if self.verbose_name_plural is None:
             self.verbose_name_plural = self.model._meta.verbose_name_plural
-    
+
     def _media(self):
         from django.conf import settings
         js = []
Index: auth/admin.py
===================================================================
--- auth/admin.py	(revision 9296)
+++ auth/admin.py	(working copy)
@@ -19,9 +19,9 @@
     fieldsets = (
         (None, {'fields': ('username', 'password')}),
         (_('Personal info'), {'fields': ('first_name', 'last_name', 'email')}),
-        (_('Permissions'), {'fields': ('is_staff', 'is_active', 'is_superuser', 'user_permissions')}),
-        (_('Important dates'), {'fields': ('last_login', 'date_joined')}),
-        (_('Groups'), {'fields': ('groups',)}),
+        (_('Permissions'), {'fields': ('is_staff', 'is_active', 'is_superuser', )}),
+        #(_('Important dates'), {'fields': ('last_login', 'date_joined')}),
+        #(_('Groups'), {'fields': ('groups',)}),
     )
     form = UserChangeForm
     add_form = UserCreationForm
@@ -29,8 +29,8 @@
     list_display = ('username', 'email', 'first_name', 'last_name', 'is_staff')
     list_filter = ('is_staff', 'is_superuser')
     search_fields = ('username', 'first_name', 'last_name', 'email')
-    ordering = ('username',)
-    filter_horizontal = ('user_permissions',)
+    ordering = ('username','email')
+    #filter_horizontal = ('user_permissions',)
 
     def __call__(self, request, url):
         # this should not be here, but must be due to the way __call__ routes
@@ -76,7 +76,7 @@
             'save_as': False,
             'username_help_text': self.model._meta.get_field('username').help_text,
             'root_path': self.admin_site.root_path,
-            'app_label': self.model._meta.app_label,            
+            'app_label': self.model._meta.app_label,
         }, context_instance=template.RequestContext(request))
 
     def user_change_password(self, request, id):
@@ -109,6 +109,6 @@
         }, context_instance=RequestContext(request))
 
 
-admin.site.register(Group, GroupAdmin)
+#admin.site.register(Group, GroupAdmin)
 admin.site.register(User, UserAdmin)
 
