首页 > 解决方案 > 将 OData 查询编码为 URL

问题描述

我正在尝试在 python 中使用各种过滤器参数对 odata 查询进行编码。请求的纯字符串版本如下所示:

*endpoint*?$filter=datecolumn gt 2019-01-01T00:00:00Z

为了实际从服务器请求数据,我需要将字符串格式化为可以在请求中传递的 URL。URL 版本如下所示:

*endpoint*?%24filter=datecolumn%20gt%'2019-01-01T00:00:00Z

为了在 python 中轻松获取字符串的 URL 版本,我最初尝试使用 urllib 包:

import urllib
urllib.parse.quote('?$filter=datecolumn gt 2019-01-01T00:00:00Z')

但这似乎过度格式化了字符串。它将起始美元符号和等号等字符替换为其 url 编码的对应字符,这使我的 odata 查询不起作用。python 或任何包中是否有可用于轻松编码字符串以进行 odata 查询的方法?

一般来说,请求中 odata 使用的编码类型是否有名称?

标签: pythonpython-3.xurlodata

解决方案


我最近对此很感兴趣,并且玩弄了臭名昭著的 Northwind 示例服务,虽然有一些 Python 包可供试用,但我想首先我会看看仅使用请求和内置 Python 能走多远。

您可以看到格式化 URL 字符串就像 Hoang HUA 所说的那样简单——而且我什至没有使用请求可用的命令的“全部强度”[注意:表“加入”操作正在客户端发生,这个蛮横的强制代码仍然很短]:

import requests
import operator

def make_HTTP_request(url):
    r = requests.get(url)
    return r.json()

srvc_root = 'https://services.odata.org/V4/Northwind/Northwind.svc'

order_date = '1998-01-01T00:00:00Z'
filter = '$filter=OrderDate gt {} and RequiredDate lt ShippedDate'.format(order_date)
orders_qry = '$select=OrderID,CustomerID,EmployeeID&{}'.format(filter)
url_orders_qry = '{}/Orders?{}'.format(srvc_root, orders_qry)
urldict_orders = make_HTTP_request(url_orders_qry)

customerIDs = []
employeeIDs = []

for order in urldict_orders['value']:
    customerIDs.append(order['CustomerID'])
    employeeIDs.append(str(order['EmployeeID']))

customer_qry = '$select={}&$filter=CustomerID eq \'{}\''.format('CustomerID,CompanyName', '\' or CustomerID eq \''.join(customerIDs))
url_customers_qry = '{}/Customers?{}'.format(srvc_root, customer_qry)
urldict_customers = make_HTTP_request(url_customers_qry)

employee_qry = '$select={}&$filter=EmployeeID eq {}'.format('EmployeeID,FirstName,LastName', ' or EmployeeID eq '.join(employeeIDs))
url_employees_qry = '{}/Employees?{}'.format(srvc_root, employee_qry)
urldict_employees = make_HTTP_request(url_employees_qry)

dict_customers = {}
dict_employees = {}
dict_orders = {}

for cust in urldict_customers['value']:
    dict_customers[cust['CustomerID']] = cust['CompanyName']

for emp in urldict_employees['value']:
    dict_employees[emp['EmployeeID']] = '{} {}'.format(emp['FirstName'], emp['LastName'])

for order in urldict_orders['value']:
    dict_orders[order['OrderID']] = (dict_customers[order['CustomerID']], dict_employees[order['EmployeeID']])

for orders in sorted(dict_orders.items(), key=operator.itemgetter(1)):
    print('{0:7d}  {1:30s}{2:30s}'.format(orders[0], orders[1][0], orders[1][1]))

这是输出 - 跨 3 个表(实体)的 3 列(属性)的 8 行(元组):

  10924  Berglunds snabbköp            Janet Leverling               
  10827  Bon app'                      Nancy Davolio                 
  10970  Bólido Comidas preparadas     Anne Dodsworth                
  10816  Great Lakes Food Market       Margaret Peacock              
  10960  HILARION-Abastos              Janet Leverling               
  10927  La corne d'abondance          Margaret Peacock              
  10828  Rancho grande                 Anne Dodsworth                
  10847  Save-a-lot Markets            Margaret Peacock

顺便说一句,在 Northwind 的本地 PostgreSQL 数据库副本上执行,这是等效的 SQL:

SELECT
    O.order_id, C.company_name,
    E.first_name || ' ' || E.last_name AS Employee
FROM
    orders O JOIN employees E ON O.employee_id = E.employee_id
    JOIN customers C ON O.customer_id = C.customer_id
WHERE
    O.order_date > '1998-01-01' AND O.shipped_date > O.required_date
ORDER BY
    C.company_name;

推荐阅读