Scaffolding: scaffold.py

File scaffold.py, 8.9 KB (added by javinievas@…, 9 years ago)

scaffold file

Line 
1#!/usr/bin/env python
2
3###################################################################################################
4# Scaffolding
5# Author: Javier Nievas (javinievas@gmail.com)
6# Date: 6th August 2006
7###################################################################################################
8# BASED ON...
9# Script based on the work of:
10#  - Lllama
11#  - Akaihola
12#  - David Warry
13###################################################################################################
14# INTRODUCTION...
15# The original work lives in: http://code.djangoproject.com/wiki/ScaffoldScript
16# I have put together the generation of forms and manipulators in the same file
17###################################################################################################
18#
19# If you choose to use custom templates (-t custom) this script suppose you have three files:
20#       templates/scaffold/form.html      - the main template, it contains the form tag and a {{ formfields }}
21#       templates/scaffold/pre_form.html  - this file is prepended to generated template before the form
22#       templates/scaffold/post_form.html - this file is appened to generated template after the form
23#
24# This script was tested under Windows XP, using Django 0.96-pre
25# You may have to change some code to match your own installation
26###################################################################################################
27
28from optparse import OptionParser
29import sys
30import os
31from django.shortcuts import render_to_response
32from django.template.loader import get_template
33from django.db.models import get_model
34from django.db import models
35from django.template import Context, Template
36
37
38
39def readfile(file):
40    f = open(file,"r")
41    pre = f.read()
42    f.close()
43   
44    return pre
45
46
47def argValue(s, args):
48    if s == 'related_query_name':
49        return "???"
50    else:
51        return args[s]
52       
53def field_text(field):
54    d = field.__dict__
55    args = dict([(f, isinstance(d[f], str) and "'%s'" % d[f] or d[f]) for f in d if f not in ['db_index', 'primary_key', 'rel', 'core', 'creation_counter',
56    'editable', 'name', 'default', 'column', 'attname', 'auto_now_add', 'help_text', 'auto_now', 'unique', 'verbose_name']])
57    if args['blank'] is True or args['null'] is True:
58        args['is_required'] = False
59    else:
60        args['is_required'] = True
61    try:
62        del(args['blank'])
63        del(args['null'])
64    except KeyError:
65        pass
66    try:
67        args['validator_list'] = ['%s' % v.__name__ for v in args['validator_list']]
68    except KeyError:
69        pass
70    if field.__class__.__name__ == 'CharField':
71        fieldType = 'TextField'
72    if field.__class__.__name__ == 'TextField':
73        fieldType = 'LargeTextField'
74    elif field.__class__.__name__ == 'ForeignKey':
75        fieldType = 'SelectField'
76        args['choices'] = "[('','-------')] + [(o.id, o) for o in %s.get_list()]" % (field.name.lower() + "s",)
77    elif field.__class__.__name__ == 'BooleanField':
78        fieldType = 'CheckboxField'
79    elif field.__class__.__name__ == 'DateTimeField':
80        fieldType = 'DatetimeField'
81    elif field.__class__.__name__ == 'ManyToManyField':
82        fieldType = 'SelectMultipleField'
83        args['choices'] = "[(o.id, o) for o in %s.get_list()]" % (field.name.lower() + "s",)
84    else:
85        fieldType = field.__class__.__name__
86   
87    extra_args = ["%s=%s" % (s, argValue(s, args)) for s in args if args[s] not in [None, '', False, []]]
88    #print field.name, extra_args
89    if extra_args:       
90        return '''\
91            forms.%s(field_name='%s', %s),''' % (fieldType, field.name, ', '.join(extra_args))
92    else:
93        return '''\
94            forms.%s(field_name='%s'),''' % (fieldType, field.name)
95
96def value_text(field):
97    return """\
98                %s=new_data['%s']""" % (field.name, field.name)
99
100def m2m_text(field):
101    return """        temp.set_%s(newdata['%s'])""" % (field.name, field.name)
102
103def image_field_html(name):
104    return '''\
105        {{ form.NAME_file }} \
106        {{ form.NAME }}
107        {% if form.NAME.errors %}
108        <div class='div_errors'>
109        {{ form.NAME.errors|join:", " }}
110        </div>
111        {% endif %}'''.replace('NAME', name)
112
113def field_html(name):
114    return '''\
115    {{ form.NAME }}
116    {% if form.NAME.errors %}
117      <div class='div_errors'>
118      {{ form.NAME.errors|join:", " }}
119      </div>
120    {% endif %}'''.replace('NAME', name)
121
122
123def labeled_field_html(field):
124    if isinstance(field, models.DateTimeField):
125        rows = [field_html(field.name + '_' + suffix)
126                for suffix in 'date', 'time']
127    elif isinstance(field, models.ImageField):
128        rows = [image_field_html(field.name)]
129    else:
130        rows = [field_html(field.name)]
131    return '''\
132  <li>
133    <label for="id_%s">%s:</label>
134%s
135  </li>''' % (field.name, field.verbose_name or field.name, '\n'.join(rows))
136
137def renderForm(appname, modelname):
138   
139    modelobj = get_model(appname, modelname)
140   
141    template = Template(
142"""<form method="POST" action=".">
143<fieldset>
144<legend>{{modelname}}</legend>
145<ul>
146{{ formfields }}
147</ul>
148</fieldset>
149<input type="submit" value="submit" />
150</form>
151""")
152
153    context = Context({'formfields': '\n'.join(labeled_field_html(f) for f in modelobj._meta.fields + modelobj._meta.many_to_many if f.name !='id'), 'modelname':modelname})
154   
155    if (options.template == "custom"):
156        t=get_template('scaffold/form.html')
157        out = readfile("../apps/%s/templates/scaffold/pre_form.html" % appname )
158        out += t.render(context)
159        out += readfile("../apps/%s/templates/scaffold/post_form.html" % appname )
160        return out
161    else:
162        return template.render(context)
163
164def renderManipulator(appname, modelname, manipname):
165    modelobj = get_model(appname, modelname)
166   
167    template = Template(
168"""class {{ name }}Manipulator(forms.Manipulator):
169    def __init__(self, pk=None):
170        if pk:
171            # change
172            self.original_object = {{model}}.objects.get(id=pk)
173            self.pk = pk
174        else:
175            # add
176            self.original_object = None
177            self.pk = None
178       
179        self.fields = (
180{{ fields }}
181        )
182
183    def save(self, new_data):
184        if self.original_object:
185            # update
186            temp = dict(
187{{ values }}           
188            )
189            for k,v in temp.iteritems():
190                self.original_object.__setattr__(k, v)
191            self.original_object.save()           
192            return {{model}}.objects.get(id=pk)
193           
194        else:
195            # insert
196            temp = {{ model }}(
197{{ values }}
198            )
199{{ m2m }}
200            temp.save()
201            return temp
202        """)
203
204    context = Context({'fields': '\n'.join([field_text(f) for f in modelobj._meta.fields + modelobj._meta.many_to_many if f.name !='id']), 
205                'name': manipname, 
206                'model': modelname, 
207            'values': ',\n'.join([value_text(f) for f in modelobj._meta.fields if f.name != 'id']),                               
208                'm2m': '\n'.join([m2m_text(f) for f in modelobj._meta.many_to_many])})
209
210    if (options.template == "custom"):
211        t=get_template('scaffold/manipulator.py')
212        return  t.render(context)
213    else:
214        return template.render(context)
215
216
217if __name__ == "__main__":
218
219    try:
220        import settings
221    except ImportError:
222        print "Settings file not found.  Place this file in the same place as manage.py"
223        sys.exit()
224
225    project_directory = os.path.dirname(settings.__file__)
226    project_name = os.path.basename(project_directory)
227    sys.path.append(os.path.join(project_directory, '..'))
228    project_module = __import__(project_name, '', '', [''])
229    sys.path.pop()
230    os.environ['DJANGO_SETTINGS_MODULE'] = '%s.settings' % project_name
231
232    p = OptionParser()
233
234    #p.add_option("-p", "--project", dest="project", help="The project which contains the model")
235    p.add_option("-g","--generate", dest="generate", help="Choose between form or manipulator")
236    p.add_option("-a", "--app", dest="app", help="The app which contains the model")
237    p.add_option("-m", "--model", dest="model", help="The model to produce the form for")
238    p.add_option("-n", "--name", dest="name", help="The name of the custom manipulator")
239    p.add_option("-t", "--template", dest="template", help="Type custom to use your template/scaffold directory or leave blank for default template")
240
241    options, args = p.parse_args()
242
243    if not (options.generate and options.model and options.app):
244        p.print_help()
245        sys.exit()
246
247    if not options.name:
248        options.name = "%s%s" % (options.app, options.model)
249
250    m = __import__("%s.models" % (options.app,), '', '', [options.model])
251
252    a = getattr(m, options.model)
253   
254    if options.generate == "form":
255        print renderForm(options.app, options.model)
256    elif options.generate == "manipulator":
257        print renderManipulator(options.app, options.model, options.name)
258
Back to Top