Geoalchemy2 запрашивает всех пользователей в пределах X метров

У меня есть приложение, которое берет адресную строку, отправляет ее в API Карт Google и получает широкие / длинные координаты. Затем я хочу показать всех пользователей в пределах X метров этой точки (там lat / long хранится в моей базе данных) , То я хочу, чтобы фильтр был результат, чтобы показывать только пользователей с некоторыми домашними животными

Итак, во-первых, у меня есть мои модели

class User(UserMixin, Base): first_name = Column(Unicode) address = Column(Unicode) location = Column(Geometry('POINT')) pets = relationship('Pet', secondary=user_pets, backref='pets') class Pet(Base): __tablename__ = 'pets' id = Column(Integer, primary_key=True) name = Column(Unicode) user_pets = Table('user_pets', Base.metadata, Column('user_id', Integer, ForeignKey('users.id')), Column('pet_id', Integer, ForeignKey('pets.id')) ) 

Я получаю свой lat / long от Google API и сохраняю его в своей базе данных, поэтому из адресной строки «London England» я получаю

 POINT (-0.1198244000000000 51.5112138999999871) 

это хранится в моей базе данных:

 0101000000544843D7CFACBEBF5AE102756FC14940 

Теперь, когда все работает нормально, теперь я читаю документы Geoalchemy2, которые, по-видимому, не могут найти запрос exmaple для решения моей проблемы.

То, что я хочу передать, – это еще один набор лат / длинных координат для Geoalchemy2, а затем верните ближайших 10 пользователей. Пока я прошу об этом, я также буду фильтровать только пользователей, у которых есть определенные домашние животные (это не обязательно для моего запроса на работу, но я хотел показать, что запрос действительно будет делать в полном объеме).

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

Я предполагаю, что мне нужно будет использовать «ST_DWithin» или «ST_DFullyWithin», но я не могу найти полный пример любой из функций. Благодаря.

Поэтому у меня есть рабочий запрос

 distance = 10 address_string = "London, England" results = Geocoder.geocode(address_string) # load long[1], lat[0] into shapely center_point = Point(results.coordinates[1], results.coordinates[0]) print center_point # 'POINT (-0.1198244000000000 51.5112138999999871)' wkb_element = from_shape(center_point) users = DBSession.query(User).\ filter(func.ST_DWithin(User.location, wkb_element, distance)).all() 

Что генерирует следующий SQL

 2013-12-30 15:12:06,445 INFO [sqlalchemy.engine.base.Engine][Dummy-2] SELECT users.first_name AS users_first_name, users.last_name AS users_last_name, users.phone AS users_phone, users.address AS users_address, users.about AS users_about, ST_AsBinary(users.location) AS users_location, users.profile_image_id AS users_profile_image_id, users.searchable AS users_searchable, users.user_password AS users_user_password, users.registered_date AS users_registered_date, users.id AS users_id, users.last_login_date AS users_last_login_date, users.status AS users_status, users.user_name AS users_user_name, users.email AS users_email, users.security_code AS users_security_code FROM users WHERE ST_DWithin(users.location, ST_GeomFromWKB(%(ST_GeomFromWKB_1)s, %(ST_GeomFromWKB_2)s), %(param_1)s) 2013-12-30 15:12:06,445 INFO [sqlalchemy.engine.base.Engine][Dummy-2] {'ST_GeomFromWKB_1': <read-only buffer for 0x7f7d10258f70, size -1, offset 0 at 0x7f7d10258db0>, 'param_1': 10, 'ST_GeomFromWKB_2': -1} 

Теперь это всегда возвращает всех моих пользователей, независимо от переменной расстояния, поэтому я угадываю, что что-то не так, правильно, но я не могу понять, почему.

Ответ:

Единицы были в радиусе градуса, поэтому мне пришлось перевести милю в дегресс, чтобы получить наилучшую (грубую) оценку. Это не обязательно должно быть точным:

 d = 90 distance = d * 0.014472 #1 mile = 0.014472 degrees r1 = -0.1198244 r2 = 51.5112139 # load long[1], lat[0] into shapely center_point = Point(r1, r2) # 'POINT (-0.1198244000000000 51.5112138999999871)' wkb_element = from_shape(center_point) users = DBSession.query(User).\ filter(func.ST_DFullyWithin(User.location, wkb_element, distance)).all() 

Данные Lat / Lon не подходят для расчетов расстояний.

Каждая градус широты составляет приблизительно 69 миль (111 километров) друг от друга. Диапазон варьируется (из-за слегка эллипсоидной формы земли) от 68,703 миль (110,567 км) на экваторе до 69,407 (111,699 км) на полюсах. Это удобно, потому что каждая минута (1/60 градуса) составляет примерно одну милю.

Степень долготы наиболее широка на экваторе на 69,172 миль (111,321) и постепенно сжимается до нуля на полюсах. На 40 ° севернее или юг расстояние между степенью долготы составляет 53 мили (85 км).

Вы можете использовать ST_Transform для преобразования координат в другую проекцию, которая использует метры или мили. Они имеют тенденцию быть локальными, поскольку они проектируют сферу Земли на растрированную плоскость. Британская национальная сетка (SRID 27700) может соответствовать вашим потребностям.

Interesting Posts