This is my first snipplet. With this, you can manage your models in console using ncurses Dialog or Whiptail or XDialog. Models are auto-discovered. You can browse, edit, add and delete models. Bugreports very welcome.
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 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 | # Admin-like editor/browser of your models using DIALOG / WHIPTAIL / XDIALOG / ...
#
# License: GPL 2
#
# Usage:
#
# 1) install python-dialog package and dialog-like program (dialog, whiptail, xdialog)
#
# 2) put this file to your project's top-level directory
#
# 3) into your settings.py put something like this:
# DIALOG_APPS = (
# 'yourproject.yourapp',
# 'yourproject.otherapp',
# ...
# )
#
# ...optionally you can specify a dialog program:
# DIALOG_DIALOG = '/usr/bin/whiptail' (I prefer)
# or DIALOG_DIALOG = '/usr/bin/dialog'
# or DIALOG_DIALOG = '/usr/bin/Xdialog'
#
# ...and some other settings, see bellow...
#
# 4) start this program:
# ./manage.py shell
# >>> from yourproject import dialogadmin
# >>> dialogadmin.run()
#
# ...or you can create django-admin custom command
# (see http://docs.djangoproject.com/en/dev/howto/custom-management-commands/#howto-custom-management-commands )
#
#
# Bugreports welcome...
#
import dialog
from django.db import models
from django.conf import settings
from django.core.exceptions import ObjectDoesNotExist
# From http://www.python.org/doc/2.5.2/lib/built-in-funcs.html
# Helps me to import module like 'myproject.myapp.models' by string
def my_import(name):
mod = __import__(name)
components = name.split('.')
for comp in components[1:]:
mod = getattr(mod, comp)
return mod
# Lets try import default settings, only required is DIALOG_APPS (iterable)
try:
DIALOG = str(settings.DIALOG_DIALOG) # absolute path to executable or name of executable'
except AttributeError:
DIALOG = 'dialog'
try:
DIALOGRC = str(settings.DIALOG_DIALOGRC)
except AttributeError:
DIALOGRC = None
try:
HEIGHT = int(settings.DIALOG_HEIGHT)
except AttributeError:
HEIGHT = 0
try:
WIDTH = int(settings.DIALOG_WIDTH)
except AttributeError:
WIDTH = 0
# Inititialize Dialog object from python-dialog package
D = dialog.Dialog(dialog=DIALOG, DIALOGRC=DIALOGRC)
try:
D.setBackgroundTitle(str(settings.DIALOG_BACKGROUND_TITLE))
except AttributeError:
pass
""" Initialize model control structure
Example:
Models['myproject.myapp']['model_name'] = modelclass
"""
Models = {}
for app in settings.DIALOG_APPS:
for Model in models.get_models(my_import('%s.models' % app)):
try:
Models[app][Model._meta.verbose_name] = Model
except KeyError:
Models[app] = {}
Models[app][Model._meta.verbose_name] = Model
### These dialog_* methods shows DIALOG on the screen
def dialog_menu(msg, choices): # choices are in the form (tag, item)
return D.menu(str(msg), width=WIDTH, height=HEIGHT, choices=tuple(choices))
def dialog_radiolist(msg, choices): # choices are in the form (tag, item, status) and status is boolean
return D.radiolist(str(msg), width=WIDTH, height=HEIGHT, choices=tuple(choices))
def dialog_msgbox(msg):
return D.msgbox(str(msg), width=WIDTH, height=HEIGHT)
# return (1, None)
def dialog_yesno(msg, default): # 'default' is initial value of boolean type
return int(not D.yesno(str(msg), width=WIDTH, height=HEIGHT, defaultno=not default))
def dialog_inputbox(msg, default): # default is initial string
return D.inputbox(str(msg), width=WIDTH, height=HEIGHT, init=str(default))
def dialog_checklist(msg, choices): # choices are in the form (tag, item, status) and status is boolean
return D.checklist(str(msg), width=WIDTH, height=HEIGHT, choices=tuple(choices))
def handler_AutoField(): # no args here
return (1, dialog_msgbox(u'Cannot edit AutoField'))
# Called when edit ManyToManyField, arguments: obj=model instance, field=fieldclass
def handler_ManyToManyField(obj, field):
if obj.pk == None:
return (1, dialog_msgbox('Object %s must be saved before editing ManyToManyField %s' % (obj, field.name)))
try:
checked = getattr(obj, field.name).all()
except ValueError:
checked = ()
choices = [ (str(o.pk), str(o), int(o in checked)) for o in field.rel.to.objects.all()]
ret = dialog_checklist('Choose object(s) for %s: %s' % (obj, field.name), choices)
objects = None
if not ret[0]:
objects = [field.rel.to.objects.get(pk=pk) for pk in ret[1]]
return (ret[0], objects)
# Called when edit ForeignKey, arguments: obj=model instance, field=fieldclass
def handler_ForeignKey(obj, field):
try:
default = getattr(obj, field.name)
except ObjectDoesNotExist:
default = None
choices = [ (str(o.pk), str(o), int(o == default)) for o in field.rel.to.objects.all()]
ret = dialog_radiolist('Choose object for %s: %s' % (obj, field.name), choices)
obj = None
if not ret[0]:
obj = field.rel.to.objects.get(pk=ret[1])
return (ret[0], obj)
def handler_OneToOneField(obj, field):
return handler_ForeignKey(obj, field)
def handler_BooleanField(msg, value):
return (0, dialog_yesno(msg, value))
# Called when no other handler is called
def handler_BaseField(msg, value):
return dialog_inputbox(msg, value)
# Main field handler. It determines, which other field-handler to call, arguments: obj=model instance, field=fieldclass, field_value=value as string
def field_handler(obj, field, field_value):
if isinstance(field, models.AutoField):
ret = handler_AutoField()
elif isinstance(field, models.ManyToManyField):
ret = handler_ManyToManyField(obj, field)
elif isinstance(field, models.ForeignKey):
ret = handler_ForeignKey(obj, field)
elif isinstance(field, models.OneToOneField):
ret = handler_OneToOneField(obj, field)
elif isinstance(field, models.BooleanField):
ret = handler_BooleanField('Choose yes/no for field %s of object %s' % (field.name, obj), field_value)
else:
ret = handler_BaseField('Edit field %s of object %s' % (field.name, obj), field_value)
return ret
# Mother of other AdminDialogs :))
class AdminDialog(object):
pass
# Shows dialog with list of apps
class AppsAdminDialog(AdminDialog):
def __init__(self):
choices = [(key, key) for key in Models.keys()]
while True:
ret = dialog_menu('Choose app', choices)
if ret[0]:
break
ModelsAdminDialog(ret[1])
# Shows dialog with list of app's models
class ModelsAdminDialog(AdminDialog):
def __init__(self, app):
choices = [(key, key) for key in Models[app].keys()]
while True:
ret = dialog_menu('Choose model from %s' % app, choices)
if ret[0]:
break
ActionAdminDialog(Models[app][ret[1]])
# Show dialog for choosing action
class ActionAdminDialog(AdminDialog):
def __init__(self, Model):
choices = [(key, key) for key in ('browse/edit', 'add', 'delete')]
while True:
ret = dialog_menu('Choose action for %s' % Model._meta.verbose_name, choices)
if ret[0]:
break
action = ret[1]
if action == 'browse/edit':
ObjectsAdminDialog(Model, action, ObjectDetailAdminDialog)
elif action == 'delete':
ObjectsAdminDialog(Model, action, ObjectDeleteAdminDialog)
elif action == 'add':
ObjectDetailAdminDialog(Model())
# Show dialog with list of all objects (model instances), Model=modelclass, action=string, next_dialog=class of AdminDiaalog to call next (detail or delete)
class ObjectsAdminDialog(AdminDialog):
def __init__(self, Model, action, next_dialog):
while True:
choices = [(str(o.pk), str(o)) for o in Model.objects.all()]
ret = dialog_menu('Choose object to %s' % action, choices)
if ret[0]:
break
next_dialog(Model.objects.get(pk=ret[1]))
# Show dialog to ask for deletion, arguments: obj=model instance
class ObjectDeleteAdminDialog(AdminDialog):
def __init__(self, obj):
if dialog_yesno('Delete object %s ?' % obj, False):
obj.delete()
dialog_msgbox('%s deleted' % obj)
#
class ObjectDetailAdminDialog(AdminDialog):
""" Creates choices to display on the screen
Example:
(
( field1, field_value1 ),
( field2, field_value2 ),
...
)
"""
def _init_choices(self, obj):
self.choices = []
for field_name in obj._meta.get_all_field_names():
field = obj._meta.get_field_by_name(field_name)[0]
if isinstance(field, models.related.RelatedObject): # Ignore this strange type
continue
elif isinstance(field, models.ManyToManyField):
try:
field_value = [str(M) for M in getattr(obj, field.name).all()] # Create unicode list of ManyToMany related objects
except ValueError:
field_value = None
else:
try:
field_value = getattr(obj, field.name) # Read other type of field
except:
field_value = None
self.choices.append( (field.name, str(field_value)) )
def __init__(self, obj):
changed = False # if object changes, this is set to True and finally yesno dialog asks for save
while True:
self._init_choices(obj)
ret = dialog_menu('Choose field of %s' % obj, self.choices)
if ret[0]:
if changed:
if dialog_yesno('Save changes to %s ?' % obj, False):
try:
obj.save()
dialog_msgbox('Object %s saved' % obj)
except Exception, e:
dialog_msgbox('An error occured saving object %s: %s' % (obj, e))
continue
break
field = obj._meta.get_field_by_name(ret[1])[0] # get fieldclass
try:
field_value = getattr(obj, field.name) # read value of field
except:
field_value = None
ret = field_handler(obj, field, field_value)
print ret[1] == field_value
if not ret[0]:
if ret[1] == field_value: # No change, let's continue
continue
setattr(obj, field.name, ret[1])
changed = True # Set changed flag
def run():
AppsAdminDialog()
|
More like this
- Template tag - list punctuation for a list of items by shapiromatron 10 months, 3 weeks ago
- JSONRequestMiddleware adds a .json() method to your HttpRequests by cdcarter 11 months ago
- Serializer factory with Django Rest Framework by julio 1 year, 5 months ago
- Image compression before saving the new model / work with JPG, PNG by Schleidens 1 year, 6 months ago
- Help text hyperlinks by sa2812 1 year, 7 months ago
Comments
Please login first before commenting.