iT邦幫忙

2023 iThome 鐵人賽

DAY 1
0
自我挑戰組

Django系列 第 11

Day11~Django 漫漫長路-當post 遇上了 filter

  • 分享至 

  • xImage
  •  

大家好,我是Leo
今天要來講解的是使用post method 來達到篩選的功能/images/emoticon/emoticon30.gif
OK~~~ Let's go now!!!


爬取資料

假設我們今天想要把全省某連鎖餐廳的地址都透過網路爬蟲的方式,擷取下來透過migration的方式存入database內
總共3頁,這邊直接將它轉成dataframe,發現index第22筆遺漏區域,於是正確地址補上去
因有些區是只有兩個字,於是做一個邏輯判斷
iloc -> 主要適用index取值,取值方式 -> [index,col]
將整理好資訊印出來,方便等下直接擷取使用

hotpot.py

import requests
from bs4 import BeautifulSoup
import pandas as pd
result = []
for i in range(1,4):
    url = f'https://www.findcoupon.tw/showroom-1013/store?page={i}'
    res = requests.get(url)
    soup = BeautifulSoup(res.text,'lxml')
    tables = soup.select('.tbody > .tr')
    for table in tables:
        details = table.find_all('a')
        detail_list = []
        for detail in details:
            detail_list.append(detail.text)
        result.append(detail_list)

df = pd.DataFrame(result,columns=['name','address','tel'])
df.iloc[22,1] = ' 台南市南區金華路二段129號'
df['city'] = [x[:4] for x in df['address']]
df['town'] = [x[4:6] if '區' in x[4:6] else x[4:7] for x in df['address']]
df['address'] = [str(df.iloc[i,1]).split(df.iloc[i,-1])[1] for i in range(len(df))]

for i in range(len(df)):
    print(f"store{i+1} = stores(id={i+1} ,name = '{df.loc[i,'name']}', city_name='{df.loc[i,'city']}' ,town_name='{df.loc[i,'town']}' , address='{df.loc[i,'address']}')")
    print(f'store{i+1}.save()')

列印出來的資訊,如下圖,透過全選的方式貼入待會要建立的檔案內

https://ithelp.ithome.com.tw/upload/images/20230103/20154853Sla2SJjszl.jpg


建立model

models/hotpot_store_model.py

from django.db import models

class HotPot_Store(models.Model):
    id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=255)
    city_name = models.CharField(max_length=255)
    town_name = models.CharField(max_length=255)
    address = models.CharField(max_length=255)

models/init.py

from .hotpot_store_model import *

建立makemigrations

https://ithelp.ithome.com.tw/upload/images/20230103/20154853eUhmX7C8BW.jpg

可以將剛剛print出來的資料copy貼上至def add_hot_pot_store(apps, schema_editor) function內
注意 Migration 內,請改為makemigrations資料夾內上一個的檔案名
像我的就是0002_add_user_roles

migrations/0003_hot_pot_store.py

from __future__ import unicode_literals
from django.db import models, migrations
from website.models import HotPot_Store

def add_hot_pot_store(apps, schema_editor):
    stores = apps.get_model("website", "HotPot_Store")
    store1 = stores(id=1, name='南投家樂福店', city_name=' 南投縣', town_name='南投市', address='三和三路21號2F')
    store1.save()
    store2 = stores(id=2, name='台中中華店', city_name=' 台中市', town_name='北區', address='中華路二段199-6號')
    store2.save()
    store3 = stores(id=3, name='台中漢口崇德店', city_name=' 台中市', town_name='北區', address='漢口路四段395號')
    store3.save()
    store4 = stores(id=4, name='台中美村南店', city_name=' 台中市', town_name='南區', address='美村南路126號')
    store4.save()
    store5 = stores(id=5, name='台中家樂福文心店', city_name=' 台中市', town_name='南屯區', address='文心路一段521號')
    store5.save()
    store6 = stores(id=6, name='台中黎明店', city_name=' 台中市', town_name='南屯區', address='黎明路二段216號')
    store6.save()
    store7 = stores(id=7, name='大里大買家店', city_name=' 台中市', town_name='大里區', address='國光路2段710號2F')
    store7.save()
    store8 = stores(id=8, name='太平中山店', city_name=' 台中市', town_name='太平區', address='中山路四段169號')
    store8.save()
    store9 = stores(id=9, name='清水中山店', city_name=' 台中市', town_name='清水區', address='中山路177號')
    store9.save()
    store10 = stores(id=10, name='台中河南店', city_name=' 台中市', town_name='西屯區', address='河南路二段312號')
    store10.save()
    store11 = stores(id=11, name='台中西屯玉門店', city_name=' 台中市', town_name='西屯路', address='三段285號')
    store11.save()
    store12 = stores(id=12, name='豐原三豐店', city_name=' 台中市', town_name='豐原區', address='三豐路36號')
    store12.save()
    store13 = stores(id=13, name='台北民權龍江店', city_name=' 台北市', town_name='中山區', address='民權東路三段19號')
    store13.save()
    store14 = stores(id=14, name='台北捷運後山埤店', city_name=' 台北市', town_name='信義區',
                     address='忠孝東路五段789號')
    store14.save()
    store15 = stores(id=15, name='台北天母店', city_name=' 台北市', town_name='士林區', address='天母西路40號')
    store15.save()
    store16 = stores(id=16, name='台北信義店', city_name=' 台北市', town_name='大安區', address='信義路二段72號')
    store16.save()
    store17 = stores(id=17, name='台北安居店', city_name=' 台北市', town_name='大安區', address='安居街50號')
    store17.save()
    store18 = stores(id=18, name='台北捷運景美店', city_name=' 台北市', town_name='文山區', address='羅斯福路六段192號')
    store18.save()
    store19 = stores(id=19, name='台北興隆店', city_name=' 台北市', town_name='文山區', address='興隆路四段149號')
    store19.save()
    store20 = stores(id=20, name='台北家樂福桂林店', city_name=' 台北市', town_name='萬華區',
                     address='家樂福桂林店家樂福桂林路1號4F')
    store20.save()
    store21 = stores(id=21, name='仁德中山店', city_name=' 台南市', town_name='仁德區', address='中山路777號')
    store21.save()
    store22 = stores(id=22, name='台南中華東店', city_name=' 台南市', town_name='東區', address='中華東路三段341號')
    store22.save()
    store23 = stores(id=23, name='台南金華店', city_name=' 台南市', town_name='南區', address='金華路二段129號')
    store23.save()
    store24 = stores(id=24, name='員林中山店', city_name=' 彰化縣', town_name='員林鎮', address='中山路二段368號')
    store24.save()
    store25 = stores(id=25, name='蘆洲家樂福店', city_name=' 新北市', town_name='三重區', address='五華街282號4F')
    store25.save()
    store26 = stores(id=26, name='三重家樂福重新店', city_name=' 新北市', town_name='三重區', address='重新路五段654號')
    store26.save()
    store27 = stores(id=27, name='三重龍門店', city_name=' 新北市', town_name='三重區', address='龍門路6號3F')
    store27.save()
    store28 = stores(id=28, name='中和德光店', city_name=' 新北市', town_name='中和區', address='德光路32號')
    store28.save()
    store29 = stores(id=29, name='土城中央店', city_name=' 新北市', town_name='土城區', address='中央路二段223之13號')
    store29.save()
    store30 = stores(id=30, name='新店捷運大坪林店', city_name=' 新北市', town_name='新店區', address='民權路15號')
    store30.save()
    store31 = stores(id=31, name='新莊輔大店', city_name=' 新北市', town_name='新莊區', address='建國一路61號')
    store31.save()
    store32 = stores(id=32, name='板橋捷運新埔店', city_name=' 新北市', town_name='板橋區', address='文化路一段360號')
    store32.save()
    store33 = stores(id=33, name='林口家樂福店', city_name=' 新北市', town_name='林口區', address='文化二路一段559號B1')
    store33.save()
    store34 = stores(id=34, name='新竹林森店', city_name=' 新竹市', town_name='東區', address='林森路2巷9號3F')
    store34.save()
    store35 = stores(id=35, name='中壢家樂福中山東店', city_name=' 桃園市', town_name='中壢區',
                     address='中山東路二段510號1F')
    store35.save()
    store36 = stores(id=36, name='中壢中美店', city_name=' 桃園市', town_name='中壢區', address='中美路一段12號3樓')
    store36.save()
    store37 = stores(id=37, name='桃園南平店', city_name=' 桃園市', town_name='桃園區', address='同安街442號')
    store37.save()
    store38 = stores(id=38, name='桃園大興店', city_name=' 桃園市', town_name='桃園區', address='大興路155號')
    store38.save()
    store39 = stores(id=39, name='竹南家樂福民族店', city_name=' 苗栗縣', town_name='竹南鎮', address='光復路125號')
    store39.save()
    store40 = stores(id=40, name='斗六文化店', city_name=' 雲林縣', town_name='斗六市', address='文化路65-1號')
    store40.save()
    store41 = stores(id=41, name='高雄建工店', city_name=' 高雄市', town_name='三民區', address='建工路590號')
    store41.save()
    store42 = stores(id=42, name='高雄七賢店', city_name=' 高雄市', town_name='前金區', address='七賢二路193-10號')
    store42.save()
    store43 = stores(id=43, name='高雄青年店', city_name=' 高雄市', town_name='前金區', address='青年二路34號')
    store43.save()
    store44 = stores(id=44, name='高雄華夏店', city_name=' 高雄市', town_name='左營區', address='華夏路685號')
    store44.save()
    store45 = stores(id=45, name='高雄後昌店', city_name=' 高雄市', town_name='楠梓區', address='後昌路622號')
    store45.save()
    store46 = stores(id=46, name='高雄三多店', city_name=' 高雄市', town_name='苓雅區', address='三多三路132號')
    store46.save()
    store47 = stores(id=47, name='鳳山五甲店', city_name=' 高雄市', town_name='鳳山區', address='五甲一路261號')
    store47.save()
    store48 = stores(id=48, name='高雄鳳山店', city_name=' 高雄市', town_name='鳳山區', address='青年路二段259號')
    store48.save()

def delete_all(apps, schema_editor):
    return 'SET FOREIGN_KEY_CHECKS=0; DELETE from website_cities_towns;'

class Migration(migrations.Migration):
    dependencies = [
        ('website', '0002_add_user_roles'),
    ]
    operations = [
        migrations.RunPython(add_hot_pot_store,delete_all),
    ]

執行生成資料

python .\manage.py migrate

資料生成完成

https://ithelp.ithome.com.tw/upload/images/20230103/20154853MN76gRjB8F.jpg


serializers

serializers/init.py

from .hotpot_ser import *

"all" = 欄位全取
serializers/hotpot_ser.py

from rest_framework import serializers
from website.models import HotPot_Store

class HotPotStoreSerializer(serializers.ModelSerializer):
    class Meta:
        model = HotPot_Store
        fields = "__all__"

views

透過每次抓取request.data.get("value")的value值進行filter
有則filter,再將filter的資訊帶入下一次的比對
如未有這個欄位或空值也不會報錯
最後將object轉為serializer 回傳serializer.sdata

views/hotpot_store.py

from rest_framework.response import Response
from rest_framework.views import APIView
from rest_framework import generics,permissions
from website.models import HotPot_Store
from website.serializers import HotPotStoreSerializer

class HotPotStoreAPIView(APIView):
    permission_classes = (permissions.AllowAny,)
    authentication_classes = []

    def post(self, request):
        hotpots = HotPot_Store.objects.all()
        try:
            name = request.data.get("name")
            hotpots = hotpots.filter(name__icontains=name)
        except:
            pass
        try:
            city_name = request.data.get("cityName")
            hotpots = hotpots.filter(city_name__icontains=city_name)
        except:
            pass
        try:
            town_name = request.data.get("townName")
            hotpots = hotpots.filter(town_name__icontains=town_name)
        except:
            pass
        try:
            address = request.data.get("address")
            hotpots = hotpots.filter(address__icontains=address)
        except:
            pass
        serializer_hotpots = HotPotStoreSerializer(
            hotpots, many=True, context={"request": request}
        )

        return Response(serializer_hotpots.data)

views/init.py

from .hotpot_store import *

postman的呈現

如果今天沒有name這個欄位,並且townName這個欄位傳空值參數
進行作篩選比對後,回傳符合的資訊
可以透過這個做快速的篩選

https://ithelp.ithome.com.tw/upload/images/20230103/20154853QX5Poful6L.jpg


今天主要是介紹多欄位的filter,透過post method的方式做篩選
明天我想介紹的是django filter內的其他功能
我們明天見,各位掰掰~~~/images/emoticon/emoticon29.gif


上一篇
Day10~Django 漫漫長路- 多檔案上傳
下一篇
Day12~Django 漫漫長路- 知曉filter,知曉篩選真理
系列文
Django30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言