日期篩選

Python + django + 騰訊api 取得中國省市區列表

由於最近在建置關於中國物流方面的東西

講到物流一定會想到中國非常非常多的省市區

如果用手動新增的情況下你一定會發瘋

所以寫了一個可以自動抓省市區並新增至資料庫的程式

設計架構:

由於中國有分省跟市跟區

不過市有分直轄市跟一般的市

所以在結構上會有一些不一致

比如說

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)

很多時候不一定要用龐大的框架來實作網頁

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的使用達到時間的加減以及運算

如果我們想要實作時間的加減

可以透過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看看

AttributeValue
daysBetween -999999999 and 999999999 inclusive
secondsBetween 0 and 86399 inclusive
microsecondsBetween 0 and 999999 inclusive

Ubuntu 15.02 安裝nodejs後無法使用npm解決方法

由於ubuntu原先是使用node

不過因為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實作方法

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










Django rest_framework 3 的變化 (pagination)

相信有用到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

Django sitemaps架設

如何建置django提供的sitemaps呢?

首先

先確定你的專案是否有加入了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>



技術提供:Blogger.

Pages

FACEBOOK