Python + django + 騰訊api 取得中國省市區列表
Unknown
由於最近在建置關於中國物流方面的東西
講到物流一定會想到中國非常非常多的省市區
如果用手動新增的情況下你一定會發瘋
所以寫了一個可以自動抓省市區並新增至資料庫的程式
設計架構:
由於中國有分省跟市跟區
不過市有分直轄市跟一般的市
所以在結構上會有一些不一致
比如說
provinces 省
下面有
city 市
在更下面就是
district 區
而資料庫的關聯應該就是
省 關聯 市 關聯 區
不過當直轄市出現的時候
若把它當作省放的話
就會變成
provinces 省
關聯
city 市
不過拿上海市來說好了
上海市下面就已經是區了
這樣table跟資料概念不一
所以我的解決方法是
把直轄市仍放在city當中
並加一個Boolean判斷是否是直轄市
table架構如下
//uq_id指的是各省市區都有一個id
首先
先去註冊個QQ帳號吧
註冊完之後去申請金鑰

我們這次要使用的是騰訊web service api (beta)
寫這篇文章的時候他還是beta版
所以之後規格會不會改我不能跟大家保證
他的api route是
http://apis.map.qq.com/ws/district/v1 之後則是參數囉 首先是所有地區的列表

可以看到result下面有3筆list
照順序來說是
省.直轄市 市 區接下來就是針對某一個地區的id取
的該地區下一層級的地區列表
http://apis.map.qq.com/ws/district/v1/getchildren? &id=110000& key=OB4BZ-D4W3U-B7VVO-4PJWW-6TKDJ-WPB77
id這個參數帶的就是地區代表碼
這包的結構如下:
實作
先在後台新增我想要自動匯入的省份或直轄市
views.py
講到物流一定會想到中國非常非常多的省市區
如果用手動新增的情況下你一定會發瘋
所以寫了一個可以自動抓省市區並新增至資料庫的程式
設計架構:
由於中國有分省跟市跟區
不過市有分直轄市跟一般的市
所以在結構上會有一些不一致
比如說
provinces 省
下面有
city 市
在更下面就是
district 區
而資料庫的關聯應該就是
省 關聯 市 關聯 區
不過當直轄市出現的時候
若把它當作省放的話
就會變成
provinces 省
關聯
city 市
不過拿上海市來說好了
上海市下面就已經是區了
這樣table跟資料概念不一
所以我的解決方法是
把直轄市仍放在city當中
並加一個Boolean判斷是否是直轄市
table架構如下
//uq_id指的是各省市區都有一個id
class ChinaProvinces(models.Model):
name = models.CharField(
pgettext_lazy('china provinces', 'name'),
max_length=12)
uq_id = models.CharField(
pgettext_lazy('china provinces', 'uq_id'),
max_length=6, unique=True)
enable = models.BooleanField(default="True")
sort = models.SmallIntegerField('sort', default=0)
def __str__(self):
return self.name
class ChinaCity(models.Model):
//由於前面提到的直轄市並不隸屬於任何省,所以要設定null=True
province = models.ForeignKey(
ChinaProvinces, related_name='province', blank=True, null=True)
name = models.CharField(
pgettext_lazy('china city', 'name'),
max_length=12)
uq_id = models.CharField(
pgettext_lazy('china city', 'uq_id'),
max_length=6, unique=True)
enable = models.BooleanField(default="True")
is_municipality = models.BooleanField(default=False)
sort = models.SmallIntegerField('sort', default=0)
def __str__(self):
return self.name
class ChinaDistrict(models.Model):
city = models.ForeignKey(
ChinaCity, related_name='city',)
name = models.CharField(
pgettext_lazy('china district', 'name'),
max_length=12)
uq_id = models.CharField(
pgettext_lazy('china district', 'uq_id'),
max_length=6, unique=True)
enable = models.BooleanField(default="True")
sort = models.SmallIntegerField('sort', default=0)
def __str__(self):
return self.name
接下來是如何跟騰訊call api取得我們要的資料首先
先去註冊個QQ帳號吧
註冊完之後去申請金鑰

我們這次要使用的是騰訊web service api (beta)
寫這篇文章的時候他還是beta版
所以之後規格會不會改我不能跟大家保證
他的api route是
http://apis.map.qq.com/ws/district/v1 之後則是參數囉 首先是所有地區的列表
http://apis.map.qq.com/ws/district/v1/list?key=OB4BZ-D4W3U-B7VVO-4PJWW-6TKDJ-WPB77
key後面的那一串就是剛剛申請的金鑰字串
打下來這一包的結構如

可以看到result下面有3筆list
照順序來說是
省.直轄市 市 區接下來就是針對某一個地區的id取
的該地區下一層級的地區列表
http://apis.map.qq.com/ws/district/v1/getchildren? &id=110000& key=OB4BZ-D4W3U-B7VVO-4PJWW-6TKDJ-WPB77
id這個參數帶的就是地區代表碼
這包的結構如下:
實作
先在後台新增我想要自動匯入的省份或直轄市
views.py
import requests
QQ_KEY = "YOUR_KEY"
URL = "http://apis.map.qq.com/ws/district/v1/"
def import_address(request):
def get_district(id):
url = URL + "getchildren?&id=%s&key=%s" % (id, QQ_KEY,)
response = json.loads(requests.get(url=url).text)
return response
def auto_create_from_provinces():
provinces = ChinaProvinces.objects.filter(enable=True).all()
try:
for province in provinces:
provinces_uq_id = province.uq_id
cities = get_district(provinces_uq_id)
for city in cities['result'][0]:
city_uq_id = city["id"]
city_name = city["fullname"]
new_city = ChinaCity(name=city_name, uq_id=city_uq_id, province=province)
new_city.save()
districts = get_district(city_uq_id)
for district in districts['result'][0]:
district_uq_id = district["id"]
district_name = district["fullname"]
new_district = ChinaDistrict(name=district_name, uq_id=district_uq_id, city=new_city)
new_district.save()
except Exception as e:
print(e)
def auto_create_from_municipalities():
municipalities = ChinaCity.objects.filter(enable=True, is_municipality=True).all()
for municipality in municipalities:
municipality_uq_id = municipality.uq_id
districts = get_district(municipality_uq_id)
for district in districts['result'][0]:
district_uq_id = district["id"]
district_name = district["fullname"]
new_district = ChinaDistrict(name=district_name, uq_id=district_uq_id, city=municipality)
new_district.save()
auto_create_from_provinces()
auto_create_from_municipalities()
return HttpResponse("Done!!")
大功告成
Python 無框架式網站 (baseHttpserver)
Unknown
很多時候不一定要用龐大的框架來實作網頁
Simple is best
python 其實有提供一些基本的web功能
官方標準套件介紹
如何開始呢?
寫隻程式當作入口吧!!
1.Response code
Simple is best
python 其實有提供一些基本的web功能
官方標準套件介紹
如何開始呢?
寫隻程式當作入口吧!!
if __name__ == ‘__main__’: server = HTTPServer((‘localhost’,8888),Handler) server.serve_forever() BaseHTTPServer下function mainn class 的名稱(RequestHandlerClass)以get當作例子,其必要參數的實作:
1.Response code
send_response(200)2.Headers
send_header(keyword,value)3.Templates
wfile.write(html)結果:
django.utils timezone搭配timedelta的使用達到時間的加減以及運算
Unknown
如果我們想要實作時間的加減
可以透過timedelta
今天我想要把一組現在的時間+上一分鐘來當作我的驗證失效時間
我們可以這樣做
首先
在我們的settings.py中宣告timezone啟用的設定
setting.py
接著在程式碼當中提出實體,並透過timedelta做運算
這樣due_time就會是現在時間加一分鐘
若套用在models上面則是
當最後需要運算的時候判斷是否超過一分鐘
當timezone.now()-due_date後取得的事timedelta的實體
大功告成
特別要注意timedelta能做加減的型態
要實作分鐘的話就用秒數*60去實作囉
因為沒提供minutes或是hour
可以去官方document看看
可以透過timedelta
今天我想要把一組現在的時間+上一分鐘來當作我的驗證失效時間
我們可以這樣做
首先
在我們的settings.py中宣告timezone啟用的設定
setting.py
USE_TZ = True
接著在程式碼當中提出實體,並透過timedelta做運算
due_time = timezone.now() + timezone.timedelta(seconds=60)
這樣due_time就會是現在時間加一分鐘
若套用在models上面則是
due_date = models.DateTimeField('due date', default=timezone.now()+ timezone.timedelta(seconds=60), editable=False)
當最後需要運算的時候判斷是否超過一分鐘
當timezone.now()-due_date後取得的事timedelta的實體
if((timezone.now()-due_date).seconds > 60):
print("verify fail!!!")
else:
do something
大功告成
特別要注意timedelta能做加減的型態
要實作分鐘的話就用秒數*60去實作囉
因為沒提供minutes或是hour
可以去官方document看看
| Attribute | Value |
|---|---|
| days | Between -999999999 and 999999999 inclusive |
| seconds | Between 0 and 86399 inclusive |
| microseconds | Between 0 and 999999 inclusive |
晚上11:06
django
Ubuntu 15.02 安裝nodejs後無法使用npm解決方法
Unknown
由於ubuntu原先是使用node
不過因為debian的關係
改用成nodejs了
所以在安裝上步驟必須如下
之後再操作npm上面可能會有錯誤
甚至
在terminal下打node --v 或是 node --help都沒有反應
到底為什麼呢?
因為我們缺少一個溝通node to nodejs的橋樑
系統原生這邊是會抓node
不過現在已經改用nodejs
系統並不知道
所以我們需要裝
當作橋樑
話說2012 debian就改用nodejs了
那為什麼在裝nodejs的時候不順便把nodejs-legacy一起包含進去呢
這樣會讓很多人被雷到
明明都裝了該裝的,版本也沒什麼問題
卻在使用上出問題
不過因為debian的關係
改用成nodejs了
所以在安裝上步驟必須如下
sudo apt-get-repository ppa:chris-lea/node.js
sudo apt-get update
sudo apt-get install nodejs
sudo apt-get install npm
之後再操作npm上面可能會有錯誤
甚至
在terminal下打node --v 或是 node --help都沒有反應
到底為什麼呢?
因為我們缺少一個溝通node to nodejs的橋樑
系統原生這邊是會抓node
不過現在已經改用nodejs
系統並不知道
所以我們需要裝
sudo apt-get install nodejs-legacy
當作橋樑
話說2012 debian就改用nodejs了
那為什麼在裝nodejs的時候不順便把nodejs-legacy一起包含進去呢
這樣會讓很多人被雷到
明明都裝了該裝的,版本也沒什麼問題
卻在使用上出問題
djagno + rest_framework2.X pagination實作方法
Unknown
Django 提供了一種方便整合分頁的功能
from django.core.paginator import Paginator
rest_framework也提供相對應的功能
from rest_framework import pagination注意:rest_framework 3 沒提供pagination的功能了
功能:
透過”Previous/Next”的links來整合多筆資料
逕而達到分頁效果。
原理:
Paginator 傳入data,以及每一頁要呈現的資料數量取得實體
在將Query parames取得當前page number
最後透過page number去取得該page的資料
PaginationSerializer
將先後頁及筆數同時序列化
fields:
count
next
previous程式:
views.py
cars = Car.objects.filter(color="red").order_by('-date')
cars = paginationTools(objects_list=cars, pre_page=9, page_number=request.QUERY_PARAMS.get('page'))
serializer_context = {'request': request}
serializer = PaginatedCarsSerializer(data=scenes, context=serializer_context)
return Response(serializer.data,status=status.HTTP_200_OK)
pre_page意思是一分頁要幾個item
page_number則是取得現在是要取得第幾頁的內容 serializer.py
class PaginatedCarsSerializer(pagination.PaginationSerializer):
#自定義欄位
start_index = serializers.SerializerMethodField('getStartIndex')
end_index = serializers.SerializerMethodField('getEndIndex')
page_count = serializers.ReadOnlyField(source='paginator.num_pages')
#Reda only use "source="XXXX"
current_index = serializers.ReadOnlyField(source='number')
class Meta:
#指定serializer class
object_serializer_class = CarSerializer
def getStartIndex(self, obj):
return obj.start_index()
def getEndIndex(self, obj):
return obj.end_index()
class CarSerializer(serializers.ModelSerializer):
""" Session Serializer """
class Meta:
model = EventScenes
fields = ['name', 'image', 'id', 'description', 'color', 'place']
mytools.py
def paginationTools(objects_list, pre_page, page_number):
paginator = Paginator(objects_list, pre_page)
try:
result = paginator.page(page_number)
except PageNotAnInteger:
result = paginator.page(1)
except EmptyPage:
result = paginator.page(paginator.num_pages)
except InvalidPage:
result = paginator.page(1)
return result
這裡基本是封裝了我的Django pagination的方法其中做了try catch
下午6:47
django
,
pagination
,
rest_framework
,
serializer
Django rest_framework 3 的變化 (pagination)
Unknown
相信有用到pagination功能的道友們應該都發現了吧
rest_framework 3之後沒有pagination serializer了
這對用習慣Django 1.4 + rest_framework 2.x版的做pagination的我實在是...
好吧
新的rest_framework用的pagination方式是必須透過繼承generics.ListAPIView的方式
如官方文檔
用習慣APIView了
要轉換著實有點麻煩
下篇文章會聊到我是怎麼透過其他方式實作pagination
rest_framework 3之後沒有pagination serializer了
這對用習慣Django 1.4 + rest_framework 2.x版的做pagination的我實在是...
好吧
新的rest_framework用的pagination方式是必須透過繼承generics.ListAPIView的方式
如官方文檔
class BillingRecordsView(generics.ListAPIView):
queryset = Billing.objects.all()
serializer = BillingRecordsSerializer
pagination_class = LargeResultsSetPagination
用習慣APIView了
要轉換著實有點麻煩
下篇文章會聊到我是怎麼透過其他方式實作pagination
下午6:41
django
,
python
,
rest_framework
Django sitemaps架設
Unknown
如何建置django提供的sitemaps呢?
首先
先確定你的專案是否有加入了sites以及sitemaps
以及TEMPLATES下的APP_DIRS是否是True
settings.py
然後我們回到我們的urls.py
urls.py
結束後快點去瀏覽器輸入你的domain + /sitemap.xml 就能看到結果了
result:
<urlset>
<url>
<loc>http://https://l-somewhere.com/login/</loc>
<lastmod>2015-09-03</lastmod>
<changefreq>weekly</changefreq>
</url>
</urlset>
首先
先確定你的專案是否有加入了sites以及sitemaps
以及TEMPLATES下的APP_DIRS是否是True
settings.py
INSTALLED_APPS = (
'django.contrib.sites',
'django.contrib.sitemaps',
)
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR, 'templates')],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
接著我們創建一個sitemaps.py在專案底下(哪邊都可以)
sitemaps.py
from django.contrib.sitemaps import Sitemap
from datetime import datetime
from django.core.urlresolvers import reverse
class test(Sitemap):
def __init__(self, naems):
self.names = names
def items(self):
return self.names
def changefreq(self, obj):
return 'weekly'
def lastmod(self, obj):
return datetime.now()
//取得該url name 的網址
def location(self, obj):
return reverse(obj)
然後我們回到我們的urls.py
urls.py
//import 剛剛創建的sitemaps.py 底下的class from myprojest.sitemaps import test //創一個dictionary關於sitemaps的對照
sitemaps = {
//class帶進去的參數是url name
'pages':test(['login_index'], ['logout_index'])
}
urlpatterns = [
//這就是我提到的url name
url(r'^login/', memver.views.LoginView, name='login_index'),
url(r'^logout/', memver.views.LogoutView, name='logout_index'),
//關鍵在這了 sitemaps就是剛剛上面創建的dictionary
url(r'^sitemap\.xml$', 'django.contrib.sitemaps.views.sitemap', {'sitemaps':sitemaps}),
]
結束後快點去瀏覽器輸入你的domain + /sitemap.xml 就能看到結果了
result:
<urlset>
<url>
<loc>http://https://l-somewhere.com/login/</loc>
<lastmod>2015-09-03</lastmod>
<changefreq>weekly</changefreq>
</url>
</urlset>
訂閱:
文章
(
Atom
)
技術提供:Blogger.
