Answer the question
In order to leave comments, you need to log in
How to double filter in Flask-Admin?
import os
import subprocess
from flask_admin.contrib.sqla import ModelView
from app.admin.helpers.files_validation_helper import ImageRequired
from app.admin.mixins.models_views import BaseModelView
from app.admin.helpers.widgets_helper import CustomTimeField
from app.admin.helpers.widgets_helper import MultipleSelect2Field
from app.admin.helpers.week_days import weekly_days_numbers, WEEKLY_EVENT_DAYS
from app.admin.helpers.widgets_helper import FileUploadFieldOverride
from app.helpers.file_ops import get_uuid_hash
from app.helpers.file_ops import normalize_filename
from app.helpers.file_ops import write_file
from app.models.weekly_event import WeeklyEventDays, WeeklyEvent
from app.models.schedule import Schedule
from app.models.gym import Gym
from app.models.gym_city import GymCity
from app.models.user import User
from config.environments.settings import AVATARS_UPLOAD_PATH
import datetime
from app.admin.helpers import time_plus
from wtforms.validators import ValidationError
from db.sessions import Session
from sqlalchemy import or_
from flask_admin.contrib.sqla.filters import BaseSQLAFilter
from flask import Markup
class FilterByUser(BaseSQLAFilter):
def apply(self, query, value, alias=None):
return query.join(User, WeeklyEvent.user_id == User.id, aliased=True) \
.filter(User.name.in_(value.split(',')))
def operation(self):
return u'выбрать'
def get_options(self, view):
return [(p.name, p.name) for p in Session.query(User).order_by(User.id)]
class FilterByCity(BaseSQLAFilter):
def apply(self, query, value, alias=None):
return query.join(Gym, WeeklyEvent.gym_id == Gym.id) \
.join(GymCity, Gym.gym_city_id == GymCity.id) \
.filter(GymCity.name.in_(value.split(',')))
def operation(self):
return u'выбрать'
def get_options(self, view):
return [(p.name, p.name) for p in Session.query(GymCity).order_by(GymCity.id)]
class FilterByGym(BaseSQLAFilter):
def apply(self, query, value, alias=None):
return query.join(Gym, WeeklyEvent.gym_id == Gym.id, aliased=True) \
.filter(Gym.name.in_(value.split(',')))
def operation(self):
return u'выбрать'
def get_options(self, view):
return [(p.name, p.name) for p in Session.query(Gym).order_by(Gym.id)]
class WeeklyEventModelView(BaseModelView, ModelView):
form_overrides = dict(
weekly_event_start_time=CustomTimeField,
weekly_event_end_time=CustomTimeField,
weekly_event_days=MultipleSelect2Field,
image_url=FileUploadFieldOverride,
)
form_args = dict(
image_url=dict(validators=[ImageRequired()])
)
column_list = (
'title',
'city',
'gym',
'weekly_event_start_time',
'weekly_event_end_time',
'weekly_event_days',
'user',
)
column_default_sort = ('id', True)
form_excluded_columns = ('record_modified', 'record_created')
can_delete = True
can_create = True
page_size = 50
column_filters = ('title', 'record_created', )
column_labels = {
'title': 'Заголовок',
'gym': 'Зал',
'city': 'Город',
'weekly_event_start_date': 'Начало события',
'weekly_event_stop_date': 'Конец события',
'weekly_event_days': 'Дни по которым проходит событие',
'weekly_event_start_time': 'Время начала события',
'weekly_event_end_time': 'Время завершения события',
'description': 'Описание',
'user': 'Пользователь',
#'image_url': 'Изображение',
}
form_columns = [
'title',
'gym',
'user',
'weekly_event_start_date',
'weekly_event_stop_date',
'weekly_event_days',
'weekly_event_start_time',
'weekly_event_end_time',
'description',
#'image_url',
]
form_args = dict(
weekly_event_start_time=dict(default_format='%H:%M', formats=('%H:%M', '%H:%M')),
weekly_event_end_time=dict(default_format='%H:%M', formats=('%H:%M', '%H:%M')),
weekly_event_days=dict(render_kw=dict(multiple="multiple"), choices=[(v, v) for v in WEEKLY_EVENT_DAYS])
)
column_formatters = dict(
weekly_event_start_time=lambda v, c, m, p: m.clock_start.strftime('%H:%M'),
weekly_event_end_time=lambda v, c, m, p: m.clock_end.strftime('%H:%M')
)
form_widget_args = {
form_column: {'autocomplete': "off"}
for form_column in form_columns
}
column_filters = [
FilterByCity(column=None, name='Фильтр по городу'),
FilterByGym(column=None, name='Фильтр по залу'),
FilterByUser(column=None, name='Фильтр по пользователю'),
]
def get_city(view, context, model, name):
l = model.gym.gym_city.name
return Markup(l)
def get_gym(view, context, model, name):
l = model.gym.name
return Markup(l)
#def get_type(view, context, model, name):
# return STATUSES[model.type][1]
column_formatters = {
'city': get_city,
'gym': get_gym,
# 'type': get_type
}
'''
def _change_path_data(self, _form):
if not _form.image_url.raw_data:
return
storage_file = _form.image_url.raw_data[0]
if not hasattr(storage_file, 'filename'):
return
filename = os.path.basename(storage_file.filename)
uuid_hash = get_uuid_hash(filename)
uuid_folder = '{}{}'.format(AVATARS_UPLOAD_PATH, uuid_hash)
fpath = "{}/{}".format(
uuid_folder,
normalize_filename(filename)
)
source_url = os.path.join(uuid_hash, normalize_filename(filename))
try:
if not os.path.exists(uuid_folder):
try:
os.makedirs(uuid_folder)
except Exception as e:
subprocess.call(['chmod', '-R', '+w', uuid_folder])
os.makedirs(uuid_folder)
write_file(fpath, _form.image_url.data)
except Exception:
raise
source_url = '/images/%s' % source_url
return source_url
def on_model_change(self, form, model, is_created):
image_url = self._change_path_data(form)
if image_url:
model.image_url = image_url
'''
def on_model_change(self, form, model, is_created):
if form.weekly_event_start_date.data > form.weekly_event_stop_date.data:
raise ValidationError('Дата начала не может быть меньше даты конца')
if form.weekly_event_start_time.data > form.weekly_event_end_time.data:
raise ValidationError('Время начала не может быть меньше времени конца')
td = datetime.timedelta(minutes=1)
tstart = time_plus(form.weekly_event_start_time.data, td)
tstop = time_plus(form.weekly_event_end_time.data, td)
l = weekly_days_numbers(form.weekly_event_days.data)
delta = datetime.timedelta(days=1)
d1 = form.weekly_event_start_date.data
d2 = form.weekly_event_stop_date.data
days_in_period = []
while d1 <= d2:
if d1.weekday() in l:
days_in_period.append(d1)
d1 += delta
c = Session.query(Schedule).join(Gym, Gym.id == Schedule.gym_id) \
.filter(Gym.id == form.gym.data.id) \
.filter(Schedule.date.in_(days_in_period)) \
.filter(or_(Schedule.time_start.between(tstart, tstop),
Schedule.time_stop.between(tstart, tstop)))
if c.count() != 0:
raise ValidationError('В расписании уже найдено событие на это время! Укажите другое время или дату!')
cw = Session.query(WeeklyEvent).join(Gym, Gym.id == WeeklyEvent.gym_id) \
.join(WeeklyEventDays, WeeklyEvent.id == WeeklyEventDays.weekly_event_id) \
.filter(Gym.id == form.gym.data.id) \
.filter(WeeklyEventDays.event_date.in_(days_in_period)) \
.filter(or_(WeeklyEvent.weekly_event_start_time.between(tstart, tstop),
WeeklyEvent.weekly_event_end_time.between(tstart, tstop)))
if not is_created:
cw = cw.filter(WeeklyEvent.id != model.id)
if cw.count() != 0:
raise ValidationError('В расписании уже найдено периодическое событие на это время! Укажите другое время или дату!')
#Добавляем даты в периоде
for e in days_in_period:
wed = WeeklyEventDays(event_date=e)
model.days_in_period.append(wed)
def edit_form(self, obj=None):
form = super(WeeklyEventModelView, self).edit_form(obj)
return form
def edit_form(self, obj):
return self._customize_form(super(WeeklyEventModelView, self).edit_form(obj), obj)
def _customize_form(self, form, model=None):
return form
Answer the question
In order to leave comments, you need to log in
Didn't find what you were looking for?
Ask your questionAsk a Question
731 491 924 answers to any question