├── mysite ├── __init__.py ├── urls.py ├── wsgi.py └── settings.py ├── wechat ├── __init__.py ├── models.py ├── tests.py ├── urls.py ├── views.py ├── wechatEvent.py ├── wechatUtil.py ├── wechatService.py ├── wechatMessage.py └── wechatReply.py ├── .gitignore ├── requirements.txt ├── config.yaml ├── index.wsgi ├── manage.py ├── README.md └── LICENSE /mysite/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /wechat/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | *.DS_Store 3 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | requests 2 | django 3 | lxml 4 | -------------------------------------------------------------------------------- /wechat/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | 3 | # Create your models here. 4 | -------------------------------------------------------------------------------- /config.yaml: -------------------------------------------------------------------------------- 1 | libraries: 2 | - name: "django" 3 | version: "1.4" 4 | 5 | - name: lxml 6 | version: "2.3.4" 7 | -------------------------------------------------------------------------------- /index.wsgi: -------------------------------------------------------------------------------- 1 | import sae 2 | from mysite import wsgi 3 | 4 | application = sae.create_wsgi_app(wsgi.application) 5 | -------------------------------------------------------------------------------- /manage.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import os 3 | import sys 4 | 5 | if __name__ == "__main__": 6 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mysite.settings") 7 | 8 | from django.core.management import execute_from_command_line 9 | 10 | execute_from_command_line(sys.argv) 11 | -------------------------------------------------------------------------------- /wechat/tests.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | """ 3 | # Author: Pegasus Wang (pegasuswang@qq.com, http://ningning.today) 4 | # Created Time : Tue Mar 3 19:44:02 2015 5 | 6 | # File Name: tests.py 7 | # Description: 8 | 9 | """ 10 | import requests 11 | import codecs 12 | 13 | f = codecs.open(u'post.xml', u'r', u'utf-8') 14 | content = u''.join(f.readlines()) 15 | f.close() 16 | 17 | res = requests.post(u'http://2.pegasuswang.sinaapp.com/wechat/', data=content.encode(u'utf-8')) 18 | print res.text 19 | -------------------------------------------------------------------------------- /wechat/urls.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | """ 3 | # Author: Pegasus Wang (pegasuswang@qq.com, http://ningning.today) 4 | # Created Time : Fri Feb 20 22:31:30 2015 5 | 6 | # File Name: urls.py 7 | # Description: 8 | 9 | # :copyright: (c) 2015 by Pegasus Wang. 10 | # :license: MIT, see LICENSE for more details. 11 | """ 12 | from django.conf.urls import patterns, url 13 | from django.views.decorators.csrf import csrf_exempt 14 | from wechat import views 15 | 16 | 17 | urlpatterns = patterns('', 18 | url(r'^$', csrf_exempt(views.WechatInterfaceView.as_view())), 19 | ) -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ###WeiPython 2 | python2.7+django1.4。 3 | 封装了微信开发需要的一些类和函数,包括三种消息类,xml文件的解析和生成, json解析等。 4 | 你可以在此基础上开发练手。你只需要克隆代码,然后实现wechatService.py里的processRequest方法就可以根据不同消息类型回复。目前实现的是调用[图灵机器人](http://www.tuling123.com/openapi/)自动回复,可以实现翻译,查询天气,简单聊天等功能。(初学python时练手的,代码非常不pythonic,慎用代码) 5 | 6 | ###Step 7 | - Clone this reposity: `git clone https://github.com/PegasusWang/WeiPython.git` 8 | - Write your own processRequest in wechatService.py 9 | - upload your code to sae or bae server. 10 | 11 | ###[Tutorial](http://ningning.today/2015/02/21/python/django-python%E5%BE%AE%E4%BF%A1%E5%BC%80%E5%8F%91%E4%B9%8B%E4%B8%80%EF%BC%8D%E5%87%86%E5%A4%87%E5%B7%A5%E4%BD%9C/) 12 | -------------------------------------------------------------------------------- /mysite/urls.py: -------------------------------------------------------------------------------- 1 | from django.conf.urls import patterns, include, url 2 | 3 | # Uncomment the next two lines to enable the admin: 4 | # from django.contrib import admin 5 | # admin.autodiscover() 6 | 7 | urlpatterns = patterns('', 8 | # Examples: 9 | # url(r'^$', 'mysite.views.home', name='home'), 10 | # url(r'^mysite/', include('mysite.foo.urls')), 11 | 12 | # Uncomment the admin/doc line below to enable admin documentation: 13 | # url(r'^admin/doc/', include('django.contrib.admindocs.urls')), 14 | 15 | # Uncomment the next line to enable the admin: 16 | # url(r'^admin/', include(admin.site.urls)), 17 | url(r'^wechat/', include('wechat.urls', namespace='wechat')), 18 | ) 19 | -------------------------------------------------------------------------------- /wechat/views.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | """ 3 | # Author: Pegasus Wang (pegasuswang@qq.com, http://ningning.today) 4 | # Created Time : Wed Feb 18 18:18:10 2015 5 | 6 | # File Name: views.py 7 | # Description: 8 | 9 | # :copyright: (c) 2015 by Pegasus Wang. 10 | # :license: MIT, see LICENSE for more details. 11 | """ 12 | # Create your views here. 13 | from django.http import HttpResponse 14 | from django.views.generic.base import View 15 | from .wechatUtil import checkSignature 16 | from .wechatService import WechatService 17 | 18 | 19 | class WechatInterfaceView(View): 20 | 21 | def get(self, request): 22 | echostr = request.GET.get(u'echostr', None) 23 | if checkSignature(request): 24 | return HttpResponse(echostr) 25 | 26 | def post(self, request): 27 | return HttpResponse(WechatService.processRequest(request)) 28 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Pegasus Wang 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /mysite/wsgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | WSGI config for mysite project. 3 | 4 | This module contains the WSGI application used by Django's development server 5 | and any production WSGI deployments. It should expose a module-level variable 6 | named ``application``. Django's ``runserver`` and ``runfcgi`` commands discover 7 | this application via the ``WSGI_APPLICATION`` setting. 8 | 9 | Usually you will have the standard Django WSGI application here, but it also 10 | might make sense to replace the whole Django WSGI application with a custom one 11 | that later delegates to the Django one. For example, you could introduce WSGI 12 | middleware here, or combine a Django application with an application of another 13 | framework. 14 | 15 | """ 16 | import os 17 | 18 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mysite.settings") 19 | 20 | # This application object is used by any WSGI server configured to use this 21 | # file. This includes Django's development server, if the WSGI_APPLICATION 22 | # setting points here. 23 | from django.core.wsgi import get_wsgi_application 24 | application = get_wsgi_application() 25 | 26 | # Apply WSGI middleware here. 27 | # from helloworld.wsgi import HelloWorldApplication 28 | # application = HelloWorldApplication(application) 29 | -------------------------------------------------------------------------------- /wechat/wechatEvent.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | """ 3 | # Author: Pegasus Wang (pegasuswang@qq.com, http://ningning.today) 4 | # Created Time : Wed Feb 18 18:29:06 2015 5 | 6 | # File Name: wechatEvent.py 7 | # Description: 8 | 9 | # :copyright: (c) 2015 by Pegasus Wang. 10 | # :license: MIT, see LICENSE for more details. 11 | """ 12 | 13 | 14 | class BaseEvent(object): 15 | """base event class""" 16 | def __init__(self): 17 | self.ToUserName = u'' 18 | self.FromUserName = u'' 19 | self.CreateTime = 0L 20 | self.MsgType = u'' 21 | self.Event = u'' 22 | 23 | def getToUserName(self): 24 | return self.ToUserName 25 | 26 | def setToUserName(self, toUserName): 27 | self.ToUserName = toUserName 28 | 29 | def getFromUserName(self): 30 | return self.FromUserName 31 | 32 | def setFromUserName(self, fromUserName): 33 | self.FromUserName = fromUserName 34 | 35 | def getCreateTime(self): 36 | return self.CreateTime 37 | 38 | def setCreateTime(self, createTime): 39 | self.CreateTime = createTime 40 | 41 | def getMsgType(self): 42 | return self.MsgType 43 | 44 | def setMsgType(self, msgType): 45 | self.MsgType = msgType 46 | 47 | def getEvent(self): 48 | return self.Event 49 | 50 | def setMsgId(self, event): 51 | self.Event = event 52 | 53 | 54 | class SubscribeEvent(BaseEvent): 55 | """subscribe event class""" 56 | def __init__(self): 57 | super(SubscribeEvent, self).__init__() 58 | 59 | 60 | class QRCodeEvent(BaseEvent): 61 | """scan QR code event class""" 62 | def __init__(self): 63 | super(QRCodeEvent, self).__init__() 64 | self.EventKey = u'' 65 | self.Ticket = u'' 66 | 67 | def getEventKey(self): 68 | return self.EventKey 69 | 70 | def setEventKey(self, eventKey): 71 | self.EventKey = eventKey 72 | 73 | def getTicket(self): 74 | return self.Ticket 75 | 76 | def setTicket(self, ticket): 77 | self.Ticket = ticket 78 | 79 | 80 | class LocationEvent(BaseEvent): 81 | """upload location event class""" 82 | def __init__(self): 83 | super(LocationEvent, self).__init__() 84 | self.Latitude = u'' 85 | self.Longitude = u'' 86 | self.Precision = u'' 87 | 88 | def getLatitude(self): 89 | return self.Latitude 90 | 91 | def setLatitude(self, latitude): 92 | self.Latitude = latitude 93 | 94 | def getLongitude(self): 95 | return self.Longitude 96 | 97 | def setLongitude(self, longtitude): 98 | self.Longitude = longtitude 99 | 100 | def getPrecision(self): 101 | return self.Precision 102 | 103 | def setPrecision(self, precision): 104 | self.Precision = precision 105 | 106 | 107 | class MenuEvent(BaseEvent): 108 | """customize menu class""" 109 | def __init__(self): 110 | super(MenuEvent, self).__init__() 111 | self.EventKey = u'' 112 | 113 | def getEventKey(self): 114 | return self.EventKey 115 | 116 | def setEventKey(self, eventKey): 117 | self.EventKey = eventKey 118 | -------------------------------------------------------------------------------- /wechat/wechatUtil.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | """ 3 | # Author: Pegasus Wang (pegasuswang@qq.com, http://ningning.today) 4 | # Created Time : Wed Feb 18 18:18:10 2015 5 | 6 | # File Name: wechatUtil.py 7 | # Description: 8 | 9 | # :copyright: (c) 2015 by Pegasus Wang. 10 | # :license: MIT, see LICENSE for more details. 11 | """ 12 | 13 | import hashlib 14 | from lxml import etree 15 | 16 | 17 | def checkSignature(request): 18 | """check signature. 19 | 20 | :param request: get method 21 | :return: if success return True else False 22 | """ 23 | signature = request.GET.get(u'signature', None) 24 | timestamp = request.GET.get(u'timestamp', None) 25 | nonce = request.GET.get(u'nonce', None) 26 | token = u'pegasuswang' # your wechat token 27 | 28 | tmplist = [token, timestamp, nonce] 29 | tmplist.sort() 30 | tmpstr = '%s%s%s' % tuple(tmplist) 31 | tmpstr = hashlib.sha1(tmpstr).hexdigest() 32 | 33 | if tmpstr == signature: 34 | return True 35 | else: 36 | return False 37 | 38 | 39 | class MessageUtil(object): 40 | """MessageUtil has some methods to process message.""" 41 | # request message types 42 | REQ_MESSAGE_TYPE_TEXT = u'text' 43 | REQ_MESSAGE_TYPE_IMAGE = u'image' 44 | REQ_MESSAGE_TYPE_VOICE = u'voice' 45 | REQ_MESSAGE_TYPE_VIDEO = u'video' 46 | REQ_MESSAGE_TYPE_LOCATION = u'location' 47 | REQ_MESSAGE_TYPE_LINK = u'link' 48 | REQ_MESSAGE_TYPE_EVENT = u'event' 49 | 50 | # event types 51 | EVENT_TYPE_SUBSCRIBE = u'subscribe' 52 | EVENT_TYPE_UNSUBSCRIBE = u'unsubscribe' 53 | EVENT_TYPE_SCAN = u'scan' 54 | EVENT_TYPE_LOCATION = u'LOCATION' 55 | EVENT_TYPE_CLICK = u'CLICK' 56 | 57 | # reply message types 58 | RESP_MESSAGE_TYPE_TEXT = u'text' 59 | RESP_MESSAGE_TYPE_IMAGE = u'image' 60 | RESP_MESSAGE_TYPE_VOICE = u'voice' 61 | RESP_MESSAGE_TYPE_VIDEO = u'video' 62 | RESP_MESSAGE_TYPE_MUSIC = u'music' 63 | RESP_MESSAGE_TYPE_NEWS = u'news' 64 | 65 | # message types 66 | MESSAGETYPE = [u'Image', u'Voice', u'Video', u'Music', u'Articles'] 67 | 68 | @staticmethod 69 | def parseXml(request): 70 | """parse request post xml message. 71 | 72 | :param request: post request 73 | :return: dict of xml message 74 | """ 75 | raw_xml = request.body.decode(u'UTF-8') 76 | xmlstr = etree.fromstring(raw_xml) 77 | dict_xml = {} 78 | for child in xmlstr: 79 | dict_xml[child.tag] = child.text.encode(u'UTF-8') # note 80 | return dict_xml 81 | 82 | 83 | 84 | @staticmethod 85 | def class2xml(obj): 86 | """convert reply message class to xml. 87 | 88 | :param obj: reply message class' object 89 | :return: xml of the object 90 | """ 91 | root = etree.Element(u'xml') 92 | for key, value in vars(obj).items(): 93 | if key in MessageUtil.MESSAGETYPE: 94 | tmproot = etree.SubElement(root, key) 95 | if key == u'Articles': # solve Article, it's special 96 | for eachArticle in value: 97 | etree.SubElement(tmproot, u'item') 98 | for tmpkey, tmpvalue in vars(eachArticle).items(): 99 | tmpkey_ele = etree.SubElement(tmproot, tmpkey) 100 | tmpkey_ele.text = etree.CDATA(unicode(tmpvalue)) 101 | else: 102 | for tmpkey, tmpvalue in vars(obj.__getattribute__(key)).items(): 103 | tmpkey_ele = etree.SubElement(tmproot, tmpkey) 104 | if u'time' in tmpkey.lower() or u'count' in tmpkey.lower(): 105 | tmpkey_ele.text = unicode(tmpvalue) 106 | else: # CDATA tag for str 107 | tmpkey_ele.text = etree.CDATA(unicode(tmpvalue)) 108 | else: 109 | if u'time' in key.lower() or u'count' in key.lower(): 110 | etree.SubElement(root, key).text = unicode(value) 111 | else: 112 | etree.SubElement(root, key).text = etree.CDATA(unicode(value)) 113 | 114 | return etree.tostring(root, pretty_print=True, xml_declaration=False, encoding=u'utf-8') 115 | -------------------------------------------------------------------------------- /wechat/wechatService.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | """ 3 | # Author: Pegasus Wang (pegasuswang@qq.com, http://ningning.today) 4 | # Created Time : Fri Feb 20 21:38:57 2015 5 | 6 | # File Name: wechatService.py 7 | # Description: 8 | 9 | # :copyright: (c) 2015 by Pegasus Wang. 10 | # :license: MIT, see LICENSE for more details. 11 | """ 12 | 13 | import json 14 | import time 15 | import urllib 16 | import urllib2 17 | 18 | from wechatUtil import MessageUtil 19 | from wechatReply import TextReply 20 | 21 | class RobotService(object): 22 | """Auto reply robot service""" 23 | KEY = 'd92d20bc1d8bb3cff585bf746603b2a9' 24 | url = 'http://www.tuling123.com/openapi/api' 25 | @staticmethod 26 | def auto_reply(req_info): 27 | query = {'key': RobotService.KEY, 'info': req_info.encode('utf-8')} 28 | headers = {'Content-type': 'text/html', 'charset': 'utf-8'} 29 | data = urllib.urlencode(query) 30 | req = urllib2.Request(RobotService.url, data) 31 | f = urllib2.urlopen(req).read() 32 | return json.loads(f).get('text').replace('
', '\n') 33 | #return json.loads(f).get('text') 34 | 35 | 36 | class WechatService(object): 37 | """process request""" 38 | @staticmethod 39 | def processRequest(request): 40 | """process different message types. 41 | 42 | :param request: post request message 43 | :return: None 44 | """ 45 | requestMap = MessageUtil.parseXml(request) 46 | fromUserName = requestMap.get(u'FromUserName') 47 | toUserName = requestMap.get(u'ToUserName') 48 | createTime = requestMap.get(u'CreateTime') 49 | msgType = requestMap.get(u'MsgType') 50 | msgId = requestMap.get(u'MsgId') 51 | 52 | textReply = TextReply() 53 | textReply.setToUserName(fromUserName) 54 | textReply.setFromUserName(toUserName) 55 | textReply.setCreateTime(time.time()) 56 | textReply.setMsgType(MessageUtil.RESP_MESSAGE_TYPE_TEXT) 57 | 58 | if msgType == MessageUtil.REQ_MESSAGE_TYPE_TEXT: 59 | content = requestMap.get('Content').decode('utf-8') # note: decode first 60 | #respContent = u'您发送的是文本消息:' + content 61 | respContent = RobotService.auto_reply(content) 62 | elif msgType == MessageUtil.REQ_MESSAGE_TYPE_IMAGE: 63 | respContent = u'您发送的是图片消息!' 64 | elif msgType == MessageUtil.REQ_MESSAGE_TYPE_VOICE: 65 | respContent = u'您发送的是语音消息!' 66 | elif msgType == MessageUtil.REQ_MESSAGE_TYPE_VIDEO: 67 | respContent = u'您发送的是视频消息!' 68 | elif msgType == MessageUtil.REQ_MESSAGE_TYPE_LOCATION: 69 | respContent = u'您发送的是地理位置消息!' 70 | elif msgType == MessageUtil.REQ_MESSAGE_TYPE_LINK: 71 | respContent = u'您发送的是链接消息!' 72 | elif msgType == MessageUtil.REQ_MESSAGE_TYPE_EVENT: 73 | eventType = requestMap.get(u'Event') 74 | if eventType == MessageUtil.EVENT_TYPE_SUBSCRIBE: 75 | respContent = u'^_^谢谢您的关注,本公众号由王宁宁开发(python2.7+django1.4),如果你有兴趣继续开发,' \ 76 | u'可以联系我,就当打发时间了.' 77 | elif eventType == MessageUtil.EVENT_TYPE_UNSUBSCRIBE: 78 | pass 79 | elif eventType == MessageUtil.EVENT_TYPE_SCAN: 80 | # TODO 81 | pass 82 | elif eventType == MessageUtil.EVENT_TYPE_LOCATION: 83 | # TODO 84 | pass 85 | elif eventType == MessageUtil.EVENT_TYPE_CLICK: 86 | # TODO 87 | pass 88 | 89 | textReply.setContent(respContent) 90 | respXml = MessageUtil.class2xml(textReply) 91 | 92 | return respXml 93 | 94 | 95 | 96 | """ 97 | if msgType == 'text': 98 | content = requestMap.get('Content') 99 | # TODO 100 | 101 | elif msgType == 'image': 102 | picUrl = requestMap.get('PicUrl') 103 | # TODO 104 | 105 | elif msgType == 'voice': 106 | mediaId = requestMap.get('MediaId') 107 | format = requestMap.get('Format') 108 | # TODO 109 | 110 | elif msgType == 'video': 111 | mediaId = requestMap.get('MediaId') 112 | thumbMediaId = requestMap.get('ThumbMediaId') 113 | # TODO 114 | 115 | elif msgType == 'location': 116 | lat = requestMap.get('Location_X') 117 | lng = requestMap.get('Location_Y') 118 | label = requestMap.get('Label') 119 | scale = requestMap.get('Scale') 120 | # TODO 121 | 122 | elif msgType == 'link': 123 | title = requestMap.get('Title') 124 | description = requestMap.get('Description') 125 | url = requestMap.get('Url') 126 | """ 127 | -------------------------------------------------------------------------------- /wechat/wechatMessage.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | """ 3 | # Author: Pegasus Wang (pegasuswang@qq.com, http://ningning.today) 4 | # Created Time : Wed Feb 18 18:18:10 2015 5 | 6 | # File Name: wechatMessage.py 7 | # Description: 8 | 9 | # :copyright: (c) 2015 by Pegasus Wang. 10 | # :license: MIT, see LICENSE for more details. 11 | """ 12 | 13 | 14 | class BaseMessage(object): 15 | """base message class""" 16 | def __init__(self): 17 | self.ToUserName = u'' 18 | self.FromUserName = u'' 19 | self.CreateTime = 0L 20 | self.MsgType = u'' 21 | self.MsgId = 0L 22 | 23 | def getToUserName(self): 24 | return self.ToUserName 25 | 26 | def setToUserName(self, toUserName): 27 | self.ToUserName = toUserName 28 | 29 | def getFromUserName(self): 30 | return self.FromUserName 31 | 32 | def setFromUserName(self, fromUserName): 33 | self.FromUserName = fromUserName 34 | 35 | def getCreateTime(self): 36 | return self.CreateTime 37 | 38 | def setCreateTime(self, createTime): 39 | self.CreateTime = createTime 40 | 41 | def getMsgType(self): 42 | return self.MsgType 43 | 44 | def setMsgType(self, msgType): 45 | self.MsgType = msgType 46 | 47 | def getMsgId(self): 48 | return self.MsgId 49 | 50 | def setMsgId(self, msgId): 51 | self.MsgId = msgId 52 | 53 | 54 | class TextMessage(BaseMessage): 55 | """text message class""" 56 | def __init__(self): 57 | super(TextMessage, self).__init__() 58 | self.Content = u'' 59 | 60 | def getContent(self): 61 | return self.Content 62 | 63 | def setContent(self, content): 64 | self.Content = content 65 | 66 | 67 | class ImageMessage(BaseMessage): 68 | """image message class""" 69 | def __init__(self): 70 | super(ImageMessage, self).__init__() 71 | self.PicUrl = u'' 72 | 73 | def getPicUrl(self): 74 | return self.PicUrl 75 | 76 | def setPicUrl(self, picUrl): 77 | self.PicUrl = picUrl 78 | 79 | 80 | class VoiceMessage(BaseMessage): 81 | """voice message class""" 82 | def __init__(self): 83 | super(VoiceMessage, self).__init__() 84 | self.MediaId = u'' 85 | self.Format = u'' 86 | self.Recognition = u'' 87 | 88 | def getMediaId(self): 89 | return self.MediaId 90 | 91 | def setMediaId(self, mediaId): 92 | self.MediaId = mediaId 93 | 94 | def getFormat(self): 95 | return self.Format 96 | 97 | def setFormat(self, format): 98 | self.Format = format 99 | 100 | def getRecognition(self): 101 | return self.Recognition 102 | 103 | def setRecognition(self, recognition): 104 | self.Recognition = recognition 105 | 106 | 107 | class VideoMessage(BaseMessage): 108 | """video message class""" 109 | def __init__(self): 110 | super(VideoMessage, self).__init__() 111 | self.MediaId = u'' 112 | self.ThumbMediaId = u'' 113 | 114 | def getMediaId(self): 115 | return self.MediaId 116 | 117 | def setMediaId(self, mediaId): 118 | self.MediaId = mediaId 119 | 120 | def getThumbMediaId(self): 121 | return self.ThumbMediaId 122 | 123 | def setThumbMediaId(self, thumbMediaId): 124 | self.ThumbMediaId = thumbMediaId 125 | 126 | 127 | class LocationMessage(BaseMessage): 128 | """location message class""" 129 | def __init__(self): 130 | super(LocationMessage, self).__init__() 131 | self.Location_X = u'' 132 | self.Location_Y = u'' 133 | self.Scale = u'' 134 | self.Label = u'' 135 | 136 | def getLocation_X(self): 137 | return self.Location_X 138 | 139 | def setLocation_X(self, location_X): 140 | self.Location_X = location_X 141 | 142 | def getLocation_Y(self): 143 | return self.Location_Y 144 | 145 | def setLocation_Y(self, location_Y): 146 | self.Location_Y = location_Y 147 | 148 | def getScale(self): 149 | return self.Scale 150 | 151 | def setScale(self, scale): 152 | self.Scale = scale 153 | 154 | def getLabel(self): 155 | return self.Label 156 | 157 | def setLabel(self, label): 158 | self.Label = label 159 | 160 | 161 | class LinkMessage(BaseMessage): 162 | """link message class""" 163 | def __init__(self): 164 | super(LinkMessage, self).__init__() 165 | self.Title = u'' 166 | self.Description = u'' 167 | self.Url = u'' 168 | 169 | def getTitle(self): 170 | return self.Title 171 | 172 | def setTitle(self, title): 173 | self.Title = title 174 | 175 | def getDescription(self): 176 | return self.Description 177 | 178 | def setDescription(self, description): 179 | self.Description = description 180 | 181 | def getUrl(self): 182 | return self.Url 183 | 184 | def setUrl(self, url): 185 | self.Url = url 186 | -------------------------------------------------------------------------------- /mysite/settings.py: -------------------------------------------------------------------------------- 1 | # Django settings for mysite project. 2 | 3 | DEBUG = True 4 | TEMPLATE_DEBUG = DEBUG 5 | 6 | ADMINS = ( 7 | # ('Your Name', 'your_email@example.com'), 8 | ) 9 | 10 | MANAGERS = ADMINS 11 | 12 | DATABASES = { 13 | 'default': { 14 | 'ENGINE': 'django.db.backends.', # Add 'postgresql_psycopg2', 'mysql', 'sqlite3' or 'oracle'. 15 | 'NAME': '', # Or path to database file if using sqlite3. 16 | 'USER': '', # Not used with sqlite3. 17 | 'PASSWORD': '', # Not used with sqlite3. 18 | 'HOST': '', # Set to empty string for localhost. Not used with sqlite3. 19 | 'PORT': '', # Set to empty string for default. Not used with sqlite3. 20 | } 21 | } 22 | 23 | # Local time zone for this installation. Choices can be found here: 24 | # http://en.wikipedia.org/wiki/List_of_tz_zones_by_name 25 | # although not all choices may be available on all operating systems. 26 | # On Unix systems, a value of None will cause Django to use the same 27 | # timezone as the operating system. 28 | # If running in a Windows environment this must be set to the same as your 29 | # system time zone. 30 | TIME_ZONE = 'Asia/Shanghai' 31 | 32 | # Language code for this installation. All choices can be found here: 33 | # http://www.i18nguy.com/unicode/language-identifiers.html 34 | LANGUAGE_CODE = 'zh-cn' 35 | 36 | SITE_ID = 1 37 | 38 | # If you set this to False, Django will make some optimizations so as not 39 | # to load the internationalization machinery. 40 | USE_I18N = True 41 | 42 | # If you set this to False, Django will not format dates, numbers and 43 | # calendars according to the current locale. 44 | USE_L10N = True 45 | 46 | # If you set this to False, Django will not use timezone-aware datetimes. 47 | USE_TZ = True 48 | 49 | # Absolute filesystem path to the directory that will hold user-uploaded files. 50 | # Example: "/home/media/media.lawrence.com/media/" 51 | MEDIA_ROOT = '' 52 | 53 | # URL that handles the media served from MEDIA_ROOT. Make sure to use a 54 | # trailing slash. 55 | # Examples: "http://media.lawrence.com/media/", "http://example.com/media/" 56 | MEDIA_URL = '' 57 | 58 | # Absolute path to the directory static files should be collected to. 59 | # Don't put anything in this directory yourself; store your static files 60 | # in apps' "static/" subdirectories and in STATICFILES_DIRS. 61 | # Example: "/home/media/media.lawrence.com/static/" 62 | STATIC_ROOT = '' 63 | 64 | # URL prefix for static files. 65 | # Example: "http://media.lawrence.com/static/" 66 | STATIC_URL = '/static/' 67 | 68 | # Additional locations of static files 69 | STATICFILES_DIRS = ( 70 | # Put strings here, like "/home/html/static" or "C:/www/django/static". 71 | # Always use forward slashes, even on Windows. 72 | # Don't forget to use absolute paths, not relative paths. 73 | ) 74 | 75 | # List of finder classes that know how to find static files in 76 | # various locations. 77 | STATICFILES_FINDERS = ( 78 | 'django.contrib.staticfiles.finders.FileSystemFinder', 79 | 'django.contrib.staticfiles.finders.AppDirectoriesFinder', 80 | # 'django.contrib.staticfiles.finders.DefaultStorageFinder', 81 | ) 82 | 83 | # Make this unique, and don't share it with anybody. 84 | SECRET_KEY = '&gd+bs(3q^_f_^4hlq(-gvo3t3rrd+nse!4j4^em)ttmsmwdm-' 85 | 86 | # List of callables that know how to import templates from various sources. 87 | TEMPLATE_LOADERS = ( 88 | 'django.template.loaders.filesystem.Loader', 89 | 'django.template.loaders.app_directories.Loader', 90 | # 'django.template.loaders.eggs.Loader', 91 | ) 92 | 93 | MIDDLEWARE_CLASSES = ( 94 | 'django.middleware.common.CommonMiddleware', 95 | 'django.contrib.sessions.middleware.SessionMiddleware', 96 | 'django.middleware.csrf.CsrfViewMiddleware', 97 | 'django.contrib.auth.middleware.AuthenticationMiddleware', 98 | 'django.contrib.messages.middleware.MessageMiddleware', 99 | # Uncomment the next line for simple clickjacking protection: 100 | # 'django.middleware.clickjacking.XFrameOptionsMiddleware', 101 | ) 102 | 103 | ROOT_URLCONF = 'mysite.urls' 104 | 105 | # Python dotted path to the WSGI application used by Django's runserver. 106 | WSGI_APPLICATION = 'mysite.wsgi.application' 107 | 108 | TEMPLATE_DIRS = ( 109 | # Put strings here, like "/home/html/django_templates" or "C:/www/django/templates". 110 | # Always use forward slashes, even on Windows. 111 | # Don't forget to use absolute paths, not relative paths. 112 | ) 113 | 114 | INSTALLED_APPS = ( 115 | 'django.contrib.auth', 116 | 'django.contrib.contenttypes', 117 | 'django.contrib.sessions', 118 | 'django.contrib.sites', 119 | 'django.contrib.messages', 120 | 'django.contrib.staticfiles', 121 | 'wechat', # my wechat app 122 | # Uncomment the next line to enable the admin: 123 | # 'django.contrib.admin', 124 | # Uncomment the next line to enable admin documentation: 125 | # 'django.contrib.admindocs', 126 | ) 127 | 128 | # A sample logging configuration. The only tangible logging 129 | # performed by this configuration is to send an email to 130 | # the site admins on every HTTP 500 error when DEBUG=False. 131 | # See http://docs.djangoproject.com/en/dev/topics/logging for 132 | # more details on how to customize your logging configuration. 133 | LOGGING = { 134 | 'version': 1, 135 | 'disable_existing_loggers': False, 136 | 'filters': { 137 | 'require_debug_false': { 138 | '()': 'django.utils.log.RequireDebugFalse' 139 | } 140 | }, 141 | 'handlers': { 142 | 'mail_admins': { 143 | 'level': 'ERROR', 144 | 'filters': ['require_debug_false'], 145 | 'class': 'django.utils.log.AdminEmailHandler' 146 | } 147 | }, 148 | 'loggers': { 149 | 'django.request': { 150 | 'handlers': ['mail_admins'], 151 | 'level': 'ERROR', 152 | 'propagate': True, 153 | }, 154 | } 155 | } 156 | -------------------------------------------------------------------------------- /wechat/wechatReply.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | """ 3 | # Author: Pegasus Wang (pegasuswang@qq.com, http://ningning.today) 4 | # Created Time : Wed Feb 18 18:58:39 2015 5 | 6 | # File Name: wechatReply.py 7 | # Description: 8 | 9 | # :copyright: (c) 2015 by Pegasus Wang. 10 | # :license: MIT, see LICENSE for more details. 11 | """ 12 | 13 | 14 | class BaseReply(object): 15 | """base reply message class""" 16 | def __init__(self): 17 | self.ToUserName = u'' 18 | self.FromUserName = u'' 19 | self.CreateTime = 0L 20 | self.MsgType = u'' 21 | 22 | def getToUserName(self): 23 | return self.ToUserName 24 | 25 | def setToUserName(self, toUserName): 26 | self.ToUserName = toUserName 27 | 28 | def getFromUserName(self): 29 | return self.FromUserName 30 | 31 | def setFromUserName(self, fromUserName): 32 | self.FromUserName = fromUserName 33 | 34 | def getCreateTime(self): 35 | return self.CreateTime 36 | 37 | def setCreateTime(self, createTime): 38 | self.CreateTime = createTime 39 | 40 | def getMsgType(self): 41 | return self.MsgType 42 | 43 | def setMsgType(self, msgType): 44 | self.MsgType = msgType 45 | 46 | 47 | class TextReply(BaseReply): 48 | """text reply message class""" 49 | def __init__(self): 50 | super(TextReply, self).__init__() 51 | self.Content = u'' 52 | 53 | def getContent(self): 54 | return self.Content 55 | 56 | def setContent(self, content): 57 | self.Content = content 58 | 59 | 60 | class Image(object): 61 | """image class""" 62 | def __init__(self): 63 | self.MediaId = u'' 64 | 65 | def getMediaId(self): 66 | return self.MediaId 67 | 68 | def setMediaId(self, mediaId): 69 | self.MediaId = mediaId 70 | 71 | 72 | class ImageReply(BaseReply): 73 | """image reply message class""" 74 | def __init__(self): 75 | super(ImageReply, self).__init__() 76 | self.Image = Image() 77 | 78 | def getImage(self): 79 | return self.Image 80 | 81 | def setImage(self, image): 82 | self.Image = image 83 | 84 | 85 | class Voice(object): 86 | """voice class""" 87 | def __init__(self): 88 | self.MediaId = u'' 89 | 90 | def getMediaId(self): 91 | return self.MediaId 92 | 93 | def setMediaId(self, mediaId): 94 | self.MediaId = mediaId 95 | 96 | 97 | class VoiceReply(BaseReply): 98 | """voice reply message class""" 99 | def __init__(self): 100 | super(VoiceReply, self).__init__() 101 | self.Voice = Voice() 102 | 103 | def getVoice(self): 104 | return self.Voice 105 | 106 | def setVoice(self, voice): 107 | self.Voice = voice 108 | 109 | 110 | class Video(object): 111 | """video class""" 112 | def __init__(self): 113 | self.MediaId = u'' 114 | self.ThumbMediaId = u'' 115 | 116 | def getMediaId(self): 117 | return self.MediaId 118 | 119 | def setMediaId(self, mediaId): 120 | self.MediaId = mediaId 121 | 122 | def getThumbMediaId(self): 123 | return self.ThumbMediaId 124 | 125 | def setThumbMediaId(self, thumbMediaId): 126 | self.ThumbMediaId = thumbMediaId 127 | 128 | 129 | class VideoReply(BaseReply): 130 | """video reply message class""" 131 | def __init__(self): 132 | super(VideoReply, self).__init__() 133 | self.Video = Video() 134 | 135 | def getVideo(self): 136 | return self.Video 137 | 138 | def setVideo(self, video): 139 | self.Video = video 140 | 141 | 142 | class Music(object): 143 | """music class""" 144 | def __init__(self): 145 | self.Title = u'' 146 | self.Description = u'' 147 | self.MusicUrl = u'' 148 | self.HQMusicUrl = u'' 149 | self.ThumbMediaId = u'' 150 | 151 | def getTitle(self): 152 | return self.Title 153 | 154 | def setTitle(self, title): 155 | self.Title = title 156 | 157 | def getDescription(self): 158 | return self.Description 159 | 160 | def setDescription(self, description): 161 | self.Description = description 162 | 163 | def getMusicUrl(self): 164 | return self.MusicUrl 165 | 166 | def setMusicUrl(self, musicUrl): 167 | self.MusicUrl = musicUrl 168 | 169 | def getHQMusicUrl(self): 170 | return self.HQMusicUrl 171 | 172 | def setHQMusicUrl(self, musicUrl): 173 | self.HQMusicUrl = musicUrl 174 | 175 | def getThumbMediaId(self): 176 | return self.ThumbMediaId 177 | 178 | def setThumbMediaId(self, thumbMediaId): 179 | self.ThumbMediaId = thumbMediaId 180 | 181 | 182 | class MusicReply(BaseReply): 183 | """music reply message class""" 184 | def __init__(self): 185 | super(MusicReply, self).__init__() 186 | self.Music = Music() 187 | 188 | def getMusic(self): 189 | return self.Music 190 | 191 | def setMusic(self, music): 192 | self.Music = music 193 | 194 | 195 | class Article(object): 196 | """article class""" 197 | def __init__(self): 198 | self.Title = u'' 199 | self.Description = u'' 200 | self.PicUrl = u'' 201 | self.Url = u'' 202 | 203 | def getTitle(self): 204 | return self.Title 205 | 206 | def setTitle(self, title): 207 | self.Title = title 208 | 209 | def getDescription(self): 210 | return self.Description 211 | 212 | def setDescription(self, description): 213 | self.Description = description 214 | 215 | def getPicUrl(self): 216 | return self.PicUrl 217 | 218 | def setPicUrl(self, picUrl): 219 | self.PicUrl = picUrl 220 | 221 | def getUrl(self): 222 | return self.Url 223 | 224 | def setUrl(self, url): 225 | self.Url = url 226 | 227 | 228 | class NewsReply(BaseReply): 229 | """news(image and text) reply message class""" 230 | def __init__(self): 231 | super(NewsReply, self).__init__() 232 | self.ArticleCount = 0 233 | self.Articles = [] 234 | 235 | def getArticleCount(self): 236 | return self.ArticleCount 237 | 238 | def setArticleCount(self, articleCount): 239 | self.ArticleCount = articleCount 240 | 241 | def getArticles(self): 242 | return self.Articles 243 | 244 | def setArticles(self, articles): 245 | self.Articles = articles 246 | --------------------------------------------------------------------------------