[Django] 지도에 트윗 띄우기(2)

Cherry·2022년 5월 9일
0

앞의 게시물에서 트윗을 스트리밍해서 분석하여 모델에 저장하는 과정을 적었다. 앞으로는 저장된 트윗모델에서 해당지역에 트윗들을 띄우는 역할만 해주면 된다.

현재 javascript 형태 분석하기

지금 현재 지도가 어떤식으로 렌더링하고 있는지 살펴보면 현재 /api/markers/라는 url을 참고하여 지도에 렌더링해주고 있다. 가보면

async function load_markers() {
    const markers_url = `/api/markers/?in_bbox=${map.getBounds().toBBoxString()}`
    const response = await fetch(markers_url)
    const geojson = await response.json()
    return geojson
}

async function render_markers() {
    const markers = await load_markers();
    L.geoJSON(markers)
    .bindPopup((layer) => layer.feature.properties.region_name) //현재 여기에서 팝업을 띄어주고 있다.
    .addTo(map);
}

현재 이 url로 들어가면 mark모델에 관한 리스트뷰가 geojson형태로 나와있을것이다.

우선 마크 리스트에 트윗같이 띄어준후 .bindPopup((layer) => layer.feature.properties.region_name) 이부분만 수정해주면 될것 같았다. 이를 해주기 위해서 먼저 시리얼라이저를 수정해주어야 한다.

Serializer 작성해주기

from rest_framework_gis import serializers
from rest_framework import serializers as rest_serializer

from .models import Mark, Tweet

class TweetSerializer(serializers.ModelSerializer):
    disaster_tag = rest_serializer.SerializerMethodField()

    class Meta:
        model = Tweet
        fields = ("time", "text", "user", "disaster_tag")

    def get_disaster_tag(self, obj): # disastertag 추가해주기
        return obj.disaster_tag.name


class MarkSerializer(serializers.GeoFeatureModelSerializer):
    tweet = rest_serializer.SerializerMethodField()

    def get_tweet(self, obj):
        tweets = obj.tweet_set.all().order_by('-time')
        check = obj.tweet_set.exists() # 해당 지역에 트윗이 존재하는지 확인해준다
        if check: # 트윗이 존재하면 시리얼라이저로 
            return TweetSerializer(instance=tweets, many=True, context=self.context).data
        else: # 트윗이 존재하지 않으면 디폴트 트윗을 만들어준다.
            tweet = Tweet.objects.create(time="default", text="default", twid="default", user="default", location=obj,
                                        disaster_tag_id=1)
            return TweetSerializer(instance=tweet, context=self.context).data

    class Meta:
        fields = ("id", "region_name", "tweet")
        geo_field = "location"
        model = Mark

우선 코드를 작성하면서 트윗이 렌더링이 되지 않는 에러가 발생했는데 해당 지역에 트윗이 존재하지 않으면 에러가 발생했다. 따라서 먼저 해당 지역에 트윗이 존재하는지의 여부를 확인해주고 존재하지 않으면 디폴트 트윗을 만들어주어서 렌더링하는 형식으로 진행했다. 이렇게 시리얼라이저를 수정해주고 다시 /api/markers/로 들어가보면 다음과 같이 밑에 트윗이 json형식으로 같이 나온다.

지도와 트윗 연결해주기

이제 마지막 단계만 남았다. javascript를 수정해주면 된다. 뷰를 보면서 수정해주었다.

async function render_markers() {
    const markers = await load_markers();
    L.geoJSON(markers, {
        onEachFeature : function (feature, layer) {
            popupstring = "<div style='overflow:auto;height:200px;'>"
            num = Math.min(feature.properties.tweet.length, 5)
            for (var i=0;i<num;i++){
                popupstring += "<img src='트위터 로고 이미지' style='width:20px;'><p style='display:flow-root;'><span style='float:left;font-weight:700'>@"
                  +feature.properties.tweet[i].user
                  +"</span><span style='float:right;color:gray;'>"
                  +feature.properties.tweet[i].time
                  +"</span></p><p>"+feature.properties.region_name
                  +" - "+feature.properties.tweet[i].disaster_tag
                  +"</p><p>"+feature.properties.tweet[i].text+"</p><hr>"
            }
            popupstring += "</div>"
            layer.bindPopup(popupstring);
        }
    }).addTo(map);
}

완성은 아래와 같다. 해당 지역에 트윗이 여러개라면 스크롤 할수 있게 만들었다.

0개의 댓글