Подтвердить что ты не робот

Применить функцию к столбцу перед фильтрацией

У меня есть столбец в моей базе данных под названием coordinates, теперь столбец координат содержит информацию о диапазоне времени, которое объект занимает в моем графике. Я хочу разрешить пользователю фильтровать по дате, но проблема в том, что я использую функцию для определения даты в обычном режиме. Возьмем:

# query_result is the result of some filter operation
for obj in query_result:
    time_range, altitude_range = get_shape_range(obj.coordinates)
    # time range for example would be "2006-06-01 07:56:17 - ..."

Теперь, если я хочу фильтровать по дате, я бы хотел, чтобы это был like:

query_result = query_result.filter(
    DatabaseShape.coordinates.like('%%%s%%' % date))

Но проблема в том, что мне сначала нужно применить get_shape_range к coordinates, чтобы получить строку. Есть ли способ сделать... Я предполагаю операцию transform_filter? Такое, что до like происходит, я применяю некоторую функцию к координатам? В этом случае мне нужно будет написать функцию get_time_range, которая вернула бы только время, но вопрос остается тем же.


EDIT: Здесь мой класс базы данных

class DatabasePolygon(dbBase):
    __tablename__ = 'objects'

    id = Column(Integer, primary_key=True)  # primary key
    tag = Column(String)  # shape tag
    color = Column(String)  # color of polygon
    time_ = Column(String)  # time object was exported
    hdf = Column(String)  # filename
    plot = Column(String)  # type of plot drawn on
    attributes = Column(String)  # list of object attributes
    coordinates = Column(String)  # plot coordinates for displaying to user
    notes = Column(String)  # shape notes
    lat = Column(String)

    @staticmethod
    def plot_string(i):
        return constants.PLOTS[i]

    def __repr__(self):
        """
        Represent the database class as a JSON object. Useful as our program
        already supports JSON reading, so simply parse out the database as
        separate JSON 'files'
        """
        data = {}
        for key in constants.plot_type_enum:
            data[key] = {}
        data[self.plot] = {self.tag: {
            'color': self.color,
            'attributes': self.attributes,
            'id': self.id,
            'coordinates': self.coordinates,
            'lat': self.lat,
            'notes': self.notes}}
        data['time'] = self.time_
        data['hdfFile'] = self.hdf
        logger.info('Converting unicode to ASCII')
        return byteify(json.dumps(data))

и я использую sqlite 3.0. Причина, по которой большинство вещей - это строки, состоит в том, что большинство моих значений, которые должны быть сохранены в базе данных, отправляются как строки, поэтому сохранение является тривиальным. Мне интересно, должен ли я все это развить магия с функциями раньше, и просто иметь больше записей в базе данных? для таких вещей, как decimal time_begin, time_end, latitude_begin вместо строки, содержащей диапазон времени, который я анализирую, чтобы найти time_begin и time_end, когда я фильтрую

4b9b3361

Ответ 1

Я думаю, что вам обязательно нужно разобрать строки в столбцах, прежде чем хранить их в базах данных. Пусть база данных выполнит работу, для которой она была создана!

CREATE TABLE [coordinates]
(
  id                INTEGER  NOT NULL PRIMARY KEY,
  tag               VARCHAR2(32),
  color             VARCHAR2(32)    default 'green',
  time_begin        TIMESTAMP,
  time_end          TIMESTAMP,
  latitude_begin    INT
);

create index ix_coord_tag on coordinates(tag);
create index ix_coord_tm_beg on coordinates(time_begin);

insert into coordinates(tag, time_begin, time_end, latitude_begin)
values('tag1', '2006-06-01T07:56:17', '2006-06-01T07:56:19', 123);

insert into coordinates(tag, time_begin, time_end, latitude_begin)
values('tag1', '2016-01-01T11:35:01', '2016-01-01T12:00:00', 130);

insert into coordinates(tag, color, time_begin, time_end, latitude_begin)
values('tag2', 'blue', '2014-03-03T20:11:01', '2014-03-03T20:11:20', 2500);

insert into coordinates(tag, color, time_begin, time_end, latitude_begin)
values('tag2', 'blue', '2014-03-12T23:59:59', '2014-03-13T00:00:29', 2978);

insert into coordinates(tag, color, time_begin, time_end, latitude_begin)
values('tag3', 'red', '2016-01-01T11:35:01', '2016-01-01T12:00:00', 13000);

insert into coordinates(tag, color, time_begin, time_end, latitude_begin)
values('tag3', 'red', '2016-01-01T12:00:00', '2016-01-01T12:00:11', 13001);

.headers on
.mode column

select * from coordinates where tag='tag1' and '2006-06-01T07:56:18' between time_begin and time_end;

select * from coordinates where color='blue' and time_end between '2014-03-13T00:00:00' and '2014-03-13T00:10:00';

Вывод:

sqlite> select * from coordinates where tag='tag1' and '2006-06-01T07:56:18' between time_begin and time_end;
id          tag         color       time_begin           time_end             latitude_begin
----------  ----------  ----------  -------------------  -------------------  --------------
1           tag1        green       2006-06-01T07:56:17  2006-06-01T07:56:19  123
sqlite>
sqlite> select * from coordinates where color='blue' and time_end between '2014-03-13T00:00:00' and '2014-03-13T00:10:00';
id          tag         color       time_begin           time_end             latitude_begin
----------  ----------  ----------  -------------------  -------------------  --------------
4           tag2        blue        2014-03-12T23:59:59  2014-03-13T00:00:29  2978

Ответ 2

Учитывая заголовок вопроса, я предполагаю, что вы не используете метод like().

SQLAlchemy Query.filter() принимает любые критерии, которые оцениваются как логические.

Почему бы не изменить критерий фильтра, чтобы вместо использования метода like() в строке вы тестировали объекты Python datetime.date?

Я не знаю, как выглядит obj.coordinates, но вот грубая схема, которая, на мой взгляд, имеет смысл:

def check_range(coords, date):
    """ takes a date, and a "coordinates" value (representing a date 
        range), and a date as inputs, returns True if the 
        date is within that date range, else returns False
    """
    #some code here...


query_result = query_result.filter(
        check_range(DatabaseShape.coordinates, date)
    )