@emeraldsinner

Как вызвать функцию Python/Django как «триггер»?

Дело такое:
"Пишу проект на python/django, дали дополнительную задачу, распарсить xml (файл отправляет другая програма по ftp) и залить информацию в БД MySQL, все сделал, осталось одно, нужно чтоб функция вызывалась автоматически, когда на сервер приходит xml файл, google пока не помог, а дедлайн на носу, буду очень благодарен за любые подсказки, спасибо."

Парсер пока выглядит так (в БД файлы не заливаю - нет нужды):

parser.py
# -*- coding: utf-8 -*-
from xml.dom import minidom

doc = minidom.parse('../document.xml')
object_propertys = doc.getElementsByTagName("object_property")

def getTableName(type, realty_type):
	if (type == "Rent" and realty_type == "Apartment"):
		tableName = "maklers_rent_apartment"
	if (type == "Rent" and realty_type == "House"):
		tableName = "maklers_rent_house"
	if (type == "Rent" and realty_type == "Nonlive"):
		tableName = "maklers_rent_office"
	if (type == "Sale" and realty_type == "Apartment"):
		tableName = "maklers_sale_apartment"
	if (type == "Sale" and realty_type == "House"):
		tableName = "maklers_sale_house"
	if (type == "Sale" and realty_type == "Land"):
		tableName = "maklers_sale_stead"
	if (type == "Sale" and realty_type == "Nonlive"):
		tableName = "maklers_sale_office"
	return tableName

def getId(iii):
	x = 0
	objects = doc.getElementsByTagName("object")
	for object in objects:
		soid = object.getAttribute("oid")
		myid = soid
		if (x == iii):
			break
		x+=1
 	return myid

def parse():
	i=0
	for object_property in object_propertys:
		sid = getId(i)
		i+=1
		stype = object_property.getAttribute("type")
		srealty_type = object_property.getAttribute("realty_type")
		if srealty_type == "Nonlive":
			continue
		tableName = getTableName(stype, srealty_type)
		sdistrict = object_property.getAttribute("district")
		sstreet = object_property.getAttribute("street")
		sprice = object_property.getAttribute("price")
		slevel = object_property.getAttribute("level")
		sarea_all = object_property.getAttribute("area_all")
		sobject_details = object_property.getAttribute("object_details")
		sinfo = object_property.getAttribute("info")
		print ("ID: " + sid.encode('utf-8'))
		print ("Таблиця: " + tableName.encode('utf-8'))
		print ("Район: " + sdistrict.encode('utf-8'))
		print ("Вулиця: " + sstreet.encode('utf-8'))
		print ("Вартість: " + sprice.encode('utf-8'))
		print ("Поверх: " + slevel.encode('utf-8'))
		print ("Загальна площа: " + sarea_all.encode('utf-8'))
		print ("Деталі: " + sobject_details.encode('utf-8') + " " + sinfo.encode('utf-8'))
		print i
		print ""

parse()
  • Вопрос задан
  • 4222 просмотра
Пригласить эксперта
Ответы на вопрос 2
@bromzh
Drugs-driven development
Б-же, что за говнок*д.
Почитай уже pep8, не плоди этот ужас форматирования дальше. Вдруг кому-то придётся поддерживать твоё творение?
1) Лучше 4 символа, не 8.
2) Ладно, имена функций можно в camelCase, но только если это нужно для совместимости. Ну допустим, что нужно. Но имена переменных? В первой функции - camelCase, в других случаях с_подчёркиванием. За что?
3) Имена глобальных переменных лучше ПИСАТЬ_ЗАГЛАВНЫМИ. А ещё лучше вообще не использовать глобальные переменные, так как в локальной области они перекроются. Используй функции, люк. Или хотя бы классы с полями.
4) Вместо
def getTableName(type, realty_type):
	if (type == "Rent" and realty_type == "Apartment"):
		tableName = "maklers_rent_apartment"
	if (type == "Rent" and realty_type == "House"):
		tableName = "maklers_rent_house"
        return tableName

Надо
def getTableName(type, realty_type):
	if (type == "Rent" and realty_type == "Apartment"):
		rerurn "maklers_rent_apartment"
	if (type == "Rent" and realty_type == "House"):
		return = "maklers_rent_house"
        return None

В моём варианте функция вернёт значение сразу, без создания доп. переменной и без выполнения заведомо ненужных веток (когда вариант найден). Мало того, что ты не используешь elif, что при определённых обстоятельствах принесёт тебе массу проблем, которые ты не ожидаешь, так ещё если в твоём варианте не выполнится ни одно условие, то будет ждать ещё один забавный сюрприз.
UPD. И ещё, не рекомендуется использовать названия built-in функций и пакетов для имён переменных, методов и т.д. Например, в этой функции ты не сможешь использовать встроенную type, так как внутри функции она заменяется на локальную переменную. И прочитай про области видимости, на всякий случай.
5) Вот эта строчка очень радует:
soid = object.getAttribute("oid")
myid = soid

Зачем тут вторая переменная?
Да и сама функция вызывается в цикле(!), при этом, в ней ты каждый раз теребишь парсер
objects = doc.getElementsByTagName("object")

Хотя этот код никак не меняется, и получить объекты надо строго 1 раз, а не дофига.
UPD 2. Эта функция вообще очень странная. Ты сперва отдельно получаешь список объектов и отдельно их свойства. А потом ты ищешь эти id заново (да ещё и в цикле, ещё и каждый раз заново парсишь xml). Это полнейший идиотизм. Я не видел xml, но по логике, свойства объектов должны быть внутри объекта или как-то связаны с ним через id. Возьми нормальный парсер (а ещё лучше этот) и разбирай деревом. Ну и не стоит разделять объекты от свойств, а потом заново искать id.
6) Зачем создавать переменную,
sid = getId(i)

если результат ты используешь только в одном месте?
print ("ID: " + sid.encode('utf-8'))
7) Забудь ты эти плюсы в строках
print ("Деталі: " + sobject_details.encode('utf-8') + " " + sinfo.encode('utf-8'))

Есть же удобное форматирование (когда надо что-то сложное):
print("Детали: {0} {1}".format(sobject_details.encode('utf-8'), sinfo.encode('utf-8'))
# или
print("Детали: {details} {info}".format(details=sobject_details.encode('utf-8'), info=sinfo.encode('utf-8'))

И быстрый join, когда простое форматирование:
print(" ".join(("Детали:", sobject_details.encode('utf-8'), sinfo.encode('utf-8')))

В общем, не пиши так больше, пожалуйста.
8)
propertys

propertIEs же!

Ну а по теме всё правильно сказали, ftp надо выкинуть и обрабатывать HTTP-запросы. Но, так как это невозможно, то:
1) Просто запусти какой-нибудь крон и отслеживай изменения в файлах. При изменении запускай скрипт.
2) Есть программы, которые запускаются как серверы, следят за изменением файлов в папке в реалтайме и могут отправлять всякие уведомления (в том числе и по TCP/HTTP). Можно настроить всё это на отправку HTTP-запроса на джангу. Но это создаст небольшой оверхед. Если всё на одном серваке (и фтп, и джанга), то первый вариант лучше.
Ответ написан
vvpoloskin
@vvpoloskin
Инженер связи
Нужен хук на изменение файлов, при котором будет запускаться внешний скрипт. Вот варианты в порядке увеличения сложности и геморности:
1) crontab на проверку изменения файла и запуск скрипта
2) использовать ftp-шник с нужным функционалом запуска внешнего скрипта (pureftpd умеет).
3) libnotify и отслеживание изменений файловой системы
4) самопальный отдельный ftp-сервер на том же python-е, который будет обрабатывать только нужные вам соединения. Не так уж и трудно с учетом всяких pyftpdlib, twistd.
5) обычный ftp-шник с перенаправлением логирования на именованный канал. А этот канал вы будете проверять на наличие строки типа "file xls uploaded" и запускать обработчик.

Я могу еще придумать кучу решений этой задачи с использование SNMP, различных файловых систем, email-нотификаций (pureftp вроде умеет) но если у вас есть запущенный сайт, то я бы убедил клиента использовать http вместо ftp, а в серверной части вы бы обработали как надо. Ну или после отправки файла на клиентской стороне инициировать http-запрос к вашему сервису после загрузки файла, по которому запускается скрипт.
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы