Django reportlab insert pagebreak html-side - django

I'm trying to insert a pagebreak after a table in a pdf I'm generating with reportlab, I'm using the following function to generate the pdf:
def render_to_pdf(template_src, context_dict):
template = get_template(template_src)
context = Context(context_dict)
html = template.render(context)
result = StringIO.StringIO()
pdf = pisa.pisaDocument(StringIO.StringIO(html.encode("ISO-8859-1")), dest=result, link_callback=fetch_resources)
if not pdf.err:
return result.getvalue()
return HttpResponse('We had some errors<pre>%s</pre>' % escape(html))
def fetch_resources(uri, rel):
return os.path.join(MEDIA_ROOT, uri.replace(MEDIA_URL, ""))
I'm calling the function from a view this way:
#login_required(login_url=reverse('accounts:login_box'))
def quote_pdf(request, quote_id):
data_pdf = {}
quote = get_object_or_404(Quote, id=quote_id)
data_pdf['pagesize'] = 'letter'
data_pdf['quote'] = quote
pdf = render_to_pdf('rents/quote_pdf.html', data_pdf)
return HttpResponse(pdf, mimetype='application/pdf')
And this is my template (quote_pdf.html)
{% load humanize compress verbatim %}
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>Cotización No. {{ quote.id }} Flasherz.co/alquiler</title>
<style type="text/css">
#page {
size: {{ pagesize }};
margin: 1cm;
#frame footer {
-pdf-frame-content: footerContent;
bottom: 0cm;
margin-left: 0cm;
margin-right: 0cm;
height: 0cm;
}
}
</style>
<style type="text/css">
body {
font-size: 12px;
line-height: 13px;
}
div#pdf-header {
display: block;
}
div#pdf-header h2 {
display: block;
text-align: center;
font-weight: normal;
line-height: 35px;
font-size: 18px;
}
div#pdf-quote-info {
display: block;
margin-bottom: 20px;
}
p {
margin: 0;
}
table {
border-top: 1px solid #eee;
}
table td, table th {
border-right: 1px solid #eee;
border-bottom: 1px solid #eee;
padding: 5px;
border-left: 1px solid #eee;
}
table .price {
text-align: right;
}
table th {
padding: 5px 0;
font-size: 13px;
text-transform: uppercase;
color: black;
text-align: left;
background-color: #eee;
padding-left: 5px;
}
table p.description {
color: #555;
font-size: 11px;
}
table#quote-info {
border: none;
}
table#quote-info td, table#quote-info th {
border: none;
padding: 0;
}
table td.quantity {
text-align: center;
}
</style>
</head>
<body>
<div id="pdf-header">
<div style="width: 100%; text-align: center;">
<img src="{{ STATIC_URL }}img/quotes-logo.jpeg" alt="Flasherz.co Alquiler" width="600" height="126" />
<div style="display: block; text-align: center; margin: 10px 0;">
<h2>Cotización No. {{ quote.id }}, {{ quote.client_name }}</h2>
</div>
</div>
</div>
<div id="pdf-quote-info">
<table id="quote-info" width="70%" border="none" cellpadding="3" cellspacing="0">
<tr>
<td width="25%">Fecha:</td>
<td width="75%">{{ quote.created|date:'l j' }} de {{ quote.created|date:'F' }} de {{ quote.created|date:'Y' }}</td>
</tr>
{% if quote.client_name %}
<tr>
<td>Cliente:</td>
<td>{{ quote.client_name }}</td>
</tr>
{% endif %}
{% if quote.client_email %}
<tr>
<td>Correo:</td>
<td>{{ quote.client_email }}</td>
</tr>
{% endif %}
{% if quote.client_address %}
<tr>
<td>Dirección:</td>
<td>{{ quote.client_address }}</td>
</tr>
{% endif %}
{% if quote.client_phone %}
<tr>
<td>Teléfono:</td>
<td>{{ quote.client_phone }}</td>
</tr>
{% endif %}
<tr>
<td>Cantidad de días:</td>
<td>{{ quote.rental_days }}</td>
</tr>
</table>
</div>
</div>
<div id="pdf-quote-table">
<table id="quote-table" cellpadding="0" cellspacing="0" width="100%">
{% for category in quote.categories.all %}
<tbody>
<tr>
<th colspan="4" class="category-header">{{ category.category.name }}</th>
</tr>
{% for item in category.items.all %}
<tr>
<td class="quantity" width="10%">
<p>{{ item.quantity }}</p>
</td>
<td class="name" width="50%">
<p class="name">{{ item.name }}</p>
{% if item.content %}<p class="description">{{ item.content }}</p>{% endif %}
</td>
<td class="price" width="20%">
<p>${{ item.price|intcomma }}</p>
</td>
<td class="price total-price" width="20%">
<p>${{ item.total_price|intcomma }}</p>
</td>
</tr>
{% endfor %}
</tbody>
{% endfor %}
<tbody id="others">
<tr>
<th colspan="4" class="category-header">Seguro del 10%</th>
</tr>
<tr>
<td class="quantity"></td>
<td class="name">Seguro 10%</td>
<td class="price"></td>
<td class="price total-price">
<p>${{ quote.get_insurance_price|intcomma }}</p>
</td>
</tr>
</tbody>
{% if quote.discount %}
<tbody id="others">
<tr>
<th colspan="4" class="category-header">Descuento</th>
</tr>
<tr>
<td class="quantity">
</td>
<td class="name">Descuento</td>
<td class="price"></td>
<td class="price total-price">
<p>${{ quote.discount|intcomma }}</p>
</td>
</tr>
</tbody>
{% endif %}
<tbody id="totals">
<tr>
<th colspan="4" class="category-header">Total</th>
</tr>
<tr>
<td class="fake" colspan="2"></td>
<td class="name">Subtotal</td>
<td class="price">
<p>${{ quote.get_subtotal|intcomma }}</p>
</td>
</tr>
<tr>
<td class="fake" colspan="2"></td>
<td class="name">Total días</td>
<td class="price">
<p>${{ quote.get_total_days|intcomma }}</p>
</td>
</tr>
<tr>
<td class="fake" colspan="2"></td>
<td class="name">Total</td>
<td class="price">
<p><strong>${{ quote.get_total|intcomma }}</strong></p>
</td>
</tr>
</tbody>
</table>
</div>
</body>
</html>
I don't know the way to insert a pagebreak after the table to insert the "terms and conditions" in the next page.
Also I have a problem with the images in the pdf, no one is appearing when rendered.
Thanks for helping me

From what I've learned in Pisa's documentation (and this forum post), you can use standard CSS tags like page-break-after and page-break-before. Pisa also has some of it's own tags, like pdf:nextpage. To use this, simply insert the following code block where you would like the page break (the div's are necessary so Pisa's HTML5 parser doesn't try to interpret them):
<div>
<pdf:nextpage />
</div>

I've found the correct method to do it, I needed to insert a few specific styles in the of my pdf
<style type="text/css">
#page {
size: {{ pagesize }};
margin: 1cm;
#frame footer {
-pdf-frame-content: footerContent;
bottom: 0cm;
margin-left: 0cm;
margin-right: 0cm;
height: 0cm;
}
}
.page-break{
page-break-after: always;
}
</style>
Then put a element with .page-break class in where you want to have a page break in your pdf.

I had no luck with the css method.
Just insert this bit of code in your template.html wherever you want a page break. It works for me. I'm not sure, but I think it has to be in a div.
<div>
<pdf:nextpage />
</div>

Related

Django Regoup - Sum in templates

I want to get the Volume subtotal of my "Contracts" field grouped in my template.
I manage to display the total but not the subtotal.
Here are my files:
views.py
class TransportDetListView(LoginRequiredMixin,ListView):
login_url = 'admin:login'
model = TransColisCgDlaDet
template_name = "betou/transports/sciages/trans_detail.html"
paginate_by = 15
def get_queryset(self):
queryset = TransColisCgDlaDet.objects.filter(code_trans__contains=self.kwargs['code_trans']).order_by('num_contrat','essence','epaisseur')
lstcolis = queryset.values(
'num_colis',
'essence',
'epaisseur',
'qualite',
'produit',
'num_contrat',
'code_specif',
'code_specif_douane',
'destinataire',
'port_destination',
'marque',
'receptionnaire',
'code_trans'
).annotate(volumecolis=Sum('cubage')).annotate(nb_elts=Sum('nbre_elts'))
return lstcolis
def get_context_data(self, **kwargs):
context = super(TransportDetListView, self).get_context_data(**kwargs)
context['codetrans_filter'] = TransColisCgDlaDet.objects.filter(code_trans__contains=self.kwargs['code_trans']).order_by('num_contrat','essence','epaisseur')
context['nbrecolis'] = context['codetrans_filter'].values('num_colis').order_by('num_contrat').aggregate(nbrecolis=Count('num_colis')).get('nbrecolis')
context['totalvolume'] = context['codetrans_filter'].values('cubage').aggregate(totalvolume=Sum('cubage')).get('totalvolume')
context['totalelts'] = context['codetrans_filter'].values('nbre_elts').aggregate(totalelts=Sum('nbre_elts')).get('totalelts')
context['contrats'] = context['codetrans_filter'].annotate(volumecolis=Sum('cubage')).annotate(nb_elts=Sum('nbre_elts'))
return context
template
{% regroup contrats by num_contrat as lst_group %}
<table class="table table-responsive table-bordered text-center">
{% for group_ct in lst_group %}
<thead>
<tr>
<td colspan = "15" class="align-center" style="font-weight: 600">{{ group_ct.grouper }}</td>
</tr>
<tr>
<tr>
<th>N.Contrat</th>
<th>Essence</th>
<th>Epais.</th>
<th>N.Colis</th>
<th>Nb Elts</th>
<th>Volume</th>
<th>Qualité</th>
<th>Produit</th>
<th>Specif</th>
<th>Specif Douane</th>
<th>Destinataire</th>
<th>Destination</th>
<th>Marque</th>
<th>Réceptionnaire</th>
<th>Code Trans</th>
</tr>
</thead>
<tbody>
{% for trans in group_ct.list %}
<tr>
<td>{{trans.num_contrat|default_if_none:""}}</td>
<td>{{trans.essence}}</td>
<td>{{trans.epaisseur}}</td>
<td>{{trans.num_colis}}</td>
<td style="text-align: right;">{{trans.nb_elts}}</td>
<td style="text-align: right;">{{trans.volumecolis}}</td>
<td>{{trans.qualite|default_if_none:""}}</td>
<td>{{trans.produit|default_if_none:""}}</td>
<td >{{trans.num_contrat}}&nbsp{{trans.code_specif}}</td>
<td>{{trans.code_specif_douane|default_if_none:""}}</td>
<td>{{trans.destinataire|default_if_none:""}}</td>
<td>{{trans.port_destination|default_if_none:""}}</td>
<td>{{trans.marque|default_if_none:""}}</td>
<td>{{trans.receptionnaire|default_if_none:""}}</td>
<td>{{trans.code_trans}} {% if not forloop.last %}{% endif %}</td>
</tr>
{% endfor %}
<tr>
<td colspan = "3" style="text-align: center; font-weight: 600;">TOTAUX:</td>
<td style="text-align: right; font-weight: 600;">{{ group_ct.list|length }} Colis</td>
<td style="text-align: right; font-weight: 600;">{{ group_ct.list.nb_elts }}</td>
<td style="text-align: right; font-weight: 600;"> {{ group_ct.list.volumecolis }}</td>
<td colspan = "12"></td>
</tr>
{% endfor %}
<tr>
<td colspan = "3" style="text-align: center; font-weight: 600;">TOTAUX:</td>
<td style="text-align: right; font-weight: 600;">{{ nbrecolis }} Colis</td>
<td style="text-align: right; font-weight: 600;">{{ totalelts }}</td>
<td style="text-align: right; font-weight: 600;"> {{ totalvolume }}</td>
<td colspan = "12"></td>
</tr>
</tbody>
</table>
I get this result:
screenshot browser
You see that the Parcel count is done correctly {{ group_ct.list|length }}. But for the sum I don't have a subtotal result.
Thanks

customising django allauth templates

mostly trying to modify the email verification that is sent on sign-up following the allauth documentation the sent email is modified when i change email_confirmation_message.txt but when i want to use an html representaion the documentation says to use email_confirmation_message.html but it is not recognized and instead it sends the default email or if i include both it only sneds the text one and ignores the html
email_confirmation_message.html :
{% extends "account/email/base_message.txt" %}
{% load account %}
{% load i18n %}
{% block content %}{% autoescape off %}{% user_display user as user_display %}{% blocktrans with site_name=current_site.name site_domain=current_site.domain %}
<!doctype html>
<html>
<head>
<meta charset='utf-8'>
<meta name='viewport' content='width=device-width, initial-scale=1'>
<title>Snippet - GoSNippets</title>
<link href='https://stackpath.bootstrapcdn.com/bootstrap/5.0.0-alpha1/css/bootstrap.min.css' rel='stylesheet'>
<link href='' rel='stylesheet'>
<script type='text/javascript' src=''></script>
<script type='text/javascript' src='https://cdn.jsdelivr.net/npm/popper.js#1.16.0/dist/umd/popper.min.js'></script>
<script type='text/javascript' src='https://stackpath.bootstrapcdn.com/bootstrap/5.0.0-alpha1/js/bootstrap.min.js'></script>
</head>
<body oncontextmenu='return false' class='snippet-body'>
<div style="display: none; font-size: 1px; color: #fefefe; line-height: 1px; font-family: 'Lato', Helvetica, Arial, sans-serif; max-height: 0px; max-width: 0px; opacity: 0; overflow: hidden;"> We're thrilled to have you here! Get ready to dive into your new account. </div>
<table border="0" cellpadding="0" cellspacing="0" width="100%">
<table border="0" cellpadding="0" cellspacing="0" width="100%" style="max-width: 600px;">
<tr>
<td bgcolor="#ffffff" align="left" style="padding: 20px 30px 40px 30px; color: #666666; font-family: 'Lato', Helvetica, Arial, sans-serif; font-size: 18px; font-weight: 400; line-height: 25px;">
<p style="margin: 0;">We're excited to have you get started on {{ site_domain }}. First, you need to confirm your account. Just press the button below.</p>
</td>
</tr>
<tr>
<td bgcolor="#ffffff" align="left">
<table width="100%" border="0" cellspacing="0" cellpadding="0">
<tr>
<td bgcolor="#ffffff" align="center" style="padding: 20px 30px 60px 30px;">
<table border="0" cellspacing="0" cellpadding="0">
<tr>
<td align="center" style="border-radius: 3px;" bgcolor="#FFA73B">Confirm Account</td>
</tr>
</table>
</td>
</tr>
</table>
</td>
</tr> <!-- COPY -->
<tr>
<td bgcolor="#ffffff" align="left" style="padding: 0px 30px 0px 30px; color: #666666; font-family: 'Lato', Helvetica, Arial, sans-serif; font-size: 18px; font-weight: 400; line-height: 25px;">
<p style="margin: 0;">If that doesn't work, copy and paste the following link in your browser:</p>
</td>
</tr> <!-- COPY -->
</table>
<script type='text/javascript'></script>
</body>
</html>
{% endblocktrans %}{% endautoescape %}{% endblock %}
ok,so i figured it out. you have to also change email_confirmation_signup_message.txt
to email_confirmation_signup_message.html and inside it change {% include "account/email/email_confirmation_message.txt" %} to {% include "account/email/email_confirmation_message.html" %}

Django about Different templates have different results

I'm a super newbie, so please refer to this and read it.
I am creating a bulletin board that communicates by DB <> API <> WEB method.
Successfully import comments with comment.html.
However, comments cannot be imported at {%inlude%} in boardapi_detail.html.
Please refer to the picture at the bottom of the article.
view.py
class Commentapi_list(generic.TemplateView):
def get(self, request, *args, **kwargs):
data = {
'pk': self.kwargs['pk'],
}
url = 'http://127.0.0.1:8080/boardapi/' + str(data['pk']) + '/comment/'
datas = requests.get(url, params=data).json()
# print(datas)
# print(type(datas))
df = pd.DataFrame(datas)
clist = [tuple(r) for r in df.to_numpy()]
print(clist)
# print(type(clist))
return render(self.request, 'comment_form.html', {
'comment_list' : clist
})
urls.py
path('board/<int:pk>/', views.Boardapi_detail.as_view(), name="board_detail")
comment.html
{% if not comment_list %}
<p class="text-center"> There is no comment. </p>
{% endif %}
<div style="margin:20px 0;">
{% for i in comment_list %}
<table width="100%" cellpadding="0" cellspacing="0" class="tbl_replist" id="reply_list_layer">
<tbody>
<tr style="height:45px;border-top:solid 1px #dddddd;">
<td style="padding-left: 10px;border-top: 1px solid #eee;width: 114px;">{{ i.1 }}</td>
<td style="vertical-align: top;border-top: 1px solid #eee;padding: 10px 0;">{{ i.2 }}
<span style="color: #999;font-size: 11px;display: block;">{{ i.3 }}</span>
</td>
</tr>
{% if user.username == i.c_writer or user.is_staff %}
delete
{% endif %}
</tbody>
</table>
{% endfor %}
</div>
boardapi_detail.html
{% if not board_detail %}
<p class="text-center">There's nothing. </p>
{% else %}
<table border="0" cellpadding="0" cellspacing="0" width="100%">
<tr style="height:45px;border-top:solid 1px #dddddd;">
<td width="20%" align="center">title</td>
<td width="80%" align="left">{{ board_detail.b_title }} </td>
</tr>
<tr style="height:45px;border-top:solid 1px #dddddd;">
<td width="20%" align="center">writer</td>
<td width="80%" align="left">{{ board_detail.b_writer }} </td>
</tr>
<tr style="height:45px;border-top:solid 1px #dddddd;">
<td width="20%" align="center">note</td>
<td width="80%" align="left">{{ board_detail.b_note }}</td>
</tr>
<tr style="height:45px;border-top:solid 1px #dddddd;">
<td width="20%" align="center">time</td>
<td width="80%" align="left">{{ board_detail.b_date }} </td>
</tr>
<tr style="height:60px;border-top:solid 1px #dddddd;" align="center">
<td width="100%" colspan="2">
edit
<button class="btn btn-outline-success my-2 my-sm-0" style="margin-right:10px;" onclick="location.href='/board/'">list</button>
</td>
</tr>
<tr style="height:45px;border-top:solid 1px #dddddd;">
<td width="20%" align="center">comment</td>
<td width="80%" align="left">({{ board.comment_set.all.count }})</td>
</tr>
</table>
{% endif %}
{% include "comment.html" %}
The pictures below are about the first article each.
comment.html page
↑Successfully imported all 3 comments.
boardapi_detail.html page
↑couldn't get even one comment.

= and 3D Character in html | non-ASCII characters | quoted-printable | Django email templates

Django 2, Python 3.
On sending user signup emails using Django default authentication. The sent email contains corrupted html.
contains 3D with each attribute's equal sign.
style=3D"margin:
contains = with each starting new line.
padd=
ing-top:20px;
Sample Code:
<div style="padding: 40px; background: #fff;">
<table style="width: 100%;" cellspacing="0" cellpadding="0" border="0">
<tbody>
<tr>
<td style="border-bottom:1px solid #f6f6f6;">
<h1 style="font-size:14px; font-family:arial; margin:0px; font-weight:bold;">{% trans 'Greetings!,' %}</h1>
<p style="margin-top:0px; color:#bbbbbb;">{% trans 'Here are your account activation instructions.' %}</p>
</td>
</tr>
<tr>
<td style="padding:10px 0 30px 0;">
<p>{% trans 'Thank you for joining us.' %}</p>
<p>{% trans 'To activate your profile, please follow this link:' %}</p>
<center>
{% trans 'Activate Profile' %}
</center>
<b>- {% trans 'Thanks (project team)' %}</b> </td>
</tr>
<tr>
<td style="border-top:1px solid #f6f6f6; padding-top:20px; color:#777">{% trans 'If the button above does not work, try copying and pasting the URL into your browser. If you continue to have problems, please feel free to contact us at info#project.com' %}</td>
</tr>
</tbody>
</table>
</div>
Generated HTML template:
<div style=3D"padding: 40px; background: #fff;">
<table style=3D"width: 100%;" cellspacing=3D"0" cellpadding=
=3D"0" border=3D"0">
<tbody>
<tr>
<td style=3D"border-bottom:1px solid #f6f6f6;">
<h1 style=3D"font-size:14px; font-family:ar=
ial; margin:0px; font-weight:bold;">Greetings!,</h1>
<p style=3D"margin-top:0px; color:#bbbbbb;"=
>Here are your account activation instructions.</p>
</td>
</tr>
<tr>
<td style=3D"padding:10px 0 30px 0;">
<p>Thank you for joining us.</p>
<p>To activate your profile, please follow =
this link:</p>
<center>
<a href=3D"http://localhost:8000/accoun=
ts/activate/uyi90WsYyvLKmn4wwwqq/" style=3D"display: inline-block; padding:=
11px 30px; margin: 20px 0px 30px; font-size: 15px; color: #fff; background=
: #4fc3f7; border-radius: 60px; text-decoration:none;">Activate Profile</a>
</center>
<b>- Thanks (project team)</b> </td>
</tr>
<tr>
<td style=3D"border-top:1px solid #f6f6f6; padd=
ing-top:20px; color:#777">If the button above does not work, try copying an=
d pasting the URL into your browser. If you continue to have problems, plea=
se feel free to contact us at info#project.com</td>
</tr>
</tbody>
</table>
</div>
Please help resolve/identify the issue.

CSS for a 'contact sheet' view that wraps horizontally using a <ul>

I'm trying to generate an HTML/CSS combination to display a contact sheet type view of a bunch of photos, each with some text and a form element or two. I'd like the view to fill available width and wrap as needed, in order to get as many images on screen as the user's display can manage. I think a 'ul' is the right container to use, with display set to inline, and I think it's OK to use tables for each of the elements. What I've got so far looks promising in Safari (images that are under-size in either dimension are centered within their cell, wrapping behaves as intended), but fails in FireFox. It also fails the w3c validator (no doctype), but as soon as I specify a doctype the layout breaks (list goes back to displaying in a single column in both browsers).
This is what I have so far:
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
<title>Layout test</title>
<style type="text/css">
#contact_sheet li {
list-style-type: none;
display: inline;
text-align: center;
}
#contact_sheet li table {
width: auto;
border-spacing: 0px;
display: inline;
border: thin solid #202020;
background-color: #404040;
color: white;
}
#contact_sheet li th {
height: 250px;
width: 250px;
text-align: center;
vertical-align: middle;
}
#contact_sheet li td {
text-align: center;
}
th img {
border: thin solid green;
}
</style>
</head>
<body>
<ul id="contact_sheet">
<li>
<table>
<tr>
<th><img src="" width="240" height="120" /></th>
</tr>
<tr>
<td>Some text</td>
</tr>
<tr>
<td><input type="checkbox" />Select</td>
</tr>
</table>
</li>
<li>
<table>
<tr>
<th><img src="" width="120" height="240" /></th>
</tr>
<tr>
<td>Some text</td>
</tr>
<tr>
<td><input type="checkbox" />Select</td>
</tr>
</table>
</li>
<li>
<table>
<tr>
<th><img src="" width="120" height="120" /></th>
</tr>
<tr>
<td>Some text</td>
</tr>
<tr>
<td><input type="checkbox" />Select</td>
</tr>
</table>
</li>
</ul>
</body>
</html>
What am I doing wrong?
This happens because when the specific doctype, tables took up the entire width of the page.
Just make them float:left and it will work:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
<title>Layout test</title>
<style type="text/css">
#contact_sheet li {
list-style-type: none;
display: inline;
text-align: center;
}
#contact_sheet li table {
width: auto;
border-spacing: 0px;
display: inline;
border: thin solid #202020;
background-color: #404040;
color: white;
}
#contact_sheet li th {
height: 250px;
width: 250px;
text-align: center;
vertical-align: middle;
}
#contact_sheet li td {
text-align: center;
}
table {
float: left;
}
th img {
border: thin solid green;
}
</style>
</head>
<body>
<ul id="contact_sheet">
<li>
<table>
<tr>
<th><img src="" width="240" alt="" height="120" /></th>
</tr>
<tr>
<td>Some text</td>
</tr>
<tr>
<td><input type="checkbox" />Select</td>
</tr>
</table>
</li>
<li>
<table>
<tr>
<th><img src="" width="120" alt="" height="240" /></th>
</tr>
<tr>
<td>Some text</td>
</tr>
<tr>
<td><input type="checkbox" />Select</td>
</tr>
</table>
</li>
<li>
<table>
<tr>
<th><img src="" width="120" alt="" height="120" /></th>
</tr>
<tr>
<td>Some text</td>
</tr>
<tr>
<td><input type="checkbox" />Select</td>
</tr>
</table>
</li>
</ul>
</body>
Tables are at their best when the width can be predetermined. You may be better off without tables for your desired effect. I would suggest simply wrapping each img in a div. Float all the divs left and you're done. You then eliminate the need to specify new table rows, as each new row will be created when the floated divs wrap.
That also may make it easier to apply class styles to each individual image/form.
The main problem with this approach which may make it unworkable is that your images are of indeterminate size. One div would not affect the width of the div below it, leaving you without the order of a grid