Fra*_*ath 5 python django rest
我在网上找不到关于如何做到这一点的信息,所以我决定发布我是如何做到这一点的.请随时分享您的建议或经验.
首先,在settings.py中,我设置了一些我可以重用的变量.如果您在本地使用Bonita Studio,则这些是默认设置.
BPM_HOST = 'http://localhost:9090/bonita-server-rest/'
BPM_USERNAME = 'restuser'
BPM_PASSWORD = 'restbpm'
Run Code Online (Sandbox Code Playgroud)
在views.py中,我设置了一个我可以随时使用的功能.它使用设置文件中的变量并接受登录用户的参数,要调用的url和post_data的字典.它以Bonitasoft期望的方式设置Basic身份验证和内容类型标头.
from django.conf import settings
import urllib
import urllib2
import base64
def restcall(user,url,post_data={}):
#create bpm_request
bpm_request = urllib2.Request(settings.BPM_HOST + url)
#encode username and password and add to header
authKey = base64.b64encode(settings.BPM_USERNAME + ':' + settings.BPM_PASSWORD)
bpm_request.add_header("Authorization","Basic " + authKey)
#add content type to header
bpm_request.add_header("Content-Type","application/x-www-form-urlencoded")
#must send current user in options
current_user = 'user:' + 'user'
post_data['options'] = current_user
bpm_request.add_data(urllib.urlencode(post_data))
response = urllib2.urlopen(bpm_request)
try:
return response
except Exception, exception:
logging.info(str(exception))
#endtry
#end restcall
Run Code Online (Sandbox Code Playgroud)
现在说你要构建一个所有流程实例的列表:
import xml.etree.ElementTree as ET
response = restcall(my_user,'API/queryRuntimeAPI/getLightProcessInstances')
root = ET.parse(response).getroot()
UUIDs=[]
for doc in root.findall('LightProcessInstance'):
UUIDs.append(doc.find('instanceUUID').find('value').text)
#endfor
Run Code Online (Sandbox Code Playgroud)
或者构建收件箱中的流程实例列表:
response = restcall(my_user,'API/queryRuntimeAPI/getLightParentProcessInstancesWithActiveUser/' + my_user +'?fromIndex=0&pageSize=200')
root = ET.parse(response).getroot()
UUIDs=[]
for doc in root.findall('LightProcessInstance'):
UUIDs.append(doc.find('instanceUUID').find('value').text)
#endfor
Run Code Online (Sandbox Code Playgroud)
发布数据真的很痛苦.首先,我创建了一个函数来清理你可能发送的任何文本:
def super_clean(text):
"""This will make data safe to send by rest.
Escape for <> (so we don't screw up our XML).
Quote plus to handle + signs.
Encode for international chars and smart quoates.
Strip to take out extra blanks before and after"""
return urllib.quote_plus(escape(text.encode('utf-8','replace').strip()))
#end super_clean
Run Code Online (Sandbox Code Playgroud)
以下是我生成XML映射的方法.如果您错过了它,XML地图的文档就在他们的文档中.
variable_string = '<map>' + \
'<entry><string>billing_department</string><string>' + super_clean(form.cleaned_data['billing_department']) + '</string></entry>' + \
'<entry><string>amount</string><double>' + super_clean(str(form.cleaned_data['amount'])) + '</double></entry>' + \
'<entry><string>account</string><string>' + super_clean(str(form.cleaned_data['number_attended'])) + '</long></entry>' + \
variable_string += '<entry><string>participant_name</string><list>'
for tempform in participant_formset.forms:
if 'participant_name' in tempform.cleaned_data:
variable_string += '<string>' + super_clean(tempform.cleaned_data['participant_name']) + '</string>'
#endif
#endfor
variable_string += '</list></entry>'
post_data = {}
post_data['variables'] = variable_string
Run Code Online (Sandbox Code Playgroud)
并使用以下内容更新现有记录:
process_instance_uuid = form.cleaned_data['uuid']
response = restcall(request,'API/runtimeAPI/setProcessInstanceVariables/' + process_instance_uuid,post_data)
Run Code Online (Sandbox Code Playgroud)
附加文件需要调用/ API/runtimeAPI/addAttachmentOctetStream/{instanceUUID}?name = &fileName =
这个REST调用与常规的Bonita Rest调用略有不同,所以我编写了以下函数来帮助:
from django.conf import settings
import urllib
import urllib2
import base64
def restAttachment(user,url,file):
#create bpm_request
bpm_request = urllib2.Request(settings.BPM_HOST + url,data=file.read())
#encode username and password and add to header
authKey = base64.b64encode(settings.BPM_USERNAME + ':' + settings.BPM_PASSWORD)
bpm_request.add_header("Authorization","Basic " + authKey)
#must send current user in options
current_user = 'user:' + 'user'
#add headers
bpm_request.add_header("Content-Type","application/octet-stream")
bpm_request.add_header('Content-Length', str(file.size))
bpm_request.add_header('Cache-Control', 'no-cache')
bpm_request.add_header('options', current_user)
bpm_request.add_header("Content-Disposition","attachment; filename="+urllib.quote(file.name))
try:
response = urllib2.urlopen(bpm_request)
except Exception, exception:
logging.info(str(exception))
#endtry
return response
#end restAttachment
Run Code Online (Sandbox Code Playgroud)
在forms.py中,您需要一个像这样的表单:
class AddAttachmentForm(Form):
process_instance_uuid = CharField(widget=HiddenInput())
attachment = FileField()
#end AddAttachmentForm
Run Code Online (Sandbox Code Playgroud)
在模板中,您需要具有以下内容(请注意enctype):
<form method="post" enctype="multipart/form-data" action="add_attachment"> {% csrf_token %}
{{ add_attachment_form }}
<input type="submit" value="Upload Attachment" />
</form>
Run Code Online (Sandbox Code Playgroud)
在views.py中,构建上述模板时,您应该具有以下内容:
add_attachment_form = AddAttachmentForm(initial={'process_instance_uuid':my_uuid,})
Run Code Online (Sandbox Code Playgroud)
处理表单时,您应该:
if 'attachment' not in request.FILES:
return render_to_response(...
form = AddAttachmentForm(request.POST, request.FILES) #note the request.FILES
response = restAttachment(user,'API/runtimeAPI/addAttachmentOctetStream/' + form.cleaned_data['process_instance_uuid'] + '?name=bonita_attachment_type_field_name) + '&fileName=' + urllib.quote(request.FILES['attachment'].name),request.FILES['attachment'])
Run Code Online (Sandbox Code Playgroud)
据我所知,这方面的文档几乎没有.
让我们从基础开始.要进行搜索,您必须发布到API/queryRuntimeAPI/searchByMaxResult?firstResult = &maxResults = .如果您发布到API/queryRuntimeAPI/search,则只获取记录数,而不是记录本身.
您可以使用firstResult和maxResults进行分页.
你的身体应该是这样的:
options=user:my_user&query=<query_xml>
Run Code Online (Sandbox Code Playgroud)
困难的部分是弄清楚query_xml中的内容.我在Bonitasoft网站上找到的例子都是br标签.出于某种原因,Bonitasoft网站剥离了他们的xml标签.可以使用Java API创建查询xml.一种方法是在Bonita Studio中使用Groovy Editor并使用Evaluate按钮运行它.在以下示例中,"first_name"是我创建的数据字段之一.
import org.ow2.bonita.search.SearchQueryBuilder;
import org.ow2.bonita.search.index.ProcessInstanceIndex;
import org.ow2.bonita.search.index.ActivityInstanceIndex;
SearchQueryBuilder query = new SearchQueryBuilder(new ProcessInstanceIndex());
query.criterion(ProcessInstanceIndex.VARIABLE_NAME).equalsTo("first_name").and().criterion(ProcessInstanceIndex.VARIABLE_VALUE).equalsTo('Archibald');
return query;
Run Code Online (Sandbox Code Playgroud)
你会认为这将返回字段"first_name"设置为"Archibald"的任何记录.实际上,它返回包含字段"first_name"(应该是所有这些字段)的任何记录,并且具有任何用户定义的字段,其值为"Archibald".因此,如果某人的姓氏是"Archibald",他们也将被退回.似乎没有办法解决这个问题.最好只是接受这样一个事实:它是一个完整的搜索并简化为:
query.criterion(ProcessInstanceIndex.VARIABLE_VALUE).equalsTo('Archibald');
Run Code Online (Sandbox Code Playgroud)
这会生成以下XML:
<SearchQueryBuilder>
<index class="org.ow2.bonita.search.index.ProcessInstanceIndex"/>
<query>
<org.ow2.bonita.search.Criterion>
<builder reference="../../.."/>
<fieldName>variable_value</fieldName>
<value>Archibald</value>
</org.ow2.bonita.search.Criterion>
</query>
</SearchQueryBuilder>
Run Code Online (Sandbox Code Playgroud)
同样,这只搜索用户定义的字段.如果要搜索其他字段,请参阅http://documentation.bonitasoft.com/javadoc/bpm_engine/5.9/org/ow2/bonita/search/index/ProcessInstanceIndex.html.我也想搜索创建者,所以我的XML变成了:
<SearchQueryBuilder>
<index class="org.ow2.bonita.search.index.ProcessInstanceIndex"/>
<query>
<org.ow2.bonita.search.Criterion>
<builder reference="../../.."/>
<fieldName>variable_value</fieldName>
<value>Archibald</value>
</org.ow2.bonita.search.Criterion>
<string> OR </string>
<org.ow2.bonita.search.Criterion>
<builder reference="../../.."/>
<fieldName>startedBy</fieldName>
<value>Archibald</value>
</org.ow2.bonita.search.Criterion>
</query>
</SearchQueryBuilder>
Run Code Online (Sandbox Code Playgroud)
最后,我想将搜索范围限制在日期范围内.日期格式为yyyymmddhhmmssttt.我想搜索日期范围,所以我将开始时间设置为0,将结束时间设置为所有9.逻辑规定我在OR子句周围添加括号.
<SearchQueryBuilder>
<index class="org.ow2.bonita.search.index.ProcessInstanceIndex"/>
<query>
<string>(</string>
<org.ow2.bonita.search.Criterion>
<builder reference="../../.."/>
<fieldName>variable_value</fieldName>
<value>Archibald</value>
</org.ow2.bonita.search.Criterion>
<string> OR </string>
<org.ow2.bonita.search.Criterion>
<builder reference="../../.."/>
<fieldName>startedBy</fieldName>
<value>Archibald</value>
</org.ow2.bonita.search.Criterion>
<string>)</string>
<string> AND </string>
<org.ow2.bonita.search.Criterion>
<builder reference="../../.."/>
<fieldName>startedDate</fieldName>
<value>[20130101000000000 TO 20131231999999999]</value>
</org.ow2.bonita.search.Criterion>
</query>
</SearchQueryBuilder>
Run Code Online (Sandbox Code Playgroud)
所以现在我有了我的XML,我只需要将它插入Python.我创建了一个表单:
class SearchForm(Form):
search_text = CharField(widget=TextInput(attrs={'size':'80'}))
start_date = DateField(widget=widgets.TextInput(attrs={"class":"calendar"}))
end_date = DateField(widget=widgets.TextInput(attrs={"class":"calendar"}))
Run Code Online (Sandbox Code Playgroud)
我不想弄乱分页,所以如果有超过100条记录,我会给他们一条消息来缩小他们的标准.请注意,在我的xml中,我在搜索文本周围添加了引号.这使搜索匹配整个文本.如果文本中有空格而您不使用引号,则搜索不会尝试匹配所有单词.以下是我处理表单并执行搜索的方法:
if request.method == 'POST':
search_form = SearchForm(request.POST)
if not search_form.is_valid():
return render_to_response(...
#format dates in manner expected by API
start = search_form.cleaned_data['start_date'].strftime('%Y%m%d') + "000000000"
end = search_form.cleaned_data['end_date'].strftime('%Y%m%d') + "999999999"
post_data={}
#the search query must be in this xml format
post_data['query'] = '''
<SearchQueryBuilder>
<index class="org.ow2.bonita.search.index.ProcessInstanceIndex"/>
<query>
<string>(</string>
<org.ow2.bonita.search.Criterion>
<builder reference="../../.."/>
<fieldName>variable_value</fieldName>
<value>"%s"</value>
</org.ow2.bonita.search.Criterion>
<string> OR </string>
<org.ow2.bonita.search.Criterion>
<builder reference="../../.."/>
<fieldName>startedBy</fieldName>
<value>"%s"</value>
</org.ow2.bonita.search.Criterion>
<string>)</string>
<string> AND </string>
<org.ow2.bonita.search.Criterion>
<builder reference="../../.."/>
<fieldName>startedDate</fieldName>
<value>[%s TO %s]</value>
</org.ow2.bonita.search.Criterion>
</query>
</SearchQueryBuilder>''' \
% (super_clean(search_form.cleaned_data['search_text']),
super_clean(search_form.cleaned_data['search_text']),
start,
end)
#get number of records
response = restcall(request,'API/queryRuntimeAPI/search',post_data)
number_of_records = response.read()
if is_int(number_of_records):
number_of_records = int(number_of_records)
else:
return render_to_response(...
if number_of_records > 100:
return render_to_response(...
if number_of_records == 0:
return render_to_response(...
#now get the records
response = restcall(request,'API/queryRuntimeAPI/searchByMaxResult?firstResult=0&maxResults=100',post_data)
root = ET.parse(response).getroot()
#loop through requests
for doc in root.findall('LightProcessInstance'):
...
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1062 次 |
| 最近记录: |