forked from expo/troggle
modelviz added
This commit is contained in:
parent
735b729a41
commit
f21cddb2d0
@ -65,6 +65,8 @@ class TroggleImageModel(ImageModel):
|
|||||||
class Expedition(TroggleModel):
|
class Expedition(TroggleModel):
|
||||||
year = models.CharField(max_length=20, unique=True)
|
year = models.CharField(max_length=20, unique=True)
|
||||||
name = models.CharField(max_length=100)
|
name = models.CharField(max_length=100)
|
||||||
|
|
||||||
|
# these will become min and max dates
|
||||||
date_from = models.DateField(blank=True,null=True)
|
date_from = models.DateField(blank=True,null=True)
|
||||||
date_to = models.DateField(blank=True,null=True)
|
date_to = models.DateField(blank=True,null=True)
|
||||||
|
|
||||||
@ -78,8 +80,20 @@ class Expedition(TroggleModel):
|
|||||||
def get_absolute_url(self):
|
def get_absolute_url(self):
|
||||||
return urlparse.urljoin(settings.URL_ROOT, reverse('expedition', args=[self.year]))
|
return urlparse.urljoin(settings.URL_ROOT, reverse('expedition', args=[self.year]))
|
||||||
|
|
||||||
|
def get_expedition_day(self, date):
|
||||||
|
expeditiondays = self.expeditionday_set.filter(date=date)
|
||||||
|
if expeditiondays:
|
||||||
|
assert len(expeditiondays) == 1
|
||||||
|
return expeditiondays[0]
|
||||||
|
res = ExpeditionDay(expedition=self, date=date)
|
||||||
|
res.save()
|
||||||
|
return res
|
||||||
|
|
||||||
|
|
||||||
|
class ExpeditionDay(TroggleModel):
|
||||||
|
expedition = models.ForeignKey("Expedition")
|
||||||
|
date = models.DateField()
|
||||||
|
|
||||||
#
|
#
|
||||||
# single Person, can go on many years
|
# single Person, can go on many years
|
||||||
#
|
#
|
||||||
@ -168,7 +182,7 @@ class PersonExpedition(TroggleModel):
|
|||||||
return res
|
return res
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
ordering = ('expedition',)
|
ordering = ('-expedition',)
|
||||||
#order_with_respect_to = 'expedition'
|
#order_with_respect_to = 'expedition'
|
||||||
get_latest_by = 'expedition'
|
get_latest_by = 'expedition'
|
||||||
|
|
||||||
@ -242,6 +256,7 @@ class LogbookEntry(TroggleModel):
|
|||||||
class PersonTrip(TroggleModel):
|
class PersonTrip(TroggleModel):
|
||||||
person_expedition = models.ForeignKey(PersonExpedition,null=True)
|
person_expedition = models.ForeignKey(PersonExpedition,null=True)
|
||||||
|
|
||||||
|
expeditionday = models.ForeignKey("ExpeditionDay")
|
||||||
date = models.DateField()
|
date = models.DateField()
|
||||||
time_underground = models.FloatField(help_text="In decimal hours")
|
time_underground = models.FloatField(help_text="In decimal hours")
|
||||||
logbook_entry = models.ForeignKey(LogbookEntry)
|
logbook_entry = models.ForeignKey(LogbookEntry)
|
||||||
|
@ -77,6 +77,7 @@ class SurvexBlock(models.Model):
|
|||||||
cave = models.ForeignKey('Cave', blank=True, null=True)
|
cave = models.ForeignKey('Cave', blank=True, null=True)
|
||||||
|
|
||||||
date = models.DateField(blank=True, null=True)
|
date = models.DateField(blank=True, null=True)
|
||||||
|
expeditionday = models.ForeignKey("ExpeditionDay", null=True)
|
||||||
expedition = models.ForeignKey('Expedition', blank=True, null=True)
|
expedition = models.ForeignKey('Expedition', blank=True, null=True)
|
||||||
|
|
||||||
survexfile = models.ForeignKey("SurvexFile", blank=True, null=True)
|
survexfile = models.ForeignKey("SurvexFile", blank=True, null=True)
|
||||||
|
@ -78,15 +78,9 @@ def GetPersonChronology(personexpedition):
|
|||||||
a = res.setdefault(persontrip.date, { })
|
a = res.setdefault(persontrip.date, { })
|
||||||
a.setdefault("persontrips", [ ]).append(persontrip)
|
a.setdefault("persontrips", [ ]).append(persontrip)
|
||||||
|
|
||||||
for personrole in personexpedition.personrole_set.all():
|
for personrole in personexpedition.survexpersonrole_set.all():
|
||||||
a = res.setdefault(personrole.survexblock.date, { })
|
a = res.setdefault(personrole.survexblock.date, { })
|
||||||
b = a.setdefault("personroles", { })
|
a.setdefault("personroles", [ ]).append(personrole.survexblock)
|
||||||
survexpath = personrole.survexblock.survexpath
|
|
||||||
|
|
||||||
if b.get(survexpath):
|
|
||||||
b[survexpath] += ", " + str(personrole.nrole)
|
|
||||||
else:
|
|
||||||
b[survexpath] = str(personrole.nrole)
|
|
||||||
|
|
||||||
# build up the tables
|
# build up the tables
|
||||||
rdates = res.keys()
|
rdates = res.keys()
|
||||||
@ -96,7 +90,7 @@ def GetPersonChronology(personexpedition):
|
|||||||
res2 = [ ]
|
res2 = [ ]
|
||||||
for rdate in rdates:
|
for rdate in rdates:
|
||||||
persontrips = res[rdate].get("persontrips", [])
|
persontrips = res[rdate].get("persontrips", [])
|
||||||
personroles = list(res[rdate].get("personroles", {}).items())
|
personroles = res[rdate].get("personroles", [])
|
||||||
for n in range(max(len(persontrips), len(personroles))):
|
for n in range(max(len(persontrips), len(personroles))):
|
||||||
res2.append(((n == 0 and rdate or "--"), (n < len(persontrips) and persontrips[n]), (n < len(personroles) and personroles[n])))
|
res2.append(((n == 0 and rdate or "--"), (n < len(persontrips) and persontrips[n]), (n < len(personroles) and personroles[n])))
|
||||||
|
|
||||||
|
@ -45,7 +45,7 @@ div#content h2
|
|||||||
{
|
{
|
||||||
text-align:center;
|
text-align:center;
|
||||||
font-size:200%;
|
font-size:200%;
|
||||||
padding-bottom:30px;
|
Dpadding-bottom:30px;
|
||||||
}
|
}
|
||||||
|
|
||||||
table.prevnextexpeditions
|
table.prevnextexpeditions
|
||||||
@ -118,7 +118,7 @@ div.centre img { vertical-align: middle; }
|
|||||||
|
|
||||||
h1 { text-align: center; font-size: 210%; display: inline;}
|
h1 { text-align: center; font-size: 210%; display: inline;}
|
||||||
h2 { }
|
h2 { }
|
||||||
h3 { color: #000 text-align:left; border-bottom:thin solid black; margin-bottom:1em; margin-top:1em; font-weight:bold}
|
h3 { color: #000 text-align:left; Dborder-bottom:thin solid black; margin-bottom:1em; margin-top:1em; font-weight:bold}
|
||||||
h4 { color: #0d664c; }
|
h4 { color: #0d664c; }
|
||||||
h4.navbar {line-height: 0px;}
|
h4.navbar {line-height: 0px;}
|
||||||
img.onright, div.onright { vertical-align: top; float: right;
|
img.onright, div.onright { vertical-align: top; float: right;
|
||||||
|
201
modelviz.py
Executable file
201
modelviz.py
Executable file
@ -0,0 +1,201 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
"""Django model to DOT (Graphviz) converter
|
||||||
|
by Antonio Cavedoni <antonio@cavedoni.org>
|
||||||
|
|
||||||
|
Make sure your DJANGO_SETTINGS_MODULE is set to your project or
|
||||||
|
place this script in the same directory of the project and call
|
||||||
|
the script like this:
|
||||||
|
|
||||||
|
$ python modelviz.py [-h] [-d] <app_label> ... <app_label> > <filename>.dot
|
||||||
|
$ dot <filename>.dot -Tpng -o <filename>.png
|
||||||
|
|
||||||
|
options:
|
||||||
|
-h, --help
|
||||||
|
show this help message and exit.
|
||||||
|
|
||||||
|
-d, --disable_fields
|
||||||
|
don't show the class member fields.
|
||||||
|
"""
|
||||||
|
__version__ = "0.8"
|
||||||
|
__svnid__ = "$Id: modelviz.py 78 2007-07-15 19:04:47Z verbosus $"
|
||||||
|
__license__ = "Python"
|
||||||
|
__author__ = "Antonio Cavedoni <http://cavedoni.com/>"
|
||||||
|
__contributors__ = [
|
||||||
|
"Stefano J. Attardi <http://attardi.org/>",
|
||||||
|
"limodou <http://www.donews.net/limodou/>",
|
||||||
|
"Carlo C8E Miron",
|
||||||
|
"Andre Campos <cahenan@gmail.com>",
|
||||||
|
"Justin Findlay <jfindlay@gmail.com>",
|
||||||
|
]
|
||||||
|
|
||||||
|
import getopt, sys
|
||||||
|
|
||||||
|
from django.core.management import setup_environ
|
||||||
|
|
||||||
|
try:
|
||||||
|
import settings
|
||||||
|
except ImportError:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
setup_environ(settings)
|
||||||
|
|
||||||
|
from django.template import Template, Context
|
||||||
|
from django.db import models
|
||||||
|
from django.db.models import get_models
|
||||||
|
from django.db.models.fields.related import \
|
||||||
|
ForeignKey, OneToOneField, ManyToManyField
|
||||||
|
|
||||||
|
try:
|
||||||
|
from django.db.models.fields.generic import GenericRelation
|
||||||
|
except ImportError:
|
||||||
|
from django.contrib.contenttypes.generic import GenericRelation
|
||||||
|
|
||||||
|
head_template = """
|
||||||
|
digraph name {
|
||||||
|
fontname = "Helvetica"
|
||||||
|
fontsize = 8
|
||||||
|
|
||||||
|
node [
|
||||||
|
fontname = "Helvetica"
|
||||||
|
fontsize = 8
|
||||||
|
shape = "plaintext"
|
||||||
|
]
|
||||||
|
edge [
|
||||||
|
fontname = "Helvetica"
|
||||||
|
fontsize = 8
|
||||||
|
]
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
body_template = """
|
||||||
|
{% for model in models %}
|
||||||
|
{% for relation in model.relations %}
|
||||||
|
{{ relation.target }} [label=<
|
||||||
|
<TABLE BGCOLOR="palegoldenrod" BORDER="0" CELLBORDER="0" CELLSPACING="0">
|
||||||
|
<TR><TD COLSPAN="2" CELLPADDING="4" ALIGN="CENTER" BGCOLOR="olivedrab4"
|
||||||
|
><FONT FACE="Helvetica Bold" COLOR="white"
|
||||||
|
>{{ relation.target }}</FONT></TD></TR>
|
||||||
|
</TABLE>
|
||||||
|
>]
|
||||||
|
{{ model.name }} -> {{ relation.target }}
|
||||||
|
[label="{{ relation.name }}"] {{ relation.arrows }};
|
||||||
|
{% endfor %}
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
{% for model in models %}
|
||||||
|
{{ model.name }} [label=<
|
||||||
|
<TABLE BGCOLOR="palegoldenrod" BORDER="0" CELLBORDER="0" CELLSPACING="0">
|
||||||
|
<TR><TD COLSPAN="2" CELLPADDING="4" ALIGN="CENTER" BGCOLOR="olivedrab4"
|
||||||
|
><FONT FACE="Helvetica Bold" COLOR="white"
|
||||||
|
>{{ model.name }}</FONT></TD></TR>
|
||||||
|
|
||||||
|
{% if not disable_fields %}
|
||||||
|
{% for field in model.fields %}
|
||||||
|
<TR><TD ALIGN="LEFT" BORDER="0"
|
||||||
|
><FONT {% if field.blank %}COLOR="#7B7B7B" {% endif %}FACE="Helvetica Bold">{{ field.name }}</FONT
|
||||||
|
></TD>
|
||||||
|
<TD ALIGN="LEFT"
|
||||||
|
><FONT {% if field.blank %}COLOR="#7B7B7B" {% endif %}FACE="Helvetica Bold">{{ field.type }}</FONT
|
||||||
|
></TD></TR>
|
||||||
|
{% endfor %}
|
||||||
|
{% endif %}
|
||||||
|
</TABLE>
|
||||||
|
>]
|
||||||
|
{% endfor %}
|
||||||
|
"""
|
||||||
|
|
||||||
|
tail_template = """
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
|
||||||
|
def generate_dot(app_labels, **kwargs):
|
||||||
|
disable_fields = kwargs.get('disable_fields', False)
|
||||||
|
|
||||||
|
dot = head_template
|
||||||
|
|
||||||
|
for app_label in app_labels:
|
||||||
|
app = models.get_app(app_label)
|
||||||
|
graph = Context({
|
||||||
|
'name': '"%s"' % app.__name__,
|
||||||
|
'disable_fields': disable_fields,
|
||||||
|
'models': []
|
||||||
|
})
|
||||||
|
|
||||||
|
for appmodel in get_models(app):
|
||||||
|
model = {
|
||||||
|
'name': appmodel.__name__,
|
||||||
|
'fields': [],
|
||||||
|
'relations': []
|
||||||
|
}
|
||||||
|
|
||||||
|
# model attributes
|
||||||
|
def add_attributes():
|
||||||
|
model['fields'].append({
|
||||||
|
'name': field.name,
|
||||||
|
'type': type(field).__name__,
|
||||||
|
'blank': field.blank
|
||||||
|
})
|
||||||
|
|
||||||
|
for field in appmodel._meta.fields:
|
||||||
|
add_attributes()
|
||||||
|
|
||||||
|
if appmodel._meta.many_to_many:
|
||||||
|
for field in appmodel._meta.many_to_many:
|
||||||
|
add_attributes()
|
||||||
|
|
||||||
|
# relations
|
||||||
|
def add_relation(extras=""):
|
||||||
|
_rel = {
|
||||||
|
'target': field.rel.to.__name__,
|
||||||
|
'type': type(field).__name__,
|
||||||
|
'name': field.name,
|
||||||
|
'arrows': extras
|
||||||
|
}
|
||||||
|
if _rel not in model['relations']:
|
||||||
|
model['relations'].append(_rel)
|
||||||
|
|
||||||
|
for field in appmodel._meta.fields:
|
||||||
|
if isinstance(field, ForeignKey):
|
||||||
|
add_relation()
|
||||||
|
elif isinstance(field, OneToOneField):
|
||||||
|
add_relation("[arrowhead=none arrowtail=none]")
|
||||||
|
|
||||||
|
if appmodel._meta.many_to_many:
|
||||||
|
for field in appmodel._meta.many_to_many:
|
||||||
|
if isinstance(field, ManyToManyField):
|
||||||
|
add_relation("[arrowhead=normal arrowtail=normal]")
|
||||||
|
elif isinstance(field, GenericRelation):
|
||||||
|
add_relation(
|
||||||
|
'[style="dotted"] [arrowhead=normal arrowtail=normal]')
|
||||||
|
graph['models'].append(model)
|
||||||
|
|
||||||
|
t = Template(body_template)
|
||||||
|
dot += '\n' + t.render(graph)
|
||||||
|
|
||||||
|
dot += '\n' + tail_template
|
||||||
|
|
||||||
|
return dot
|
||||||
|
|
||||||
|
def main():
|
||||||
|
try:
|
||||||
|
opts, args = getopt.getopt(sys.argv[1:], "hd",
|
||||||
|
["help", "disable_fields"])
|
||||||
|
except getopt.GetoptError, error:
|
||||||
|
print __doc__
|
||||||
|
sys.exit(error)
|
||||||
|
else:
|
||||||
|
if not args:
|
||||||
|
print __doc__
|
||||||
|
sys.exit()
|
||||||
|
|
||||||
|
kwargs = {}
|
||||||
|
for opt, arg in opts:
|
||||||
|
if opt in ("-h", "--help"):
|
||||||
|
print __doc__
|
||||||
|
sys.exit()
|
||||||
|
if opt in ("-d", "--disable_fields"):
|
||||||
|
kwargs['disable_fields'] = True
|
||||||
|
print generate_dot(args, **kwargs)
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
@ -91,10 +91,11 @@ def EnterLogIntoDbase(date, place, title, text, trippeople, expedition, logtime_
|
|||||||
lookupAttribs={'date':date, 'title':title}
|
lookupAttribs={'date':date, 'title':title}
|
||||||
nonLookupAttribs={'place':place, 'text':text, 'author':author, 'expedition':expedition, 'cave':cave, 'slug':slugify(title)[:50]}
|
nonLookupAttribs={'place':place, 'text':text, 'author':author, 'expedition':expedition, 'cave':cave, 'slug':slugify(title)[:50]}
|
||||||
lbo, created=save_carefully(models.LogbookEntry, lookupAttribs, nonLookupAttribs)
|
lbo, created=save_carefully(models.LogbookEntry, lookupAttribs, nonLookupAttribs)
|
||||||
|
expeditiondate = expedition.get_expedition_date(date)
|
||||||
|
|
||||||
for tripperson, time_underground in trippersons:
|
for tripperson, time_underground in trippersons:
|
||||||
lookupAttribs={'person_expedition':tripperson, 'logbook_entry':lbo}
|
lookupAttribs={'person_expedition':tripperson, 'logbook_entry':lbo}
|
||||||
nonLookupAttribs={'time_underground':time_underground, 'date':date, 'is_logbook_entry_author':(tripperson == author)}
|
nonLookupAttribs={'time_underground':time_underground, 'date':date, 'expeditiondate':expeditiondate, 'is_logbook_entry_author':(tripperson == author)}
|
||||||
#print nonLookupAttribs
|
#print nonLookupAttribs
|
||||||
save_carefully(models.PersonTrip, lookupAttribs, nonLookupAttribs)
|
save_carefully(models.PersonTrip, lookupAttribs, nonLookupAttribs)
|
||||||
|
|
||||||
@ -186,7 +187,7 @@ def Parseloghtml01(year, expedition, txt):
|
|||||||
tripid = mtripid and mtripid.group(1) or ""
|
tripid = mtripid and mtripid.group(1) or ""
|
||||||
tripheader = re.sub("</?(?:[ab]|span)[^>]*>", "", tripheader)
|
tripheader = re.sub("</?(?:[ab]|span)[^>]*>", "", tripheader)
|
||||||
|
|
||||||
#print [tripheader]
|
#print " ", [tripheader]
|
||||||
#continue
|
#continue
|
||||||
|
|
||||||
tripdate, triptitle, trippeople = tripheader.split("|")
|
tripdate, triptitle, trippeople = tripheader.split("|")
|
||||||
@ -270,7 +271,7 @@ yearlinks = [
|
|||||||
("1994", "1994/log.htm", Parseloghtml01),
|
("1994", "1994/log.htm", Parseloghtml01),
|
||||||
("1993", "1993/log.htm", Parseloghtml01),
|
("1993", "1993/log.htm", Parseloghtml01),
|
||||||
("1992", "1992/log.htm", Parseloghtml01),
|
("1992", "1992/log.htm", Parseloghtml01),
|
||||||
#("1991", "1991/log.htm", Parseloghtml01),
|
("1991", "1991/log.htm", Parseloghtml01),
|
||||||
]
|
]
|
||||||
|
|
||||||
def SetDatesFromLogbookEntries(expedition):
|
def SetDatesFromLogbookEntries(expedition):
|
||||||
|
@ -123,8 +123,9 @@ def RecursiveLoad(survexblock, survexfile, fin, textlines):
|
|||||||
survexblock.date = re.sub("\.", "-", line)
|
survexblock.date = re.sub("\.", "-", line)
|
||||||
expeditions = models.Expedition.objects.filter(year=line[:4])
|
expeditions = models.Expedition.objects.filter(year=line[:4])
|
||||||
if expeditions:
|
if expeditions:
|
||||||
|
assert len(expeditions) == 1
|
||||||
survexblock.expedition = expeditions[0]
|
survexblock.expedition = expeditions[0]
|
||||||
|
survexblock.expeditiondate = survexblock.expedition.get_expedition_day(survexblock.date)
|
||||||
elif re.match("team$(?i)", cmd):
|
elif re.match("team$(?i)", cmd):
|
||||||
mteammember = re.match("(Insts|Notes|Tape|Dog|Useless|Pics|Helper|Disto|Consultant)\s+(.*)$(?i)", line)
|
mteammember = re.match("(Insts|Notes|Tape|Dog|Useless|Pics|Helper|Disto|Consultant)\s+(.*)$(?i)", line)
|
||||||
if mteammember:
|
if mteammember:
|
||||||
|
@ -33,6 +33,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="toolbarlinks">
|
<div class="toolbarlinks">
|
||||||
<a href="{% url survexcaveslist %}">All Cave Survex</a> |
|
<a href="{% url survexcaveslist %}">All Cave Survex</a> |
|
||||||
|
<a href="{% url surveyscansfolders %}">All scans</a> |
|
||||||
<a href="{% url survexcavessingle 161 %}">161</a> |
|
<a href="{% url survexcavessingle 161 %}">161</a> |
|
||||||
<a href="{% url survexcavessingle 204 %}">204</a> |
|
<a href="{% url survexcavessingle 204 %}">204</a> |
|
||||||
<a href="{% url survexcavessingle 258 %}">258</a> |
|
<a href="{% url survexcavessingle 258 %}">258</a> |
|
||||||
|
@ -6,21 +6,20 @@
|
|||||||
|
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<h2>{{personexpedition.person}}: {{personexpedition.expedition}} ({{personexpedition.date_from}} - {{personexpedition.date_to}})</h2>
|
<h1>
|
||||||
|
<a href="{{personexpedition.person.get_absolute_url}}">{{personexpedition.person}}</a> :
|
||||||
|
<a href="{{personexpedition.expedition.get_absolute_url}}">{{personexpedition.expedition}}</a>
|
||||||
|
</h1>
|
||||||
|
|
||||||
<h3>{{message}}</h3>
|
<p>{{message}}</p>
|
||||||
|
|
||||||
<p><b><a href="{{ personexpedition.expedition.get_absolute_url }}">Main page for expedition: {{personexpedition.expedition}}</a></b></p>
|
<p><b>Other years:</b>
|
||||||
<p><b><a href="{{ personexpedition.person.get_absolute_url }}">Main page for person: {{personexpedition.person}}</a></b></p>
|
|
||||||
|
|
||||||
<p>List of other expos by this person</p>
|
|
||||||
<p>
|
|
||||||
{% for otherpersonexpedition in personexpedition.person.personexpedition_set.all %}
|
{% for otherpersonexpedition in personexpedition.person.personexpedition_set.all %}
|
||||||
{% ifequal otherpersonexpedition personexpedition %}
|
{% ifequal otherpersonexpedition personexpedition %}
|
||||||
| <b>{{otherpersonexpedition.expedition.year}}</b>
|
| <b>{{otherpersonexpedition.expedition.year}}</b>
|
||||||
{% else %}
|
{% else %}
|
||||||
| {{ otherpersonexpedition|link }}
|
| <a href="{{otherpersonexpedition.get_absolute_url}}">{{ otherpersonexpedition.expedition.year }}</a>
|
||||||
{% endifequal %}
|
{% endifequal %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
@ -40,8 +39,12 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% if persondate.2 %}
|
{% if persondate.2 %}
|
||||||
<td class="survexblock"><a href="{% url survexblock persondate.2.0 %}">{{persondate.2.0}}</a></td>
|
<td class="survexblock"><a href="{% url svx persondate.2.survexfile.path %}">{{persondate.2}}</a></td>
|
||||||
<td class="roles">{{persondate.2.1}}</td>
|
<td class="roles">
|
||||||
|
{% for survexpersonrole in persondate.2.survexpersonrole_set.all %}
|
||||||
|
{{survexpersonrole.nrole}}
|
||||||
|
{% endfor %}
|
||||||
|
</td>
|
||||||
{% else %}
|
{% else %}
|
||||||
<td colspan="2"> </td>
|
<td colspan="2"> </td>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
Loading…
Reference in New Issue
Block a user