2016-01-06 3 views
17

У меня есть столбец в моей базе данных под названием 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. Причина, по которой большинство вещей - это строки, состоит в том, что большинство моих значений, которые должны быть сохранены в базе данных, отправляются как строки, поэтому сохранение является тривиальным. Мне интересно, должен ли я все это разыгрывать магию с функциями до и просто иметь больше записей в базе данных? такие вещи, как десятичного time_begin, time_end, latitude_begin вместо того, чтобы иметь строку, содержащую диапазон времени что я анализирую найти time_begin и time_end когда я буду фильтровать

+1

Я думаю, что лучше всего было бы сделать скоординировать как класс и сделать его в качестве элемента базы данных, там вы можете добавлять методы, которые вы хотите по координатам, не вызывая изменение базы данных, например DatabaseShape.coordinates.get_shape_range – Eliethesaiyan

+0

@Eliethesaiyan, если бы я сделал класс элементом моей базы данных, я мог бы сделать что-то вроде «DatabaseShape.coordinates». get_shape_range.like ('дата') '? Но не get_shape_range возвращает строку в моем случае, поэтому вы не можете просто использовать '.like' на ней? –

+0

Какую базу вы используете? Как выглядит содержимое «координат», это строка? –

ответ

9

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

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's 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) 
    )