jinja2.exceptions.UndefinedError: object has no attribute - python

I am trying to create an Inventory Management System in which i can create/add stock through a form(WTForms) and have it displayed in a table on a separate page. Currently, i am stuck on the stated error. I have looked everywhere for an answer to no avail. I am supposed to add stock through 'createGPU.html' and be directed to 'retrieveGPU.html'
Clicking the submit button in createGPU results in jinja2.exceptions.UndefinedError: 'GPUs.GPUs object' has no attribute 'GPUName'
Main Program
from flask import Flask, render_template, request, redirect, url_for
from Forms import CreateGPUForm
import shelve, GPUs
#app.route("/createGPU", methods=['GET', 'POST'])
def createGPU():
createGPUForm = CreateGPUForm(request.form)
if request.method == 'POST' and createGPUForm.validate():
gpuDict = {}
db = shelve.open('storage.db', 'c')
try:
gpuDict = db['GPU']
except:
print('Error in retrieving GPUs from storage.db.')
gpu = GPUs.GPUs(createGPUForm.GPUName.data, createGPUForm.GPUUnitPrice.data, createGPUForm.GPUStock.data,createGPUForm.GPUSales.data)
gpuDict[gpu.get_GPUNo()] = gpu
db['GPU'] = gpuDict
db.close()
return redirect(url_for('retrieveGPU'))
return render_template('createGPU.html', form=createGPUForm)
if __name__ == '__main__':
app.run()
#app.route('/retrieveGPU')
def retrieveGPU():
gpuDict = {}
db = shelve.open('storage.db', 'r')
gpuDict = db['GPU']
db.close()
gpuList = []
for key in gpuDict:
gpu = gpuDict.get(key)
gpuList.append(gpu)
return render_template('retrieveGPU.html',gpuList=gpuList, count=len(gpuList))
createGPU
{% extends "base.html" %}
{% block title %}GPU-Assist - Add Graphics Card{% endblock %}
{% block content %}
{% from "includes/_formhelper.html" import render_field %}
<h1 class="display-4">Add Graphics Card</h1>
<form method="POST" action="">
<div class="form-group">
{{ render_field(form.GPUName, class="form-control") }}
</div>
<div class="form-group">
{{ render_field(form.GPUStock, class="form-control") }}
</div>
<div class="form-group">
{{ render_field(form.GPUUnitPrice, class="form-control") }}
</div>
<div class="form-group">
{{ render_field(form.GPUSales, class="form-control") }}
</div>
<input type="submit" value="Submit" class="btn btn-primary"/>
</form>
{% endblock %}
retrieveGPU
{% extends "base.html" %}
{% block title %}GPU-Assist - View GPU-Cart{% endblock %}
{% block content %}
<h1 class="display-4">View GPU</h1>
<div>
{% if count == 0 %}
<p>No GPU in recorded in inventory.</p>
{% elif count == 1 %}
<p>There is 1 GPU recorded in the inventory.</p>
{% else %}
<p>There are {{ count }} GPUs recorded in the inventory.</p>
{% endif %}
</div> <!--End of display number of users div-->
<div>
<table class="table table-striped">
<thead>
<tr>
<th>Name</th>
<th>Stock</th>
<th>Unit Price</th>
<th>Sales</th>
<th></th>
<th></th>
</tr>
</thead>
<tbody>
{% for gpu in gpuList %}
<tr>
<td>{{ gpu.GPUName() }}</td>
<td>{{ gpu.GPUStock() }}</td>
<td>{{ gpu.GPUUnitPrice() }}</td>
<td>{{ gpu.GPUSales() }}</td>
<td>Update</td>
<td>
<form action="" method="POST">
<input type="submit" value="Delete" class="btn btn-danger">
</form>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% endblock %}
GPUs.py
class GPUs:
countID = 0
def __init__(self,GPUName,GPUStock,GPUUnitPrice,GPUSales):
GPUs.countID += 1
self.__GPUName = GPUName
self.__GPUStock = GPUStock
self.__GPUUnitPrice = GPUUnitPrice
self.__GPUSales = GPUSales
self.__GPUNo=GPUs.countID
'''
One obvious limitation it has is that every time you restart the web application, the countID resets to 0.
Once the countID resets, the next newly created Users’s userID will start from 1 again and overwrite any User
that previously had __userID = 1. (Must figure out an alternative)
'''
#Getter or Accessor
def get_GPUNo(self):
return self.__GPUNo
def get_GPUName(self):
return self.__GPUName
def get_GPUStock(self):
return self.__GPUStock
def get_GPUUnitPrice(self):
return self.__GPUUnitPrice
def get_GPUSales(self):
return self.__GPUSales
#Settor or Mutator
def set_GPUNo(self, GPUNo):
self.__GPUNo = GPUNo
def set_GPUName(self, GPUName):
self.__GPUName = GPUName
def set_GPUStock(self, GPUStock):
self.__GPUStock = GPUStock
def set_GPUUnitPrice(self, GPUUnitPrice):
self.__GPUUnitPrice = GPUUnitPrice
def set_GPUSales(self, GPUSales):
self.__GPUSales = GPUSales

When Jinja2 processes
<td>{{ gpu.GPUName() }}</td>
it expects that gpu will have a callable member function named GPUName. The way you've coded things up, get_GPUName is what you want instead.
The Pythonic way were be to drop the getters and setters entirely, removed the double-underscore prefixes, and have the template go directly for the named instance variable.
<td>{{ gpu.GPUName }}</td>

Related

Flask list of fields gets the data inside just the first element

I am trying to get the data from a form that is made dynamically using Flask and WTForms. To do that I've created a list that gets populated when a user opens the link, but when I try to get the data from html I only get the data from the first element of the list.
Forms:
class Details_Form(FlaskForm):
preschool_groups = []
classes = []
continue_button = SubmitField('Continuă')
def appeend_group(self):
preschool_details = Preschool_Details()
self.preschool_groups.append(preschool_details)
def appeend_class(self, choices):
class_details = Classes_Details()
class_details.class_type.choices = choices
self.classes.append(class_details)
class Preschool_Details(FlaskForm):
group_name = StringField('', validators=[DataRequired()])
group_size = IntegerField('', validators=[DataRequired()])
class Classes_Details(FlaskForm):
class_name = StringField('', validators=[DataRequired()])
class_size = IntegerField('', validators=[DataRequired()])
class_type = SelectField('', validators=[DataRequired()])
Routes:
#app.route('/detalii-scoala/<school>/<groups>/<classes>', methods=['GET','POST'])
#login_required
def school_details_page(school, groups, classes):
groups = int(groups)
classes = int(classes)
details_form = Details_Form()
details_form.classes.clear()
details_form.preschool_groups.clear()
school_db_item = db.session.query(School).join(User, User.id == School.psychologist_id).filter(User.id == current_user.id).filter(School.school==school).first()
education_types = school_db_item.education_type.split(',')
for _ in range(groups):
details_form.appeend_group()
for _ in range(classes):
details_form.appeend_class(education_types)
if details_form.continue_button.data and details_form.validate_on_submit():
for preschool_details in details_form.preschool_groups:
group = Group(name=preschool_details.group_name.data, number_of_pupils=preschool_details.group_size.data, school_id=school_db_item.id)
db.session.add(group)
for class_details in details_form.classes:
print(class_details.class_name.data)
c = Classes(name=class_details.class_name.data, number_of_students=class_details.class_size.data, class_type=class_details.class_type.data, school_id=school_db_item.id)
db.session.add(c)
db.session.commit()
details_form.classes.clear()
details_form.preschool_groups.clear()
flash('Detaliile au fost inregistrate')
return redirect(url_for('session_page'))
return render_template('detalii-scoala.html', details_form=details_form)
html:
<form action="" method="post">
{{ details_form.hidden_tag() }}
<table>
{% for preschool in details_form.preschool_groups %}
<tr>
<td><p>
{{ preschool.group_name(class_="form-control") }}<br>
{% for error in preschool.group_name.errors %}
<span class="error">[{{ error }}]</span>
{% endfor %}
</p></td>
<td><p>
{{ preschool.group_size(class_="form-control") }}<br>
{% for error in preschool.group_size.errors %}
<span class="error">[{{ error }}]</span>
{% endfor %}
</p></td>
</tr>
{% endfor %}
</table>
<br>
<table>
<tr>
<td>Denumire clasă</td>
<td>Nr. elevi înscrişi</td>
<td>Ciclul</td>
</tr>
{% for class in details_form.classes %}
<tr>
<td><p>
{{ class.class_name(class_="form-control") }}<br>
{% for error in class.class_name.errors %}
<span class="error">[{{ error }}]</span>
{% endfor %}
</p></td>
<td><p>
{{ class.class_size(class_="form-control") }}<br>
{% for error in class.class_size.errors %}
<span class="error">[{{ error }}]</span>
{% endfor %}
</p></td>
<td><p>
{{ class.class_type(class_="form-control") }}<br>
{% for error in class.class_type.errors %}
<span class="error">[{{ error }}]</span>
{% endfor %}
</p></td>
</tr>
{% endfor %}
</table>
<p>{{ details_form.continue_button(class_="btn btn-primary") }}</p>
</form>
Front end works, the only problem is when I try to add the data from thee form in the database.
The problem was that HTML fields were having the same name. To solve that I used request.form.getlist('name) to create the lists

How do you add a summary row for Flask-Admin?

In my flask-admin index_view, I am displaying financial information for my rows.
I would like to add an extra row, "summary row", at the bottom of my index_view table which sums up all the columns.
How can I accomplish this?
There's a couple of things you need to do. Provide a custom list.html template and override the render() method for the view. In the render method inject your summary data into the kwargs and in the custom template use the summary data to output appropriate html. You could add the summary data to the end of the existing data table or add it to a separate table, as seen in the example below.
Here's a self-contained example (two files) using Flask-Admin 1.5, SQLAlchemy and SQLite. custom_list.html is taken directly from flask-admin list.html and we are manipulating the block beginning at line 68:
{% block model_list_table %}
...
{% endblock %}
Note that in the render() method the summary data is an array of dicts. Each dict has a 'title' attribute (e.g 'title: 'Page Total' plus an attribute for each of the columns summary data is required.
app.py
import random
import string
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_admin.contrib.sqla import ModelView
from flask_admin import Admin, expose
# Create application
from sqlalchemy import func
app = Flask(__name__)
# Create dummy secrey key so we can use sessions
app.config['SECRET_KEY'] = '123456790'
# Create in-memory database
app.config['DATABASE_FILE'] = 'sample_db.sqlite'
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///' + app.config['DATABASE_FILE']
db = SQLAlchemy(app)
# Flask views
#app.route('/')
def index():
return 'Click me to get to Admin!'
class Project(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(255), nullable=False, unique=True)
cost = db.Column(db.Integer(), nullable=False)
def __str__(self):
return unicode(self).encode('utf-8')
def __unicode__(self):
return "Name: {name}; Cost : {cost}".format(name=self.name, cost=self.cost)
class ProjectView(ModelView):
# don't call the custom page list.html as you'll get a recursive call
list_template = 'admin/model/custom_list.html'
form_columns = ('name', 'cost')
page_size = 5
def page_cost(self, current_page):
# this should take into account any filters/search inplace
_query = self.session.query(Project).limit(self.page_size).offset(current_page * self.page_size)
return sum([p.cost for p in _query])
def total_cost(self):
# this should take into account any filters/search inplace
return self.session.query(func.sum(Project.cost)).scalar()
def render(self, template, **kwargs):
# we are only interested in the list page
if template == 'admin/model/custom_list.html':
# append a summary_data dictionary into kwargs
_current_page = kwargs['page']
kwargs['summary_data'] = [
{'title': 'Page Total', 'name': None, 'cost': self.page_cost(_current_page)},
{'title': 'Grand Total', 'name': None, 'cost': self.total_cost()},
]
return super(ProjectView, self).render(template, **kwargs)
admin = Admin(app, template_mode="bootstrap3")
admin.add_view(ProjectView(Project, db.session))
def build_sample_db():
db.drop_all()
db.create_all()
for _ in range(0, 100):
_cost = random.randrange(1, 1000)
_project = Project(
name=''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(10)),
cost=_cost
)
db.session.add(_project)
db.session.commit()
if __name__ == '__main__':
build_sample_db()
app.run(port=5000, debug=True)
templates/admin/model/custom_list.html
{% extends 'admin/model/list.html' %}
{% block model_list_table %}
<div class="table-responsive">
<table class="table table-striped table-bordered table-hover model-list">
<thead>
<tr>
{% block list_header scoped %}
{% if actions %}
<th class="list-checkbox-column">
<input type="checkbox" name="rowtoggle" class="action-rowtoggle" title="{{ _gettext('Select all records') }}" />
</th>
{% endif %}
{% block list_row_actions_header %}
{% if admin_view.column_display_actions %}
<th class="col-md-1"> </th>
{% endif %}
{% endblock %}
{% for c, name in list_columns %}
{% set column = loop.index0 %}
<th class="column-header col-{{c}}">
{% if admin_view.is_sortable(c) %}
{% if sort_column == column %}
<a href="{{ sort_url(column, True) }}" title="{{ _gettext('Sort by %(name)s', name=name) }}">
{{ name }}
{% if sort_desc %}
<span class="fa fa-chevron-up glyphicon glyphicon-chevron-up"></span>
{% else %}
<span class="fa fa-chevron-down glyphicon glyphicon-chevron-down"></span>
{% endif %}
</a>
{% else %}
{{ name }}
{% endif %}
{% else %}
{{ name }}
{% endif %}
{% if admin_view.column_descriptions.get(c) %}
<a class="fa fa-question-circle glyphicon glyphicon-question-sign"
title="{{ admin_view.column_descriptions[c] }}"
href="javascript:void(0)" data-role="tooltip"
></a>
{% endif %}
</th>
{% endfor %}
{% endblock %}
</tr>
</thead>
{% for row in data %}
<tr>
{% block list_row scoped %}
{% if actions %}
<td>
<input type="checkbox" name="rowid" class="action-checkbox" value="{{ get_pk_value(row) }}" title="{{ _gettext('Select record') }}" />
</td>
{% endif %}
{% block list_row_actions_column scoped %}
{% if admin_view.column_display_actions %}
<td class="list-buttons-column">
{% block list_row_actions scoped %}
{% for action in list_row_actions %}
{{ action.render_ctx(get_pk_value(row), row) }}
{% endfor %}
{% endblock %}
</td>
{%- endif -%}
{% endblock %}
{% for c, name in list_columns %}
<td class="col-{{c}}">
{% if admin_view.is_editable(c) %}
{% set form = list_forms[get_pk_value(row)] %}
{% if form.csrf_token %}
{{ form[c](pk=get_pk_value(row), display_value=get_value(row, c), csrf=form.csrf_token._value()) }}
{% else %}
{{ form[c](pk=get_pk_value(row), display_value=get_value(row, c)) }}
{% endif %}
{% else %}
{{ get_value(row, c) }}
{% endif %}
</td>
{% endfor %}
{% endblock %}
</tr>
{% else %}
<tr>
<td colspan="999">
{% block empty_list_message %}
<div class="text-center">
{{ admin_view.get_empty_list_message() }}
</div>
{% endblock %}
</td>
</tr>
{% endfor %}
</table>
</div>
<h3>Summaries</h3>
<div class="table-responsive">
<table class="table table-striped table-bordered table-hover model-list">
<thead>
<tr>
{% if actions %}
<th class="list-checkbox-column">
</th>
{% endif %}
<th class="col-md-1"></th>
{% for c, name in list_columns %}
{% set column = loop.index0 %}
<th class="column-header col-{{c}}">
{{ name }}
</th>
{% endfor %}
</tr>
</thead>
{% for row in summary_data %}
<tr>
<td colspan="2"><strong>{{ row['title'] or ''}}</strong></td>
{% for c, name in list_columns %}
<td class="col-{{c}}">
{{ row[c] or ''}}
</td>
{% endfor %}
</tr>
{% endfor %}
</table>
</div>
{% block list_pager %}
{% if num_pages is not none %}
{{ lib.pager(page, num_pages, pager_url) }}
{% else %}
{{ lib.simple_pager(page, data|length == page_size, pager_url) }}
{% endif %}
{% endblock %}
{% endblock %}

Finding the sum of numbers in jinja2 template using flask

I am learning flask and tried to create a web app that accepts a student's name and marks, finds the total of all the marks and display things in a table. But the total always gets displayed as 0.
The code is given below
mark_total.py:
from flask import Flask, render_template, request
app = Flask (__name__)
#app.route('/')
def student():
return render_template('student.html')
#app.route('/result', methods = ['POST', 'GET'])
def result():
if request.method == 'POST':
result = request.form
return render_template('result.html', result = result)
if __name__ == '__main__':
app.run(host = '0.0.0.0', debug = True)
student.html:
<form action = "/result" method = "POST">
<p>Name <input type = "text" name = "Name" /></p>
<p>Physics <input type = "text" name = "Physics" /></p>
<p>Chemistry <input type = "text" name = "chemistry" /></p>
<p>Maths <input type ="text" name = "Mathematics" /></p>
<p><input type = "submit" value = "submit" /></p>
</form>
</body>
</html>
result.html:
<html>
<head>
<title>Results</title>
</head>
<body>
<h1>{{result["Name"]}}'s results</h1>
{% set total = 0 %}
<table border = 1>
{% for key, val in result.iteritems() %}
{% if key != 'Name' %}
{% set total = total|int + val|int %}
<tr>
<td>{{ key }}</td>
<td>{{ val }}</td>
<td>{{ total }}</td>
</tr>
{% endif %}
{% endfor %}
<tr>
<td>Total</td>
<td>{{total}}</td>
</tr>
</table>
</body>
</html>
The html source of the output is as follows:
<html>
<head>
<title>Results</title>
</head>
<body>
<h1>ABC's results</h1>
<table border = 1>
<tr>
<td>Mathematics</td>
<td>100</td>
<td>100</td>
</tr>
<tr>
<td>chemistry</td>
<td>100</td>
<td>100</td>
</tr>
<tr>
<td>Physics</td>
<td>100</td>
<td>100</td>
</tr>
<tr>
<td>Total</td>
<td>0</td>
</tr>
</table>
</body>
</html>
Can someone please help me understand how to solve this?
The problem is that your total defined inside the loop is not the same total defined (and accessed) outside of loop. This is what local scopes do.
You can overcome this by using a hack like this (adapted from this answer).
<html>
<head>
<title>Results</title>
</head>
<body>
<h1>{{result["Name"]}}'s results</h1>
{% set total = [0] %}
<table border = 1>
{% for key, val in result.iteritems() %}
{% if key != 'Name' %}
{% set _ = total.append(total.pop() + val|int) %}
<tr>
<td>{{ key }}</td>
<td>{{ val }}</td>
<td>{{ total[0] }}</td>
</tr>
{% endif %}
{% endfor %}
<tr>
<td>Total</td>
<td>{{ total[0] }}</td>
</tr>
</table>
</body>
</html>
But I'm really not sure that it is a good idea to do such things in a template. The main idea of templates is to separate the logic (like counting the totals) and the representation, and this is a violation of this principle.
When you change variable value inside a loop does not effect outside of the loop except a dict:
{% set total = {'value': 0} %}
...
{% if total.update({"value": c|int + total.value|int }) %} {% endif %}
...
{{total.value}}

Flask use marked up db query return as argument?

I hope this is possible.
Is there a way to pass back a returned element from a db query as an argument to a url_for?
It is being marked up by jinja template, but it is not a form element.
#app.route('/matcher/', methods=['GET', 'POST'])
def show_entries():
#global account_id
global load_file_id
if request.method == 'GET':
option = str(request.args.get('button'))
load_file_id = int(request.args.get('a'))
if option == 'All':
sql = """SELECT *
FROM TABLE WHERE LOAD_FILE_ID = :load_file_id"""
c = g.db.cursor()
c.execute(sql, load_file_id=load_file_id)
rows = c.fetchall()
for row in rows:
entries = [dict(title=row[0], text=row[1], text1=row[2], text2=row[3], text3=row[4], text4=row[5], text5=row[6], text6=row[7])]
media = row[8]
account_id = int(row[0])
c.execute("""UPDATE TABLE SET STATUS = 'PENDING' WHERE ACCOUNT_ID = :account_id""", account_id=account_id)
g.db.commit()
outs = mediapod(account_id)
return render_template('show_entries.html', entries=entries, media=media, outs=outs, src=src)
c.close()
elif:
############DOESN'T MATTER#############
and then
{% extends "layout.html" %}
{% block body %}
{% if session.logged_in %}
{% for entry in entries %}
<div class=entry>
<form action="{{ url_for('next') }}" method=get
class=validate>
<h2 name=id>{{ entry.title }}</h2>
<div class=subentry>
<div class=titles>
INFO:<br>
INFO:<br>
INFO:<br>
INFO:<br>
INFO:<br>
INFO:<br>
INFO:<br></div>
<div class=elements>
${{ entry.text|string }}<br>
{{ entry.text1|string }}<br>
{{entry.text2|string }}<br>
{{ entry.text3|string }}<br>
{{ entry.text4|string }}<br>
{{ entry.text5|string }}<br>
{{ entry.text6|string }}<br></div>
<div class=mediatable>
<table>
<tr>
<th>Type</th>
<th>Date</th>
<th>Status</th>
<th>Doc ID</th>
<th>Scan Date</th>
</tr>
{% for put in outs %}
<tr>
<td>{{ put.media_type|safe }}</td>
<td>{{ put.statement_date|safe }}</td>
<td>{{ put.media_status|safe }}</td>
<td>{{ put.doc_id|safe }}</td>
<td>{{ put.scan_date|safe }}</td>
</tr>
{% endfor %}
</table>
</div>
<div class=buttons>
<input type=radio name=box value=match>Match
<input type=radio name=box value=nomatch>No Match
<input type=radio name=box value=fup>Follow-Up
<input type=radio name=box value=nomedia>No Media
<input type=submit class=next name=submit value=Next>
</div>
</div>
</form>
</div>
{% else %}
<em>stuff</em>
{% endfor %}
{% endif %}
{% endblock %}
and then I have a route after that that needs to take the account_id from show_entries()
#Next Button
#app.route('/next', methods=['GET'])
def next():
status = request.args.get('box')
c = g.db.cursor()
c.execute("""UPDATE TABLE
SET STATUS = :status
WHERE ACCOUNT_ID = :account_id""",
{"status" : str(status),
"account_id" : account_id
})
g.db.commit()
return redirect(url_for('nextnext'))
Take a peak back at the url_for docs:
It accepts the name of the function as first argument and a number of keyword arguments, each corresponding to the variable part of the URL rule.
url_for can be used in your Python source:
from flask import url_for
url_for('index')
and in your templates:
If you want your next method to receive a value as part of the URL, then you can change the method definition to
#app.route('/next/<int:account_id>', methods=['GET'])
def next(account_id):
# ...
then you can pass the variable through the url_for call, either from the Python source or from your templates:
url_for('next', account_id=account_id)
If you need your show_entries view to have that value in the template, then pass the value with the render_template call:
return render_template('show_entries.html', entries=entries, media=media, outs=outs, src=src, account_id=account_id)

Multiple fields on the same row in Django

I'd like to display a row with a label, a textfield and a checkbox for each item in a database. I've managed to do this except for the checkbox that's on a new line. I wan't:
<tr>
<td>Label</td>
<td>Input</td>
<td>Checkbox</td>
<tr>
But all I get is:
<tr>
<td>Label</td>
<td>Input</td>
</tr>
<tr>
<td>Checkbox</td>
</tr>
Anyone knows how to do this?
EDIT:
To generate the form I do:
forms.py
class AttributeForm(forms.Form):
def __init__(self, *args, **kwargs):
extra = kwargs.pop('extra')
super(AttributeForm, self).__init__(*args, **kwargs)
for key in extra:
self.fields[key] = forms.CharField(label=key, initial=extra[key], required=False)
self.fields['delete_'+key] = forms.BooleanField(label='', required=False)
views.py
attribute_form = AttributeForm(extra=user)
return render_to_response('user.html', {'username': username, 'attribute_form': attribute_form})
template (user.html)
<form action="" method="post">
<table>{{ attribute_form.as_table }}</table>
<input type="submit" value="Save attributes">
</form>
EDIT 2:
My template ended up like this:
<form action="" method="post">
<table>
<tr>
{% for field in attribute_form %}
{% cycle '<th>' '' %}{% cycle field.label_tag '' %}{% cycle '</th>' '' %}
<td>{{ field }}{{ attribute_form.field.errors }}</td>
{% if not forloop.last %}{% cycle '' '</tr><tr>' %}{% endif %}
{% endfor %}
</tr>
</table>
<input type="submit" value="Save attributes">
</form>
.as_table renders each form field in seperate table row. You should render the form manually.

Categories

Resources