Django實現(xiàn)支付寶付款和微信支付的示例代碼
支付寶支付和微信支付是當(dāng)今互聯(lián)網(wǎng)產(chǎn)品常用的功能,我使用Django Rest Framework實現(xiàn)了網(wǎng)頁上支付寶支付和微信支付的一個通用服務(wù),提供rpc接口給其他服務(wù),包括獲取支付寶支付頁面url的rpc接口、支付寶支付成功異步回調(diào)http接口、獲取微信支付二維碼rpc接口、主動查詢微信訂單是否支付的rpc接口等。
支付寶網(wǎng)站支付需要螞蟻金服開放平臺賬號,創(chuàng)建應(yīng)用、配置秘鑰等步驟請參考:螞蟻金服支付寶電腦網(wǎng)站支付快速接入
微信網(wǎng)站支付需要到微信支付官網(wǎng)注冊服務(wù)商賬號,
目錄結(jié)構(gòu)如下:

1、models.py
from django.db import models
from django.contrib.postgres.fields import ArrayField
# Create your models here.
class BaseModel(models.Model):
"""
基礎(chǔ)模型
"""
created_time = models.DateTimeField(auto_now_add=True, verbose_name="創(chuàng)建時間")
updated_time = models.DateTimeField(auto_now=True, verbose_name="修改時間")
created_by = models.IntegerField(verbose_name="創(chuàng)建人ID")
updated_by = models.IntegerField(verbose_name="修改人ID")
is_active = models.BooleanField(default=True, verbose_name='是否正常')
class Meta:
abstract = True
class Alipay(BaseModel):
"""
支付
"""
subject = models.CharField(max_length=256, verbose_name="訂單標(biāo)題")
out_trade_no = models.CharField(max_length=64, unique=True, verbose_name="唯一訂單號")
trade_no = models.CharField(default="", max_length=64, verbose_name="支付寶系統(tǒng)中的交易流水號")
total_amount = models.DecimalField(max_digits=11, decimal_places=2, verbose_name="訂單的資金總額")
return_url = models.CharField(max_length=500, verbose_name="支付完成同步跳轉(zhuǎn)地址")
notify_url = models.CharField(max_length=500, verbose_name="支付完成異步通知rpc地址")
pay_time = models.DateTimeField(null=True, blank=True, verbose_name="支付時間")
pay_nos = ArrayField(models.CharField(max_length=100), default=[], verbose_name='同一訂單的支付ID數(shù)組')
class Meta:
verbose_name = "阿里支付"
verbose_name_plural = verbose_name
ordering = ('-created_time',)
class Wxorder(BaseModel):
"""
訂單
"""
body = models.CharField(max_length=256, verbose_name="商品描述")
out_trade_no = models.CharField(max_length=64, unique=True, verbose_name="訂單號")
transaction_id = models.CharField(default="", max_length=64, verbose_name="微信支付訂單號")
total_fee = models.BigIntegerField(verbose_name="訂單的資金總額,單位為分")
product_id = models.CharField(max_length=16, verbose_name="商品ID")
notify_url = models.CharField(max_length=500, verbose_name="支付完成通知url")
pay_time = models.DateTimeField(null=True, blank=True, verbose_name="支付時間")
class Meta:
verbose_name = "微信訂單"
verbose_name_plural = verbose_name
ordering = ('-created_time',)
class Wxpay(BaseModel):
"""
微信支付
"""
out_trade_no = models.CharField(null=True, blank=True, max_length=64, verbose_name="訂單號")
pay_no = models.CharField(null=True, blank=True, max_length=64, unique=True, verbose_name="支付唯一訂單號")
code_url = models.CharField(null=True, blank=True, max_length=100, verbose_name="二維碼地址")
nonce_str = models.CharField(null=True, blank=True, max_length=32, verbose_name="隨機字符串")
class Meta:
verbose_name = "微信支付"
verbose_name_plural = verbose_name
ordering = ('-created_time',)
2、serializers.py:
from django.conf import settings from rest_framework import serializers from pay.models import Alipay, Wxpay class BaseSerializer(serializers.ModelSerializer): created_time = serializers.DateTimeField(format=settings.DATETIME_FORMAT, read_only=True) updated_time = serializers.DateTimeField(format=settings.DATETIME_FORMAT, read_only=True) is_active = serializers.BooleanField(read_only=True) class Meta: model = None class AlipaySerializer(BaseSerializer): """ 阿里支付序列化類 """ class Meta: model = Alipay fields = "__all__" class WxpaySerializer(BaseSerializer): """ 阿里支付序列化類 """ class Meta: model = Wxpay fields = "__all__"
3、views.py:
# -*- coding=utf-8 -*-
# Create your views here.
import time
import dicttoxml
from jsonrpc import jsonrpc_method
from rest_framework.decorators import list_route
from rest_framework.response import Response
from rest_framework.viewsets import ModelViewSet
from rest_framework.views import APIView
from rest_framework_xml.parsers import XMLParser
from rest_framework_xml.renderers import XMLRenderer
from tokenauth.decorators import is_login
from pay import utils
from pay.weixin_pay import WeiXinPay, UnifiedOrderPay, OrderQuery
from pay.UUIDTools import UUIDTools
from pay.models import Alipay, Wxpay, Wxorder
from pay.serializers import AlipaySerializer, WxpaySerializer
from pay.utils import UnActiveModelMixin
from pay.alipay import AliPay
from PAY_SERVICE.settings.base import APPID, PRIVATE_KEY_PATH, \
ALI_PUB_KEY_PATH, ALIPAY_CALLBACK_URL, \
WXAPPID, WX_PAY_KEY, WX_MCH_ID, WXPAY_CALLBACK_URL
NOTIFY_URL = ALIPAY_CALLBACK_URL + 'api/v1.0/pay/alipay/notify/'
class AlipayViewSet(ModelViewSet):
queryset = Alipay.objects.filter(is_active=True)
serializer_class = AlipaySerializer
@list_route(methods=['post'])
def notify(self, request):
"""
處理支付寶的notify_url
:param request:
:return:
"""
processed_dict = {}
for k, v in request.data.items():
processed_dict[k] = v
app_id = processed_dict.get('app_id')
pay_no = processed_dict.get('out_trade_no')
trade_no = processed_dict.get('trade_no')
total_amount = processed_dict.get('total_amount')
pay_time = time.strftime('%Y-%m-%d %H:%M:%S',time.localtime())
alipay = Alipay.objects.filter(pay_nos__contains=[pay_no]).values().first()
if alipay is None:
return Response("failed")
if str(alipay.get('total_amount')) != str(total_amount):
return Response("failed")
if app_id != APPID:
return Response("failed")
if alipay.get('trade_no') != "":
return Response("failed")
sign = processed_dict.pop('sign', None)
ali_pay = AliPay(
appid=APPID,
app_notify_url=NOTIFY_URL,
app_private_key_path=PRIVATE_KEY_PATH,
alipay_public_key_path=ALI_PUB_KEY_PATH,
debug=True, # 默認(rèn)False,
return_url=alipay.get('return_url')
)
is_verify = ali_pay.verify(processed_dict, sign)
if is_verify is True:
Alipay.objects.filter(pk=alipay.get('id')).update(pay_time=pay_time, trade_no=trade_no)
ret = utils.request_thrift('TradingManager', 'notify',
settings.TRADING_RPC_IP, int(settings.TRADING_RPC_PORT),
alipay.get('out_trade_no'), str(pay_time))
if ret == "success":
return Response("success")
class WxpayViewSet(ModelViewSet):
queryset = Wxpay.objects.filter(is_active=True)
serializer_class = WxpaySerializer
parser_classes = (XMLParser,)
renderer_classes = (XMLRenderer,)
@jsonrpc_method('pay.get_alipay_url')
def get_alipay_url(request, subject, out_trade_no, total_amount, return_url, notify_url, user_id):
recode = Alipay.objects.filter(out_trade_no=out_trade_no).values().first()
if recode is not None:
pay_no = UUIDTools.datetime_random()
alipay = Alipay.objects.get(pk=recode.get('id'))
alipay.pay_nos.append(pay_no)
alipay.save()
else:
pay_no = out_trade_no
Alipay.objects.create(subject=subject,
out_trade_no=out_trade_no,
total_amount=total_amount,
return_url=return_url,
notify_url=notify_url,
pay_nos=[pay_no],
created_by=user_id,
updated_by=user_id
)
ali_pay = AliPay(
appid=APPID,
app_notify_url=NOTIFY_URL,
app_private_key_path=PRIVATE_KEY_PATH,
alipay_public_key_path=ALI_PUB_KEY_PATH,
debug=True, # 默認(rèn)False,
return_url=return_url
)
total_amount = "%.2f" % float(total_amount)
url = ali_pay.direct_pay(
subject=subject,
out_trade_no=pay_no,
total_amount=total_amount
)
# 沙箱環(huán)境網(wǎng)關(guān)
# alipay_url = "https://openapi.alipaydev.com/gateway.do?{data}".format(data=url)
# 正式環(huán)境網(wǎng)關(guān)
alipay_url = "https://openapi.alipay.com/gateway.do?{data}".format(data=url)
return alipay_url
@jsonrpc_method('pay.get_wxpay_url')
def get_wxpay_url(request, out_trade_no, body, total_fee, notify_url, product_id, user_id):
recode = Wxorder.objects.filter(out_trade_no=out_trade_no).values().first()
if recode is None:
Wxorder.objects.create(
out_trade_no=out_trade_no,
body=body,
total_fee=total_fee,
notify_url=notify_url,
product_id=product_id,
created_by=user_id,
updated_by=user_id
)
pay_no = UUIDTools.datetime_random()
pay = UnifiedOrderPay(WXAPPID, WX_MCH_ID, WX_PAY_KEY)
response = pay.post(body, pay_no, total_fee,
WXPAY_CALLBACK_URL.split('://')[1].split(':')[0], WX_NOTIFY_URL)
if response and response["return_code"] == "SUCCESS" and response["result_code"] == "SUCCESS":
wxorder = Wxorder.objects.filter(out_trade_no=out_trade_no).values().first()
Wxpay.objects.create(
out_trade_no=out_trade_no,
pay_no=pay_no,
code_url=response.get('code_url'),
nonce_str=response.get('nonce_str'),
created_by=user_id,
updated_by=user_id
)
return response.get('code_url')
@jsonrpc_method('pay.wx_order_query')
def wx_order_query(request, out_trade_no):
wxpays = Wxpay.objects.filter(out_trade_no=out_trade_no).values()
pay = OrderQuery(WXAPPID, WX_MCH_ID, WX_PAY_KEY)
for wxpay in wxpays:
response = pay.post(wxpay.get('pay_no'))
if response and response["return_code"] == "SUCCESS" \
and response["result_code"] == "SUCCESS":
trade_state = response["trade_state"]
if trade_state == "SUCCESS": # 支付成功
pay_time = response["time_end"]
transaction_id = response["transaction_id"]
Wxorder.objects.filter(out_trade_no=out_trade_no).update(
pay_time=time.strftime("%Y-%m-%d %H:%M:%S",
time.strptime(pay_time, "%Y%m%d%H%M%S")),
transaction_id=transaction_id
)
return {"success": True, "pay_time": pay_time}
return {"success": False}
4、alipay.py:
# -*- coding: utf-8 -*-
# pip install pycryptodome
from datetime import datetime
from Crypto.PublicKey import RSA
from Crypto.Signature import PKCS1_v1_5
from Crypto.Hash import SHA256
from base64 import b64encode, b64decode
from urllib.parse import quote_plus
from urllib.parse import urlparse, parse_qs
from urllib.request import urlopen
from base64 import decodebytes, encodebytes
import json
class AliPay(object):
"""
支付寶支付接口
"""
def __init__(self, appid, app_notify_url, app_private_key_path,
alipay_public_key_path, return_url, debug=False):
self.appid = appid
self.app_notify_url = app_notify_url
self.app_private_key_path = app_private_key_path
self.app_private_key = None
self.return_url = return_url
with open(self.app_private_key_path) as fp:
self.app_private_key = RSA.importKey(fp.read())
self.alipay_public_key_path = alipay_public_key_path
with open(self.alipay_public_key_path) as fp:
self.alipay_public_key = RSA.import_key(fp.read())
if debug is True:
self.__gateway = "https://openapi.alipaydev.com/gateway.do"
else:
self.__gateway = "https://openapi.alipay.com/gateway.do"
def direct_pay(self, subject, out_trade_no, total_amount, return_url=None, **kwargs):
biz_content = {
"subject": subject,
"out_trade_no": out_trade_no,
"total_amount": total_amount,
"product_code": "FAST_INSTANT_TRADE_PAY",
# "qr_pay_mode":4
}
biz_content.update(kwargs)
data = self.build_body("alipay.trade.page.pay", biz_content, self.return_url)
return self.sign_data(data)
def build_body(self, method, biz_content, return_url=None):
data = {
"app_id": self.appid,
"method": method,
"charset": "utf-8",
"sign_type": "RSA2",
"timestamp": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
"version": "1.0",
"biz_content": biz_content
}
if return_url is not None:
data["notify_url"] = self.app_notify_url
data["return_url"] = self.return_url
return data
def sign_data(self, data):
data.pop("sign", None)
# 排序后的字符串
unsigned_items = self.ordered_data(data)
unsigned_string = "&".join("{0}={1}".format(k, v) for k, v in unsigned_items)
sign = self.sign(unsigned_string.encode("utf-8"))
ordered_items = self.ordered_data(data)
quoted_string = "&".join("{0}={1}".format(k, quote_plus(v)) for k, v in ordered_items)
# 獲得最終的訂單信息字符串
signed_string = quoted_string + "&sign=" + quote_plus(sign)
return signed_string
def ordered_data(self, data):
complex_keys = []
for key, value in data.items():
if isinstance(value, dict):
complex_keys.append(key)
# 將字典類型的數(shù)據(jù)dump出來
for key in complex_keys:
data[key] = json.dumps(data[key], separators=(',', ':'))
return sorted([(k, v) for k, v in data.items()])
def sign(self, unsigned_string):
# 開始計算簽名
key = self.app_private_key
signer = PKCS1_v1_5.new(key)
signature = signer.sign(SHA256.new(unsigned_string))
# base64 編碼,轉(zhuǎn)換為unicode表示并移除回車
sign = encodebytes(signature).decode("utf8").replace("\n", "")
return sign
def _verify(self, raw_content, signature):
# 開始計算簽名
key = self.alipay_public_key
signer = PKCS1_v1_5.new(key)
digest = SHA256.new()
digest.update(raw_content.encode("utf8"))
if signer.verify(digest, decodebytes(signature.encode("utf8"))):
return True
return False
def verify(self, data, signature):
if "sign_type" in data:
sign_type = data.pop("sign_type")
# 排序后的字符串
unsigned_items = self.ordered_data(data)
message = "&".join(u"{}={}".format(k, v) for k, v in unsigned_items)
return self._verify(message, signature)
if __name__ == "__main__":
alipay = AliPay(
appid="2016081500252338",
app_notify_url="http://projectsedus.com/",
app_private_key_path="keys/private_2048.txt",
alipay_public_key_path="keys/alipay_key_2048.txt", # 支付寶的公鑰,驗證支付寶回傳消息使用,不是你自己的公鑰,
debug=True, # 默認(rèn)False,
return_url="http://192.168.247.129:8000/"
)
url = alipay.direct_pay(
subject="測試訂單",
out_trade_no="20170202126666",
total_amount=1000
)
re_url = "https://openapi.alipaydev.com/gateway.do?{data}".format(data=url)
print(re_url)
5、wxpay.py:
# -*- coding=utf-8 -*-
import time
import json
import hashlib
import requests
from pay.utils import (smart_str, dict_to_xml, calculate_sign, random_str,
post_xml, xml_to_dict, validate_post_xml, format_url)
# from local_settings import appid, mch_id, api_key
OAUTH2_AUTHORIZE_URL = "https://open.weixin.qq.com/connect/oauth2/authorize?%s"
OAUTH2_ACCESS_TOKEN_URL = "https://api.weixin.qq.com/sns/oauth2/access_token?%s"
class WeiXinPay(object):
def __init__(self, appid, mch_id, api_key):
self.appid = appid # 微信公眾號身份的唯一標(biāo)識。審核通過后,在微信發(fā)送的郵件中查看
self.mch_id = mch_id # 受理商ID,身份標(biāo)識
self.api_key = api_key # 商戶支付密鑰Key。審核通過后,在微信發(fā)送的郵件中查看
self.common_params = {
"appid": self.appid,
"mch_id": self.mch_id,
}
self.params = {}
self.url = ""
self.trade_type = ""
def set_params(self, **kwargs):
self.params = {}
for (k, v) in kwargs.items():
self.params[k] = smart_str(v)
self.params["nonce_str"] = random_str(32)
if self.trade_type:
self.params["trade_type"] = self.trade_type
self.params.update(self.common_params)
def post_xml(self):
sign = calculate_sign(self.params, self.api_key)
xml = dict_to_xml(self.params, sign)
response = post_xml(self.url, xml)
return xml_to_dict(response.text)
def valiate_xml(self, xml):
return validate_post_xml(xml, self.appid, self.mch_id, self.api_key)
def get_error_code_desc(self, error_code):
error_desc = {
"SYSTEMERROR": u"接口后臺錯誤",
"INVALID_TRANSACTIONID": u"無效 transaction_id",
"PARAM_ERROR": u"提交參數(shù)錯誤",
"ORDERPAID": u"訂單已支付",
"OUT_TRADE_NO_USED": u"商戶訂單號重復(fù)",
"NOAUTH": u"商戶無權(quán)限",
"NOTENOUGH": u"余額丌足",
"NOTSUPORTCARD": u"不支持卡類型",
"ORDERCLOSED": u"訂單已關(guān)閉",
"BANKERROR": u"銀行系統(tǒng)異常",
"REFUND_FEE_INVALID": u"退款金額大亍支付金額",
"ORDERNOTEXIST": u"訂單不存在",
}
return error_desc.get(error_code.strip().upper(), u"未知錯誤")
class UnifiedOrderPay(WeiXinPay):
"""發(fā)送預(yù)支付單"""
def __init__(self, appid, mch_id, api_key):
super(UnifiedOrderPay, self).__init__(appid, mch_id, api_key)
self.url = "https://api.mch.weixin.qq.com/pay/unifiedorder"
self.trade_type = "NATIVE"
def post(self, body, out_trade_no, total_fee, spbill_create_ip, notify_url, **kwargs):
tmp_kwargs = {
"body": body,
"out_trade_no": out_trade_no,
"total_fee": total_fee,
"spbill_create_ip": spbill_create_ip,
"notify_url": notify_url,
}
tmp_kwargs.update(**kwargs)
self.set_params(**tmp_kwargs)
return self.post_xml()[1]
class OrderQuery(WeiXinPay):
"""訂單狀態(tài)查詢"""
def __init__(self, appid, mch_id, api_key):
super(OrderQuery, self).__init__(appid, mch_id, api_key)
self.url = "https://api.mch.weixin.qq.com/pay/orderquery"
def post(self, out_trade_no):
self.set_params(out_trade_no=out_trade_no)
return self.post_xml()[1]
class JsAPIOrderPay(UnifiedOrderPay):
"""H5頁面的Js調(diào)用類"""
def __init__(self, appid, mch_id, api_key, app_secret):
super(JsAPIOrderPay, self).__init__(appid, mch_id, api_key)
self.app_secret = app_secret
self.trade_type = "JSAPI"
def create_oauth_url_for_code(self, redirect_uri):
url_params = {
"appid": self.appid,
"redirect_uri": redirect_uri, # 一般是回調(diào)當(dāng)前頁面
"response_type": "code",
"scope": "snsapi_base",
"state": "STATE#wechat_redirect"
}
url = format_url(url_params)
return OAUTH2_AUTHORIZE_URL % url
def _create_oauth_url_for_openid(self, code):
url_params = {
"appid": self.appid,
"secret": self.app_secret,
"code": code,
"grant_type": "authorization_code",
}
url = format_url(url_params)
return OAUTH2_ACCESS_TOKEN_URL % url
def _get_oauth_info(self, code):
"""
獲取OAuth2的信息:access_token、expires_in、refresh_token、openid、scope
返回結(jié)果為字典,可使用["xxx"]或.get("xxx", None)的方式進(jìn)行讀取
"""
url = self._create_oauth_url_for_openid(code)
response = requests.get(url)
return response.json() if response else None
def _get_openid(self, code):
oauth_info = self._get_oauth_info(code)
if oauth_info:
return oauth_info.get("openid", None)
return None
def _get_json_js_api_params(self, prepay_id):
js_params = {
"appId": self.appid,
"timeStamp": "%d" % time.time(),
"nonceStr": random_str(32),
"package": "prepay_id=%s" % prepay_id,
"signType": "MD5",
}
js_params["paySign"] = calculate_sign(js_params, self.api_key)
return js_params
def post(self, body, out_trade_no, total_fee, spbill_create_ip, notify_url, code):
if code:
open_id = self._get_openid(code)
if open_id:
# 直接調(diào)用基類的post方法查詢prepay_id,如果成功,返回一個字典
unified_order = super(JsAPIOrderPay, self).post(body, out_trade_no, total_fee, spbill_create_ip,
notify_url, open_id=open_id)
if unified_order:
prepay_id = unified_order.get("prepay_id", None)
if prepay_id:
return self._get_json_js_api_params(prepay_id)
return None
6、utils.py:
# -*- coding=utf-8 -*-
import hashlib
import re
import types
from random import Random
import requests
import thriftpy
from django.conf import settings
from django.core.exceptions import FieldDoesNotExist
from django.db import models
from django.db.models.fields.reverse_related import ForeignObjectRel
from rest_framework.pagination import PageNumberPagination
from thriftpy.rpc import make_client
from pay.exception_handler import ForeignObjectRelDeleteError, ModelDontHaveIsActiveFiled, logger
def smart_str(s, encoding='utf-8', strings_only=False, errors='strict'):
"""
Returns a bytestring version of 's', encoded as specified in 'encoding'.
If strings_only is True, don't convert (some) non-string-like objects.
"""
if strings_only and isinstance(s, (types.NoneType, int)):
return s
if not isinstance(s, str):
try:
return str(s)
except UnicodeEncodeError:
if isinstance(s, Exception):
# An Exception subclass containing non-ASCII data that doesn't
# know how to print itself properly. We shouldn't raise a
# further exception.
return ' '.join([smart_str(arg, encoding, strings_only,
errors) for arg in s])
return unicode(s).encode(encoding, errors)
elif s and encoding != 'utf-8':
return s.decode('utf-8', errors).encode(encoding, errors)
else:
return s
def format_url(params, api_key=None):
url = "&".join(['%s=%s' % (key, smart_str(params[key])) for key in sorted(params)])
if api_key:
url = '%s&key=%s' % (url, api_key)
return url
def calculate_sign(params, api_key):
# 簽名步驟一:按字典序排序參數(shù), 在string后加入KEY
url = format_url(params, api_key)
# 簽名步驟二:MD5加密, 所有字符轉(zhuǎn)為大寫
return hashlib.md5(url.encode('utf-8')).hexdigest().upper()
def dict_to_xml(params, sign):
xml = ["<xml>", ]
for (k, v) in params.items():
if (v.isdigit()):
xml.append('<%s>%s</%s>' % (k, v, k))
else:
xml.append('<%s><![CDATA[%s]]></%s>' % (k, v, k))
xml.append('<sign><![CDATA[%s]]></sign></xml>' % sign)
return ''.join(xml)
def xml_to_dict(xml):
if xml[0:5].upper() != "<XML>" and xml[-6].upper() != "</XML>":
return None, None
result = {}
sign = None
content = ''.join(xml[5:-6].strip().split('\n'))
pattern = re.compile(r"<(?P<key>.+)>(?P<value>.+)</(?P=key)>")
m = pattern.match(content)
while (m):
key = m.group("key").strip()
value = m.group("value").strip()
if value != "<![CDATA[]]>":
pattern_inner = re.compile(r"<!\[CDATA\[(?P<inner_val>.+)\]\]>")
inner_m = pattern_inner.match(value)
if inner_m:
value = inner_m.group("inner_val").strip()
if key == "sign":
sign = value
else:
result[key] = value
next_index = m.end("value") + len(key) + 3
if next_index >= len(content):
break
content = content[next_index:]
m = pattern.match(content)
return sign, result
def validate_post_xml(xml, appid, mch_id, api_key):
sign, params = xml_to_dict(xml)
if (not sign) or (not params):
return None
remote_sign = calculate_sign(params, api_key)
if sign != remote_sign:
return None
if params["appid"] != appid or params["mch_id"] != mch_id:
return None
return params
def random_str(randomlength=8):
chars = 'abcdefghijklmnopqrstuvwxyz0123456789'
random = Random()
return "".join([chars[random.randint(0, len(chars) - 1)] for i in range(randomlength)])
def post_xml(url, xml):
return requests.post(url, data=xml.encode('utf-8'), verify=False)
class UnActiveModelMixin(object):
"""
刪除一個對象,并不真刪除,級聯(lián)將對應(yīng)外鍵對象的is_active設(shè)置為false,需要外鍵對象都有is_active字段.
"""
def perform_destroy(self, instance):
rel_fileds = [f for f in instance._meta.get_fields() if isinstance(f, ForeignObjectRel)]
links = [f.get_accessor_name() for f in rel_fileds]
for link in links:
manager = getattr(instance, link, None)
if not manager:
continue
if isinstance(manager, models.Model):
if hasattr(manager, 'is_active') and manager.is_active:
manager.is_active = False
manager.save()
raise ForeignObjectRelDeleteError(u'{} 上有關(guān)聯(lián)數(shù)據(jù)'.format(link))
else:
if not manager.count():
continue
try:
manager.model._meta.get_field('is_active')
manager.filter(is_active=True).update(is_active=False)
except FieldDoesNotExist as ex:
# 理論上,級聯(lián)刪除的model上面應(yīng)該也有is_active字段,否則代碼邏輯應(yīng)該有問題
logger.warn(ex)
raise ModelDontHaveIsActiveFiled(
'{}.{} 沒有is_active字段, 請檢查程序邏輯'.format(
manager.model.__module__,
manager.model.__class__.__name__
))
instance.is_active = False
instance.save()
def get_queryset(self):
return self.queryset.filter(is_active=True)
class StandardResultsSetPagination(PageNumberPagination):
page_size_query_param = 'size'
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
用python結(jié)合jieba和wordcloud實現(xiàn)詞云效果
詞云,顧名思義就是很多個單詞,然后通過出現(xiàn)的頻率或者比重之類的標(biāo)準(zhǔn)匯聚成一個云朵的樣子嘛,其實呢現(xiàn)在網(wǎng)上已經(jīng)有很多能自動生成詞云的工具了,比如Wordle,Tagxedo等等,Python也能實現(xiàn)這樣的效果,我們通過jieba庫和wordcloud庫也能十分輕松的完成詞云的構(gòu)建2017-09-09
python開發(fā)實例之Python的Twisted框架中Deferred對象的詳細(xì)用法與實例
這篇文章主要介紹了python開發(fā)實例之Python的Twisted框架中Deferred對象的詳細(xì)用法與實例,需要的朋友可以參考下2020-03-03
Python數(shù)據(jù)可視化圖實現(xiàn)過程詳解
這篇文章主要介紹了Python數(shù)據(jù)可視化圖實現(xiàn)過程詳解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2020-06-06
python?通過dict(zip)和{}的方式構(gòu)造字典的方法
在python中,通常通過dict和zip組合來構(gòu)建鍵值對,這篇文章主要介紹了python?通過dict(zip)和{}的方式構(gòu)造字典的方法,需要的朋友可以參考下2022-07-07
安裝pyhttpx解決ImportError: DLL load failed錯誤
這篇文章主要為大家介紹了安裝pyhttpx解決ImportError: DLL load failed錯誤,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-08-08
PyCharm新建.py文件時默認(rèn)添加信息的實現(xiàn)
這篇文章主要介紹了PyCharm新建.py文件時默認(rèn)添加信息的實現(xiàn)方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-07-07
Python 如何定義匿名或內(nèi)聯(lián)函數(shù)
這篇文章主要介紹了Python 如何定義匿名或內(nèi)聯(lián)函數(shù),文中講解非常細(xì)致,代碼幫助大家更好的理解和學(xué)習(xí),感興趣的朋友可以了解下2020-08-08

