|
ManipulatorsMultipleModels
Manipulators with multiple modelsHere are examples (from one of my projects). I hope that this can help someone. The code is mostly hacked out from django.contrib.admin. Two model add form: #!python
@staff_member_required
@user_passes_test(lambda u: u.has_perm('nekretnine.add_realestate'))
@transaction.commit_manually
def add_rs(request, rs_type):
rs_type = int(rs_type)
rs = RealEstate.AddManipulator() #IGNORE:E1101
detail_model = get_detail_model(rs_type)
detail = detail_model.AddManipulator() #IGNORE:W0621
inline_related_objects = RealEstate._meta.get_followed_related_objects(rs.follow) #IGNORE:E1101
if request.POST:
# If data was POSTed, we're trying to create a new object(s).
new_data = request.POST.copy()
new_data['type'] = rs_type
if RealEstate._meta.has_field_type(models.FileField): #IGNORE:E1101
new_data.update(request.FILES)
# Check for errors.
errors = {}
errors.update(rs.get_validation_errors(new_data))
errors.update(detail.get_validation_errors(new_data))
rs.do_html2python(new_data)
detail.do_html2python(new_data)
if not len(errors):
# No errors. This means we can save the data!
try:
new_rs = rs.save(new_data)
new_data['parent'] = new_rs._get_pk_val()
new_det = detail.save(new_data)
_log(request, new_rs, ADDITION)
_log(request, new_det, ADDITION, add_msg=False)
transaction.commit()
except:
# something is wrong, rollback
transaction.rollback()
raise
return HttpResponseRedirect("../../../")
else:
# No POST, so we want a brand new form without any data or errors.
errors = {}
new_data = {'type': rs_type}
new_data.update(rs.flatten_data())
new_data.update(detail.flatten_data())
# Create the FormWrapper, template, context, response.
rs_form = forms.FormWrapper(rs, new_data, errors)
detail_form = forms.FormWrapper(detail, new_data, errors)
ctx_dict = {
'rs_type': rs_type,
'num_errors': len(errors),
'form': rs_form, # main form admin tags
'detail': detail_form, # add-on form
'detail_template': 'nekretnine/detail-%d.html' % rs_type,
'title': CATEGORY_NAMES[rs_type],
'inline_related_objects': inline_related_objects,
}
return render_to_response('nekretnine/rs_form.html', ctx_dict, context_instance=Context(request))and this is paired with some template tags: #!python
FTPL = """
{%% if %(field)s.errors %%}
<ul class="errorlist">{%% for err in %(field)s.errors %%}<li>{{ err }}</li>{%% endfor %%}</ul>
{%% endif %%}
<label for="{{ %(field)s.get_id }}" class="%(inline)s{%% if %(field)s.formfield.is_required %%} required{%% endif %%}">%(label)s:</label>
{{ %(field)s }}
%(addlink)s
"""
ROFTPL = """
<!-- READONLY -->
<label for="{{ %(field)s.get_id }}" class="%(inline)s{%% if %(field)s.formfield.is_required %%} required{%% endif %%}">%(label)s:</label>
<input disabled class="vTextField" id="{{ %(field)s.get_id }}" value="{{ %(wrapper)s.data.%(orig_field)s|default:"%(default)s" }}" />
%(addlink)s
"""
# TODO: help
class FormFieldNode(Node):
def __init__(self, field, label, readonly=False, inline=False, single=False, filter_=None):
super(FormFieldNode, self).__init__()
self.label = label
self.readonly = readonly
self.wrapper, self.field = field.split('.')
self.inline = inline
self.single = single
self.filter = filter_
def render(self, context): #IGNORE:R0912
wrapper = self.wrapper #IGNORE:W0612
orig_field = self.field #IGNORE:W0612
label = self.label #IGNORE:W0612
field = '%s.%s' % (self.wrapper, self.field) #IGNORE:W0612
user = get_current_user()
addlink = '' #IGNORE:W0612
js = None
if self.inline:
inline = 'inline' #IGNORE:W0612
else:
inline = ''
try:
if not self.readonly:
if user is not None and not user.is_anonymous():
model = resolve_variable(self.wrapper, context).manipulator.model #IGNORE:E1101
try:
fld = model._meta.get_field(self.field)
except FieldDoesNotExist:
raise TemplateSyntaxError, 'Field "%s" does not exists in model "%s"' % (self.field, model._meta.object_name)
#
if fld.rel:
to = fld.rel.to._meta
if user.has_perm('%s.%s' % (to.app_label, to.get_add_permission())):
alt = gettext('Add Another')
module = to.module_name
app_label = to.app_label
addlink = '\n<a href="/admin/%(app_label)s/%(module)s/add/" class="add-another" id="add_{{ %(field)s.get_id }}" onclick="return showAddAnotherPopup(this);"> <img src="/admin-media/img/admin/icon_addlink.gif" alt="%(alt)s" height="10" width="10"></a>\n' % locals()
#
if self.filter is not None:
if self.filter == 'horizontal':
dir = 0
else:
dir = 1
js = Template('<script type="text/javascript">addEvent(window, "load", function(e) { SelectFilter.init("{{ %(field)s.get_id }}", "{{ %(field)s.get_member_name }}", %(dir)d, "/admin-media/"); });</script>' % locals())
t = Template(FTPL % locals())
else:
# XXX escape field data??
default = gettext('Empty')
t = Template(ROFTPL % locals())
if not self.single:
return t.render(context)
else:
if js is None:
return '<div class="form-row">%s</div>' % t.render(context)
else:
return '<div class="form-row">%s</div>%s' % (t.render(context), js.render(context))
except TemplateSyntaxError, e:
if settings.TEMPLATE_DEBUG:
raise
return ''
I18NRE = re.compile(r'^_\((?:\'|")(.*?)(?:\'|")\)$')
# TODO: better syntax check
@register.tag
def formfield(parser, token):
"""
Create form field.
Example::
{% formfield <field> <label> [filter horizontal|vertical] [as [readonly] [inline] %}
"""
class Parser(TokenParser):
def top(self):
field = None
label = None
readonly = False
inline = False
single = False
filter = None
ct = 0
while self.more():
if ct == 0:
field = self.value()
elif ct == 1:
val = self.value().strip('"')
val = val.strip("'")
r = I18NRE.match(val)
if r:
label = gettext(r.group(1))
else:
label = val
else:
tag = self.tag()
if tag == 'filter':
filter = self.value()
single = True # force single
elif tag == 'as':
while self.more():
tag = self.tag()
if tag == 'readonly':
readonly = True
elif tag == 'inline':
inline = True
elif tag == 'single':
single = True
else:
raise TemplateSyntaxError, "'formfield' syntax error (got %r)" % tag
else:
raise TemplateSyntaxError, "'formfield' syntax error"
ct += 1
# while
return field, label, readonly, inline, single, filter
field, label, readonly, inline, single, filter = Parser(token.contents).top()
return FormFieldNode(field, label, readonly, inline, single, filter)
class FormRowNode(Node):
def __init__(self, nodelist):
super(FormRowNode, self).__init__()
self.nodelist = nodelist
def render(self, context):
try:
return '<div class="form-row">%s</div>' % self.nodelist.render(context)
except Exception:
raise
return ''
@register.tag
def formrow(parser, token):
"""
Create form row template.
Example::
{% formrow %}
{% formfield <field> with <label> [as readonly] %}
{% endformrow %}
"""
nodelist = parser.parse(('endformrow',))
parser.delete_first_token()
return FormRowNode(nodelist)
|
Sign in to add a comment
