0. 목표
Django에서 관리하는 세션정보는 로그인한 user만을 관리(django_session)하므로 실제 접속자 카운트가 정밀하게 되지 않는다.
이에 브라우저로 최초 접속시 쿠키에 ses_id존재 여부를 확인하여 ses_id가 없다면 ses_id를 발번하고
최초 한번만 session정보를 누적하도록 App를 구현한다.

 

1. App생성

C:\Work\Software\eclipse-jee-2019-12-R-win32-x86_64\workspace\Blog>BlogVenv\Scripts\activate

(BlogVenv) C:\Work\Software\eclipse-jee-2019-12-R-win32-x86_64\workspace\Blog>python manage.py startapp userSession
PowerShell

 

2. apps.py 수정

from django.apps import AppConfig


class UserSessionConfig(AppConfig):
    name = "userSession"
Python

 

3. models.py 수정

from __future__ import unicode_literals

from django.contrib.auth.models import User
from django.db import models


class UserSession(models.Model):
    ses_id      = models.CharField("Session ID", max_length=64, primary_key=True)
    ses_ip      = models.GenericIPAddressField("User IP", protocol="both", unpack_ipv4=True)
    ses_ipGeo   = models.TextField("IP GEO Location", null=True)
    ses_agent   = models.TextField("User Agent", null=True)
    ses_referer = models.TextField("Referer URL", null=True)
    ses_user    = models.ForeignKey(User, on_delete=models.PROTECT, related_name="session_user", db_column="ses_user_id", null=True)
    access_dt   = models.DateTimeField("Access Datetime", db_index=True, auto_now_add=True)
    exit_dt     = models.DateTimeField("Exit Datetime", null=True)
    
    class Meta:
        verbose_name        = "userSession"
        verbose_name_plural = "userSessions"
        db_table            = "blog_userSession"
        ordering            = ["-access_dt"]
        
    def __str__(self):
        return self.ses_id
Python

 

4. settings.py 수정

INSTALLED_APPS = [
   
...

    'userSession.apps.UserSessionConfig',

...
Python

 

5. makemigrations & migrate

(BlogVenv) C:\Work\Software\eclipse-jee-2019-12-R-win32-x86_64\workspace\Blog>python manage.py makemigrations --settings=Blog.settings.settings_dev

(BlogVenv) C:\Work\Software\eclipse-jee-2019-12-R-win32-x86_64\workspace\Blog>python manage.py migrate --settings=Blog.settings.settings_dev
PowerShell

 

6. views.py 수정

import urllib.request

from django.http.response import JsonResponse
from django.views.decorators.http import require_http_methods

from userSession.models import UserSession


class UserSessionAV():

    @staticmethod
    @require_http_methods(["POST"])
    def access(request, **kwargs):
        _result = {};
        _result["status"] = False
        _result["message"] = None
        
        if request.is_ajax():
            userSession             = UserSession()
            userSession.ses_id      = kwargs["ses_id"]
            userSession.ses_ip      = request.META.get("REMOTE_ADDR")
            userSession.ses_ipGeo   = UserSessionAV.getIPGeo(userSession.ses_ip)
            userSession.ses_agent   = request.META.get("HTTP_USER_AGENT")
            userSession.ses_referer = request.META.get("HTTP_REFERER")
            userSession.save()
                
            _result["status"] = True
            
        else:
            _result["status"] = False
            _result["message"] = "Illegal access."
            
        return JsonResponse({"result":_result})
    
    # Designated as @classmethod so that it can be called from @staticmethod
    # Of course, you can specify @staticmethod.
    @classmethod
    def getIPGeo(cls, ip):
        _geoInfo = ""
        
        try:
            # https://ipapi.co/api/?python#introduction
            _url = "https://ipapi.co/{}/json/".format(ip)
            _response = urllib.request.urlopen(_url)
            _geoInfo = _response.read().decode()
            
        except:
            pass
        
        return _geoInfo
    
Python

 

7. urls.py 수정

from django.urls import path
from userSession.views import UserSessionAV

app_name = "userSession"
urlpatterns = [
    path("access/<str:ses_id>/", UserSessionAV.access, name="access")
]
Python

 

8. ut.js 수정

var UT =
{
    UUID : function()
    {
        return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function(c)
        {
            var r = Math.random() * 16 | 0, v = c == "x" ? r : (r & 3 | 8);
            return v.toString(16);
        });
    },

...

    setCookie : function(cname, cvalue, exdays)
    {
        var d = new Date();
        
        d.setTime(d.getTime() + (exdays * 24 * 60 * 60 * 1000));
        
        var expires = "";
        
        if (UT.nvl(exdays, 0) > 0)
        {
            expires = ";expires=" + d.toUTCString();
        }
        
        document.cookie = cname + "=" + encodeURIComponent(cvalue) + expires + ";path=/";
    },
...
JavaScript

 

9. ss.js 작성

var SS = 
{
    access : function()
    {
        if (UT.isEmpty(UT.getCookie("ses_id")))
        {
            var _ses_id = UT.UUID();
            
            UT.setCookie("ses_id", _ses_id)
            UT.ajax("POST", "/userSession/access/" + _ses_id + "/");
        }
    }
}
JavaScript

 

10. base.html 수정

<!DOCTYPE html>
<html lang="ko">
    <head>
...
        <script type="text/javascript" src="{% static "javascript/ss.js" %}"></script>
...
    </head>
Markup

 

11. footer.html 수정

<script>
...
SS.access();
...
</script>
Markup

 

12. 접속테스트

 

13. 운영배포
- 관련파일 업로드하고
- DB반영

[root@linux blog.daonelab.com]# source BlogVenv/bin/activate

(BlogVenv) [root@linux blog.daonelab.com]# python manage.py makemigrations --settings=Blog.settings.settings_prd

(BlogVenv) [root@linux blog.daonelab.com]# python manage.py migrate --settings=Blog.settings.settings_prd
PowerShell