parent
72847d4d71
commit
cdcf6abcb5
11 changed files with 588 additions and 3 deletions
@ -0,0 +1 @@ |
|||||||
|
|
||||||
@ -0,0 +1,136 @@ |
|||||||
|
# -*- coding: utf-8 -*- |
||||||
|
from django import forms |
||||||
|
from django.conf import settings |
||||||
|
|
||||||
|
languages = [code for code in settings.LANGUAGES] |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class ImportEventForm(forms.Form): |
||||||
|
excel_file = forms.FileField(label='Выберите файл') |
||||||
|
event = forms.ChoiceField(label='Выберите тип события', choices=[('exposition', 'Выставка'), |
||||||
|
('conference', 'Конференция'), |
||||||
|
('seminar', 'Семинар'), |
||||||
|
('webinar', 'Вебинар')]) |
||||||
|
language = forms.ChoiceField(label='Выберите язык', choices=languages) |
||||||
|
|
||||||
|
|
||||||
|
from theme.models import Theme |
||||||
|
from country.models import Country |
||||||
|
from django.db.models.loading import get_model |
||||||
|
import StringIO |
||||||
|
from functions.translate import get_all_fields, get_all_verbose_names |
||||||
|
|
||||||
|
|
||||||
|
class ExportEventForm(forms.Form): |
||||||
|
event = forms.ChoiceField(label='Выберите тип события', choices=[('exposition.Exposition', 'Выставка'), |
||||||
|
('conference.Conference', 'Конференция'), |
||||||
|
('seminar.Seminar', 'Семинар'), |
||||||
|
('webinar.Webinar', 'Вебинар')]) |
||||||
|
language = forms.ChoiceField(label='Выберите язык', choices=languages) |
||||||
|
date_from = forms.DateField(label='С') |
||||||
|
date_to = forms.DateField(label='До') |
||||||
|
theme = forms.ModelMultipleChoiceField(label='Направление', queryset=Theme.objects.all(), required=False) |
||||||
|
country = forms.ModelMultipleChoiceField(label='Страны', queryset=Country.objects.all(), required=False) |
||||||
|
|
||||||
|
def generate_dicts(self): |
||||||
|
data = self.cleaned_data |
||||||
|
event = data['event'] |
||||||
|
language = data['language'] |
||||||
|
date_from = data['date_from'] |
||||||
|
date_to = data['date_to'] |
||||||
|
theme = data['theme'] |
||||||
|
country = data['country'] |
||||||
|
# get model of event |
||||||
|
model = get_model(event.split('.')[0], event.split('.')[1]) |
||||||
|
# |
||||||
|
objects = model.objects.language(language).filter(data_begin__range=[date_from, date_to], |
||||||
|
country__in=country, |
||||||
|
theme__in=theme |
||||||
|
).distinct() |
||||||
|
|
||||||
|
if not objects: |
||||||
|
return None |
||||||
|
# get fields |
||||||
|
# in list exclude fields |
||||||
|
fields = get_all_fields(objects[0],['organiser', 'tag', 'descriptions', 'keywords', 'title', 'theme', |
||||||
|
'users', 'company', 'translations', 'business_program', 'created', |
||||||
|
'modified']) |
||||||
|
# readable names |
||||||
|
names = get_all_verbose_names(objects[0], fields) |
||||||
|
|
||||||
|
objects_list = [] |
||||||
|
|
||||||
|
for object in objects: |
||||||
|
obj_dict = {} |
||||||
|
# generate dict with field values |
||||||
|
for field in fields: |
||||||
|
obj_dict = {'name': field, 'value': getattr(object, field), |
||||||
|
'verbose_name': names[field]} |
||||||
|
|
||||||
|
#obj_dict[field] = {'value': getattr(object, field), 'verbose_name': names[field]} |
||||||
|
|
||||||
|
objects_list.append(obj_dict) |
||||||
|
|
||||||
|
return objects_list |
||||||
|
|
||||||
|
""" |
||||||
|
def generate_dicts(self): |
||||||
|
data = self.cleaned_data |
||||||
|
event = data['event'] |
||||||
|
language = data['language'] |
||||||
|
date_from = data['date_from'] |
||||||
|
date_to = data['date_to'] |
||||||
|
theme = data['theme'] |
||||||
|
country = data['country'] |
||||||
|
# get model of event |
||||||
|
model = get_model(event.split('.')[0], event.split('.')[1]) |
||||||
|
# |
||||||
|
objects = model.objects.language(language).filter(data_begin__range=[date_from, date_to], |
||||||
|
country__in=country, |
||||||
|
theme__in=theme |
||||||
|
).distinct() |
||||||
|
|
||||||
|
if not objects: |
||||||
|
return None |
||||||
|
# get fields |
||||||
|
# in list exclude fields |
||||||
|
fields = get_all_fields(objects[0],['organiser', 'tag', 'descriptions', 'keywords', 'title', 'theme', |
||||||
|
'users', 'company', 'translations', 'business_program', 'created', |
||||||
|
'modified']) |
||||||
|
# readable names |
||||||
|
names = get_all_verbose_names(objects[0], fields) |
||||||
|
|
||||||
|
objects_list = [] |
||||||
|
|
||||||
|
for object in objects: |
||||||
|
obj_dict = {} |
||||||
|
# generate dict with field values |
||||||
|
for field in fields: |
||||||
|
obj_dict[field] = {'value': getattr(object, field), 'verbose_name': names[field]} |
||||||
|
|
||||||
|
objects_list.append(obj_dict) |
||||||
|
|
||||||
|
return objects_list |
||||||
|
""" |
||||||
|
|
||||||
|
def clean_theme(self): |
||||||
|
""" |
||||||
|
Set all themes if no theme selected |
||||||
|
""" |
||||||
|
theme = self.cleaned_data.get('theme') |
||||||
|
if not theme: |
||||||
|
theme = Theme.objects.all() |
||||||
|
|
||||||
|
return theme |
||||||
|
|
||||||
|
|
||||||
|
def clean_country(self): |
||||||
|
""" |
||||||
|
Set all countries if no country selected |
||||||
|
""" |
||||||
|
country = self.cleaned_data.get('country') |
||||||
|
if not country: |
||||||
|
country = Country.objects.all() |
||||||
|
|
||||||
|
return country |
||||||
@ -0,0 +1,98 @@ |
|||||||
|
# -*- coding: utf-8 -*- |
||||||
|
import xlwt |
||||||
|
import datetime |
||||||
|
|
||||||
|
def get_bool(value): |
||||||
|
if value: |
||||||
|
return 1 |
||||||
|
return 0 |
||||||
|
|
||||||
|
def get_int(value): |
||||||
|
if not value: |
||||||
|
return '' |
||||||
|
return value |
||||||
|
|
||||||
|
def get_audience(value): |
||||||
|
if not value: |
||||||
|
return 'Не выбрано' |
||||||
|
elif value == 'experts': |
||||||
|
return 'Специалисты' |
||||||
|
elif value == 'experts and consumers': |
||||||
|
return 'Специалисты и потребители' |
||||||
|
elif value == 'general public': |
||||||
|
return 'Широкая публика' |
||||||
|
|
||||||
|
field_settings = [ |
||||||
|
{'name': 'id', 'verbose_name': 'id', 'type': get_int, 'width':1500}, |
||||||
|
{'name': 'url', 'verbose_name': 'url', 'type': str}, |
||||||
|
{'name': 'name', 'verbose_name': 'Имя', 'type': str, 'width':8000,}, |
||||||
|
{'name': 'data_begin', 'verbose_name': 'Дата начала', 'type': str}, |
||||||
|
{'name': 'data_end', 'verbose_name': 'Дата окончания', 'type': str}, |
||||||
|
{'name': 'main_title', 'verbose_name': 'Краткое описание', 'type': str}, |
||||||
|
{'name': 'description', 'verbose_name': 'Описание', 'type': str}, |
||||||
|
{'name': 'audience', 'verbose_name': 'Аудитория', type: get_audience}, |
||||||
|
{'name': 'country', 'verbose_name': 'Страна', 'type': str}, |
||||||
|
{'name': 'city', 'verbose_name': 'Город', 'type': str}, |
||||||
|
{'name': 'periodic', 'verbose_name': 'Периодичность', 'type': str}, |
||||||
|
{'name': 'web_page', 'verbose_name': 'Веб страница', 'type': str}, |
||||||
|
{'name': 'time', 'verbose_name': 'Время проведения', 'type': str}, |
||||||
|
{'name': 'products', 'verbose_name': 'Экспонируемые продукты', 'type': str}, |
||||||
|
{'name': 'foundation_year', 'verbose_name': 'Год основания', 'type': get_int}, |
||||||
|
{'name': 'tax', 'verbose_name': 'Налог включен', 'type': get_bool, 'width':1000}, |
||||||
|
{'name': 'currency', 'verbose_name': 'Валюта', 'type': str}, |
||||||
|
{'name': 'max_price', 'verbose_name': 'Максимальная цена', 'type': get_int}, |
||||||
|
{'name': 'min_price', 'verbose_name': 'Минимальная цена', 'type': get_int}, |
||||||
|
{'name': 'registration_payment', 'verbose_name': 'Регистрационный взнос', 'type': get_int}, |
||||||
|
{'name': 'min_closed_area', 'verbose_name': 'Минимальная цена закрытой НЕ оборудованной площади', 'type': get_int}, |
||||||
|
{'name': 'max_closed_area', 'verbose_name': 'Максимальная цена закрытой НЕ оборудованной площади', 'type': get_int}, |
||||||
|
{'name': 'min_closed_equipped_area', 'verbose_name': 'Минимальная цена закрытой оборудованной площади ', 'type': get_int}, |
||||||
|
{'name': 'max_closed_equipped_area', 'verbose_name': 'Максимальная цена закрытой оборудованной площади', 'type': get_int}, |
||||||
|
{'name': 'min_open_area', 'verbose_name': 'Минимальная цена закрытой площади', 'type': get_int}, |
||||||
|
{'name': 'max_open_area', 'verbose_name': 'Максимальная цена открытой площади', 'type': get_int}, |
||||||
|
{'name': 'min_area', 'verbose_name': 'Минимальная площадь', 'type': get_int}, |
||||||
|
{'name': 'max_area', 'verbose_name': 'Максимальная площадь', 'type': get_int}, |
||||||
|
{'name': 'is_published', 'verbose_name': 'Опубликована', 'type': get_bool, 'width':1000}, |
||||||
|
{'name': 'canceled_by_administrator', 'verbose_name': 'Отменена администратором', 'type': get_bool, 'width':1000} |
||||||
|
] |
||||||
|
|
||||||
|
|
||||||
|
def get_cell(field_name, value): |
||||||
|
return {'tax': get_bool(value), 'foundation_year': get_int(value), 'max_closed_area': get_int(value), |
||||||
|
'min_closed_equipped_area': get_int(value), 'registration_payment': get_int(value), |
||||||
|
'max_closed_equipped_area': get_int(value), 'max_open_area': get_int(value), 'min_closed_area': get_int(value), |
||||||
|
'min_area': get_int(value), 'canceled_by_administrator': get_bool(value), 'is_published': get_bool(value), |
||||||
|
'min_open_area': get_int(value), 'audience': get_audience(value) |
||||||
|
}.get(field_name, str(value)) |
||||||
|
|
||||||
|
|
||||||
|
#--------------------------------------- |
||||||
|
|
||||||
|
#--------------------------------------- |
||||||
|
|
||||||
|
def get_cell_style(field_name): |
||||||
|
font = xlwt.Font() |
||||||
|
# Create the Font |
||||||
|
font.name = 'Times New Roman' |
||||||
|
default_style = xlwt.XFStyle() |
||||||
|
# Create the Style |
||||||
|
default_style.font = font |
||||||
|
return { |
||||||
|
|
||||||
|
}.get(field_name, default_style) |
||||||
|
|
||||||
|
#------------------------------------------ |
||||||
|
|
||||||
|
#------------------------------------------ |
||||||
|
sorted_names = [u'id', 'name', 'data_begin', 'data_end', 'main_title', 'description', 'country', 'city'] |
||||||
|
cols_width = {'id': 1500, 'name':8000} |
||||||
|
|
||||||
|
|
||||||
|
#field_setting.get('width', 20) |
||||||
|
|
||||||
|
def sort_by_names(val): |
||||||
|
try: |
||||||
|
# put element on the index of sorted names |
||||||
|
return sorted_names.index(val) |
||||||
|
except ValueError: |
||||||
|
# put element on the end |
||||||
|
return len(sorted_names) |
||||||
@ -0,0 +1,175 @@ |
|||||||
|
# -*- coding: utf-8 -*- |
||||||
|
from django.core.context_processors import csrf |
||||||
|
from django.shortcuts import render_to_response |
||||||
|
from django.http import HttpResponseRedirect, HttpResponse |
||||||
|
from django.contrib.auth.decorators import login_required |
||||||
|
# |
||||||
|
import xlwt |
||||||
|
import xlrd |
||||||
|
import tempfile |
||||||
|
# |
||||||
|
from custom_forms import ImportEventForm, ExportEventForm |
||||||
|
|
||||||
|
from excel_settings import sort_by_names, get_cell_style, get_cell |
||||||
|
from excel_settings import cols_width |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@login_required |
||||||
|
def import_event(request): |
||||||
|
if request.POST: |
||||||
|
form = ImportEventForm(request.POST, request.FILES) |
||||||
|
temp_file = tempfile.TemporaryFile() |
||||||
|
import_file = request.FILES.get(request.FILES.keys()[0]) |
||||||
|
book = xlrd.open_workbook(file_contents=import_file) |
||||||
|
sheet = book.sheet_by_index(0) |
||||||
|
row_list = [sheet.row_values(row_number) for row_number in range(sheet.nrows)] |
||||||
|
|
||||||
|
return HttpResponse(row_list[0]) |
||||||
|
|
||||||
|
else: |
||||||
|
form = ImportEventForm() |
||||||
|
|
||||||
|
args = {} |
||||||
|
args.update(csrf(request)) |
||||||
|
args['form'] = form |
||||||
|
return render_to_response('import_event.html', args) |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def xls_to_response(xls, fname): |
||||||
|
response = HttpResponse(mimetype="application/ms-excel") |
||||||
|
response['Content-Disposition'] = 'attachment; filename=%s' % fname |
||||||
|
xls.save(response) |
||||||
|
return response |
||||||
|
|
||||||
|
|
||||||
|
import datetime |
||||||
|
|
||||||
|
|
||||||
|
from excel_settings import field_settings |
||||||
|
|
||||||
|
from django.db.models.loading import get_model |
||||||
|
|
||||||
|
def export_event(request): |
||||||
|
if request.POST: |
||||||
|
form = ExportEventForm(request.POST) |
||||||
|
if form.is_valid(): |
||||||
|
|
||||||
|
data = form.cleaned_data |
||||||
|
# get model |
||||||
|
model = get_model(data['event'].split('.')[0], data['event'].split('.')[1]) |
||||||
|
# get objects |
||||||
|
objects = model.objects.language(data['language']).filter(data_begin__range=[data['date_from'], data['date_to']], |
||||||
|
country__in=data['country'], |
||||||
|
theme__in=data['theme'] |
||||||
|
).distinct() |
||||||
|
|
||||||
|
if not objects: |
||||||
|
# not found any objects |
||||||
|
message = 'По даному запросу объектов не найдено' |
||||||
|
args = {} |
||||||
|
args.update(csrf(request)) |
||||||
|
args['message'] = message |
||||||
|
args['form'] = form |
||||||
|
return render_to_response('export_event.html', args) |
||||||
|
|
||||||
|
workbook = xlwt.Workbook(encoding = 'utf8') |
||||||
|
# new tab |
||||||
|
worksheet = workbook.add_sheet('My Worksheet') |
||||||
|
|
||||||
|
# Create the Font for first rows |
||||||
|
font = xlwt.Font() |
||||||
|
font.name = 'Times New Roman' |
||||||
|
font.bold = True |
||||||
|
style = xlwt.XFStyle() |
||||||
|
# Create the Style |
||||||
|
style.font = font |
||||||
|
|
||||||
|
for row, object in enumerate(objects): |
||||||
|
for col, field in enumerate(field_settings): |
||||||
|
try: |
||||||
|
value = getattr(object, field['name']) |
||||||
|
except AttributeError: |
||||||
|
continue |
||||||
|
if row == 0: |
||||||
|
# first iteration. set names. set columns width |
||||||
|
worksheet.write(0, col, field.get('verbose_name', 'default'), style) |
||||||
|
worksheet.write(1, col, field.get('name'), style) |
||||||
|
worksheet.col(col).width = field.get('width', 3333) |
||||||
|
|
||||||
|
worksheet.write(row+2, col, field.get('type', str)(value)) |
||||||
|
|
||||||
|
return xls_to_response(workbook, 'My Worksheet.xls') |
||||||
|
else: |
||||||
|
form = ExportEventForm() |
||||||
|
|
||||||
|
|
||||||
|
args = {} |
||||||
|
args.update(csrf(request)) |
||||||
|
|
||||||
|
args['form'] = form |
||||||
|
|
||||||
|
return render_to_response('export_event.html', args) |
||||||
|
""" |
||||||
|
def export_event(request): |
||||||
|
if request.POST: |
||||||
|
form = ExportEventForm(request.POST) |
||||||
|
|
||||||
|
if form.is_valid(): |
||||||
|
# dict of objects |
||||||
|
objects = form.generate_dicts() |
||||||
|
return HttpResponse(str(objects)) |
||||||
|
|
||||||
|
if not objects: |
||||||
|
# empty dict |
||||||
|
message = 'По даному запросу объектов не найдено' |
||||||
|
args = {} |
||||||
|
args.update(csrf(request)) |
||||||
|
args['message'] = message |
||||||
|
args['form'] = form |
||||||
|
return render_to_response('export_event.html', args) |
||||||
|
|
||||||
|
workbook = xlwt.Workbook(encoding = 'utf8') |
||||||
|
# new tab |
||||||
|
worksheet = workbook.add_sheet('My Worksheet') |
||||||
|
|
||||||
|
# Create the Font |
||||||
|
font = xlwt.Font() |
||||||
|
font.name = 'Times New Roman' |
||||||
|
font.bold = True |
||||||
|
style = xlwt.XFStyle() |
||||||
|
# Create the Style |
||||||
|
style.font = font |
||||||
|
|
||||||
|
# get names of fields sorted like in sorted_names list |
||||||
|
fields = sorted(objects[0].keys(), key=sort_by_names) |
||||||
|
|
||||||
|
# generate first row with verbose names |
||||||
|
for i, field in enumerate(fields): |
||||||
|
worksheet.write(0, i, objects[0][field]['verbose_name'], style) |
||||||
|
# generate second row and set columns width |
||||||
|
for i, field in enumerate(fields): |
||||||
|
worksheet.write(1, i,field, style) |
||||||
|
if field in cols_width: |
||||||
|
worksheet.col(i).width = cols_width.get(field, 3333) |
||||||
|
# fill row with objects |
||||||
|
for row, object in enumerate(objects): |
||||||
|
for key, value in object.iteritems(): |
||||||
|
# current row |
||||||
|
col = fields.index(key) |
||||||
|
# begins from third row |
||||||
|
# get cell formats value (True -> 1, None -> '', ...) |
||||||
|
worksheet.write(row+2, col, get_cell(key, value['value']), get_cell_style(key)) |
||||||
|
|
||||||
|
return xls_to_response(workbook, 'My Worksheet.xls') |
||||||
|
else: |
||||||
|
form = ExportEventForm() |
||||||
|
|
||||||
|
args = {} |
||||||
|
args.update(csrf(request)) |
||||||
|
|
||||||
|
args['form'] = form |
||||||
|
|
||||||
|
return render_to_response('export_event.html', args) |
||||||
|
""" |
||||||
@ -0,0 +1,92 @@ |
|||||||
|
{% extends 'base.html' %} |
||||||
|
{% load static %} |
||||||
|
|
||||||
|
{% block scripts %} |
||||||
|
{# selects #} |
||||||
|
<link href="{% static 'js/select/select2.css' %}" rel="stylesheet"/> |
||||||
|
<script src="{% static 'js/select/select2.js' %}"></script> |
||||||
|
<script src="{% static 'custom_js/make_select.js' %}"></script> |
||||||
|
{# datetimepicker #} |
||||||
|
<link href="{% static 'js/datetimepicker/css/datetimepicker.css' %}" rel="stylesheet"/> |
||||||
|
<script src="{% static 'js/datetimepicker/js/bootstrap-datetimepicker.js' %}"></script> |
||||||
|
<script type="text/javascript"> |
||||||
|
$(document).ready(function(){ |
||||||
|
$('#id_date_from').datetimepicker({ |
||||||
|
todayHighlight: true, |
||||||
|
format : 'dd.mm.yyyy', |
||||||
|
minView:2 |
||||||
|
}); |
||||||
|
$('#id_date_to').datetimepicker({ |
||||||
|
todayHighlight: true, |
||||||
|
format : 'dd.mm.yyyy', |
||||||
|
minView:2 |
||||||
|
}); |
||||||
|
}); |
||||||
|
</script> |
||||||
|
{% endblock %} |
||||||
|
|
||||||
|
{% block body %} |
||||||
|
<form method="post" class="form-horizontal" enctype="multipart/form-data"> {% csrf_token %} |
||||||
|
{# event #} |
||||||
|
<div class="control-group {% if form.event.errors %}error{% endif %}"> |
||||||
|
<label class="control-label">{{ form.event.label }}:</label> |
||||||
|
<div class="controls"> |
||||||
|
{{ form.event }} |
||||||
|
<span class="help-inline">{{ form.event.errors }}</span> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
{# language #} |
||||||
|
<div class="control-group {% if form.language.errors %}error{% endif %}"> |
||||||
|
<label class="control-label">{{ form.language.label }}:</label> |
||||||
|
<div class="controls"> |
||||||
|
{{ form.language }} |
||||||
|
<span class="help-inline">{{ form.language.errors }}</span> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
{# date_from #} |
||||||
|
<div class="control-group {% if form.date_from.errors %}error{% endif %}"> |
||||||
|
<label class="control-label">{{ form.date_from.label }}:</label> |
||||||
|
<div class="controls"> |
||||||
|
{{ form.date_from }} |
||||||
|
<span class="help-inline">{{ form.date_from.errors }}</span> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
{# date_to #} |
||||||
|
<div class="control-group {% if form.date_to.errors %}error{% endif %}"> |
||||||
|
<label class="control-label">{{ form.date_to.label }}:</label> |
||||||
|
<div class="controls"> |
||||||
|
{{ form.date_to }} |
||||||
|
<span class="help-inline">{{ form.date_to.errors }}</span> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
{# theme #} |
||||||
|
<div class="control-group {% if form.theme.errors %}error{% endif %}"> |
||||||
|
<label class="control-label">{{ form.theme.label }}:</label> |
||||||
|
<div class="controls"> |
||||||
|
{{ form.theme }} |
||||||
|
<span class="help-inline">{{ form.theme.errors }}</span> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
{# country #} |
||||||
|
<div class="control-group {% if form.country.errors %}error{% endif %}"> |
||||||
|
<label class="control-label">{{ form.country.label }}:</label> |
||||||
|
<div class="controls"> |
||||||
|
{{ form.country }} |
||||||
|
<span class="help-inline">{{ form.country.errors }}</span> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
|
||||||
|
<div class="controls"> |
||||||
|
<input class="btn btn-large btn-primary" type="submit" value="Экспорт"> |
||||||
|
<input class="btn btn-large" type="reset" value="Отмена"> |
||||||
|
</div> |
||||||
|
|
||||||
|
|
||||||
|
</form> |
||||||
|
{% if message %} |
||||||
|
<div class="alert alert-error"> |
||||||
|
{{ message }} |
||||||
|
</div> |
||||||
|
{% endif %} |
||||||
|
|
||||||
|
{% endblock %} |
||||||
@ -0,0 +1,42 @@ |
|||||||
|
{% extends 'base.html' %} |
||||||
|
{% load static %} |
||||||
|
|
||||||
|
{% block scripts %} |
||||||
|
{% endblock %} |
||||||
|
|
||||||
|
{% block body %} |
||||||
|
<form method="post" class="form-horizontal" enctype="multipart/form-data"> {% csrf_token %} |
||||||
|
|
||||||
|
{# excel_file #} |
||||||
|
<div class="control-group {% if form.excel_file.errors %}error{% endif %}"> |
||||||
|
<label class="control-label">{{ form.excel_file.label }}:</label> |
||||||
|
<div class="controls"> |
||||||
|
{{ form.excel_file }} |
||||||
|
<span class="help-inline">{{ form.excel_file.errors }}</span> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
{# event #} |
||||||
|
<div class="control-group {% if form.event.errors %}error{% endif %}"> |
||||||
|
<label class="control-label">{{ form.event.label }}:</label> |
||||||
|
<div class="controls"> |
||||||
|
{{ form.event }} |
||||||
|
<span class="help-inline">{{ form.event.errors }}</span> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
{# language #} |
||||||
|
<div class="control-group {% if form.language.errors %}error{% endif %}"> |
||||||
|
<label class="control-label">{{ form.language.label }}:</label> |
||||||
|
<div class="controls"> |
||||||
|
{{ form.language }} |
||||||
|
<span class="help-inline">{{ form.language.errors }}</span> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
|
||||||
|
|
||||||
|
<div class="controls"> |
||||||
|
<input class="btn btn-large btn-primary" type="submit" value="Импорт"> |
||||||
|
<input class="btn btn-large" type="reset" value="Отмена"> |
||||||
|
</div> |
||||||
|
|
||||||
|
</form> |
||||||
|
{% endblock %} |
||||||
Loading…
Reference in new issue