def PatchDjangoSerializa tionModules Monkey patches the Django seriali

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
def PatchDjangoSerializationModules():
"""Monkey patches the Django serialization modules.
The standard Django serialization modules to not correctly handle the
datastore models provided by this package. This method installs replacements
for selected modules and methods to give Django the capability to correctly
serialize and deserialize datastore models.
"""
# These can't be imported until InstallAppengineDatabaseBackend has run.
from django.core.serializers import python
from appengine_django.serializer.python import Deserializer
if not hasattr(settings, "SERIALIZATION_MODULES"):
settings.SERIALIZATION_MODULES = {}
base_module = "appengine_django"
settings.SERIALIZATION_MODULES["xml"] = "%s.serializer.xml" % base_module
python.Deserializer = Deserializer
PatchDeserializedObjectClass()
DisableModelValidation()
logging.debug("Installed appengine json and python serialization modules")
def PatchDeserializedObjectClass():
"""Patches the DeserializedObject class.
The default implementation calls save directly on the django Model base
class to avoid pre-save handlers. The model class provided by this package
is not derived from the Django Model class and therefore must be called
directly.
Additionally we need to clear the internal _parent attribute as it may
contain a FakeParent class that is used to deserialize instances without
needing to load the parent instance itself. See the PythonDeserializer for
more details.
"""
# This can't be imported until InstallAppengineDatabaseBackend has run.
from django.core.serializers import base
class NewDeserializedObject(base.DeserializedObject):
def save(self, save_m2m=True):
self.object.save()
self.object._parent = None
base.DeserializedObject = NewDeserializedObject
logging.debug("Replacement DeserializedObject class installed")
def DisableModelValidation():
"""Disables Django's model validation routines.
The model validation is primarily concerned with validating foreign key
references. There is no equivalent checking code for datastore References at
this time.
Validation needs to be disabled or serialization/deserialization will fail.
"""
# Imports must be performed in this function as they differ between versions.
if VERSION < (0, 97, None):
from django.core import management
management.get_validation_errors = lambda x, y=0: 0
else:
from django.core.management import validation
validation.get_validation_errors = lambda x, y=0: 0
logging.debug("Django SQL model validation disabled")
def CleanupDjangoSettings():
"""Removes incompatible entries from the django settings module."""
# Ensure this module is installed as an application.
apps = getattr(settings, "INSTALLED_APPS", ())
found = False
for app in apps:
if app.endswith("appengine_django"):
found = True
break
if not found:
logging.warn("appengine_django module is not listed as an application!")
apps += ("appengine_django",)
setattr(settings, "INSTALLED_APPS", apps)
logging.info("Added 'appengine_django' as an application")
# Ensure the database backend is appropriately configured.
dbe = getattr(settings, "DATABASE_ENGINE", "")
if dbe != "appengine":
settings.DATABASE_ENGINE = "appengine"
logging.warn("DATABASE_ENGINE is not configured as 'appengine'. "
"Value overriden!")
for var in ["NAME", "USER", "PASSWORD", "HOST", "PORT"]:
val = getattr(settings, "DATABASE_%s" % var, "")
if val:
setattr(settings, "DATABASE_%s" % var, "")
logging.warn("DATABASE_%s should be blank. Value overriden!")
# Remove incompatible middleware modules.
mw_mods = list(getattr(settings, "MIDDLEWARE_CLASSES", ()))
disallowed_middleware_mods = (
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.doc.XViewMiddleware',)
for modname in mw_mods[:]:
if modname in disallowed_middleware_mods:
# Currently only the CommonMiddleware has been ported. As other base modules
# are converted, remove from the disallowed_middleware_mods tuple.
mw_mods.remove(modname)
logging.warn("Middleware module '%s' is not compatible. Removed!" %
modname)
setattr(settings, "MIDDLEWARE_CLASSES", tuple(mw_mods))
# Remove incompatible application modules
app_mods = list(getattr(settings, "INSTALLED_APPS", ()))
disallowed_apps = (
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.sites',)
for app in app_mods[:]:
if app in disallowed_apps:
app_mods.remove(app)
logging.warn("Application module '%s' is not compatible. Removed!" % app)
setattr(settings, "INSTALLED_APPS", tuple(app_mods))
def ModifyAvailableCommands():
"""Removes incompatible commands and installs replacements where possible."""
if have_appserver:
# Commands are not used when running from an appserver.
return
from django.core import management
if VERSION < (0, 97, None):
RemoveCommands(management.DEFAULT_ACTION_MAPPING)
from appengine_django.management.commands import runserver
management.DEFAULT_ACTION_MAPPING['runserver'] = runserver.v096_command
from appengine_django.management.commands import flush
management.DEFAULT_ACTION_MAPPING['flush'] = flush.v096_command
from appengine_django.management.commands import reset
management.DEFAULT_ACTION_MAPPING['reset'] = reset.v096_command
else:
management.get_commands()
RemoveCommands(management._commands)
# Django 0.97 will install the replacements automatically.
logging.debug("Removed incompatible Django manage.py commands")
def RemoveCommands(command_dict):
"""Removes incompatible commands from the specified command dictionary."""
for cmd in command_dict.keys():
if cmd.startswith("sql"):
del command_dict[cmd]
elif cmd in INCOMPATIBLE_COMMANDS:
del command_dict[cmd]
def InstallReplacementImpModule():
"""Install a replacement for the imp module removed by the appserver.
This is only required for Django 0.97 which uses imp.find_module to find
mangement modules provided by applications.
"""
if VERSION < (0, 97, None) or not have_appserver:
return
modname = 'appengine_django.replacement_imp'
imp_mod = __import__(modname, {}, [], [''])
sys.modules['imp'] = imp_mod
logging.debug("Installed replacement imp module")
def InstallAppengineHelperForDjango():
"""Installs and Patches all of the classes/methods required for integration.
If the variable DEBUG_APPENGINE_DJANGO is set in the environment verbose
logging of the actions taken will be enabled.
"""
if os.getenv("DEBUG_APPENGINE_DJANGO"):
logging.getLogger().setLevel(logging.DEBUG)
else:
logging.getLogger().setLevel(logging.INFO)
logging.debug("Loading the Google App Engine Helper for Django...")
# Force Django to reload its settings.
settings._target = None
# Must set this env var *before* importing any more of Django.
os.environ['DJANGO_SETTINGS_MODULE'] = 'settings'
LoadAppengineEnvironment()
InstallReplacementImpModule()
InstallAppengineDatabaseBackend()
PatchDjangoSerializationModules()
CleanupDjangoSettings()
ModifyAvailableCommands()
InstallGoogleSMTPConnection()
InstallAuthentication()
logging.debug("Successfully loaded the Google App Engine Helper for Django.")
def InstallGoogleSMTPConnection():
from appengine_django import mail as gmail
from django.core import mail
if VERSION >= (0, 97, None):
logging.debug("Installing Google Email Adapter for Django 0.97+")
mail.SMTPConnection = gmail.GoogleSMTPConnection
else:
logging.debug("Installing Google Email Adapter for Django 0.96")
mail.send_mass_mail = gmail.send_mass_mail
mail.mail_admins = gmail.mail_admins
mail.mail_managers = gmail.mail_managers
def InstallAuthentication():
logging.debug("Installing authentication framework")
from appengine_django.auth import models as helper_models
from django.contrib.auth import models
models.User = helper_models.User
models.Group = helper_models.Group
models.Permission = helper_models.Permission
models.Message = helper_models.Message
from django.contrib.auth import middleware as django_middleware
from appengine_django.auth.middleware import AuthenticationMiddleware
django_middleware.AuthenticationMiddleware = AuthenticationMiddleware
if VERSION >= (0, 97, None):
from appengine_django.auth import tests
from django.contrib.auth import tests as django_tests
django_tests.__doc__ = tests.__doc__