Hello, everyone. This is the latest edition of Learning Python. What can YOU do? Django tutorials from scratch to finally successfully deploy live projects. In this section, write dashboards in AdminLTE.

Peekpa.com official address: Peekpa.com

PI ye each article, are configured with the corresponding code. The code Tag for this article is Post_024

Currently, when we log into our CMS interface, we see something like this:

Very ugly, not beautiful. So in these sections, we’re going to develop a real CMS Dashboard. The specific development completion looks like this:

We can see that it can be divided into the following parts:

  • The user to access
  • This article statistics
  • You can add other functions if you want

We can actually do all of these things, and in the next couple of lectures, we’re going to talk about how each of these things work.

User Access Statistics

First is the user visit statistics, we want to count each user’s access requests, and record the number of website visits every day, so we need to create a model.

This model should be for site-wide use, so we created it under basefucntion/models.py:

class UserIP(models.Model):
    ip_address = models.CharField(max_length=30)
    ip_location = models.CharField(max_length=30)
    end_point = models.CharField(default='/', max_length=30)
    day = models.DateField(default=timezone.now)


# Total website visits
class VisitNumber(models.Model):
    count = models.IntegerField(default=0)  # Total number of website visits


# Daily traffic statistics
class DayNumber(models.Model):
    day = models.DateField(default=timezone.now)
    count = models.IntegerField(default=0)  # Total number of website visits
Copy the code

Next, we create a tracking_view.py under the Base application, which contains our update method, the final number of visits to the site:

def peekpa_tracking(func):
    def wrapper(request, *args, **kwargs):
        tacking_info(request)
        return func(request, *args, **kwargs)
    return wrapper


def tacking_info(request):
    update_visit_number()
    update_user_ip(request)
    update_day_visit_number()


def update_visit_number(a):
    count_nums = VisitNumber.objects.filter(id=1)
    if count_nums:
        count_nums = count_nums[0]
        count_nums.count = F('count') + 1
    else:
        count_nums = VisitNumber()
        count_nums.count = 1
    count_nums.save()


def update_user_ip(request):
    if 'HTTP_X_FORWARDED_FOR' in request.META:  # get IP
        client_ip = request.META['HTTP_X_FORWARDED_FOR']
        client_ip = client_ip.split(",") [0]  # so here is the real IP
    else:
        client_ip = request.META['REMOTE_ADDR']  Get the proxy IP address here

    UserIP().objects.create(ip=client_ip, end_point=request.path, ip_address="TBA", day=timezone.now().date())


def update_day_visit_number(a):
    date = timezone.now().date()
    today = DayNumber.objects.filter(day=date)
    if today:
        temp = today[0]
        temp.count += 1
    else:
        temp = DayNumber()
        temp.dayTime = date
        temp.count = 1
    temp.save()
Copy the code

First, we’re going to do this via decorator. When the request comes in, we do three steps:

  1. Update total website visits;
  2. Update personal access records;
  3. Update the number of visits per day.

It then passes the request to the incoming func to do what needs to be done.

We can verify the detail information in the article at this time:

@peekpa_tracking
def detail(request, time_id):
Copy the code

At this point, let’s go back to any of the previous posts:

After the access is successful, let’s look at the database:

You can see that the information that we’re tracking is already in the database. That means it worked. Now let’s do Dashboard statistics.

Page statistics display

As we saw in the early preview images, our Dashboard page displays statistics related to site clicks, and we’re going to display those.

If we were to display data to Dashboard, we would have prepared the data in the Dashboard’s home view function before passing it to the page.

Therefore, our main logic should be written in the cms_Dashboard (Request) view method.

@peekpa_login_required
def cms_dashboard(request):
    context = {}
    context.update(get_dashboard_top_data())
    context.update(get_dashboard_visitor_ip_table())
    return render(request, 'cms/home/home.html', context=context)
    
def get_dashboard_top_data(a):
    post_num = Post.objects.all().count()
    day_visit_ip_set = set()
    day_visit_ip_list = UserIP.objects.filter(day=timezone.now().date())
    if day_visit_ip_list:
        for user_ip_item in day_visit_ip_list:
            if user_ip_item.ip_address not in day_visit_ip_set:
                day_visit_ip_set.add(user_ip_item.ip_address)
    day_visit_ip_num = len(day_visit_ip_set)
    day_visit_num = DayNumber.objects.filter(day=timezone.now().date())[0].count
    total_visit_num = VisitNumber.objects.filter(id=1) [0].count
    context = {
        "post_num": post_num,
        "day_visit_ip_num": day_visit_ip_num,
        "day_visit_num": day_visit_num,
        "total_visit_num": total_visit_num
    }
    return context
    
def get_dashboard_visitor_ip_table(a):
    visitor_data = UserIP.objects.filter(day=timezone.now().date())
    if len(visitor_data):
        visitor_data = visitor_data[:7]
    context = {
        'visitor_data_list': visitor_data,
    }
    return context
Copy the code

As you can see, we use two methods get_dashboard_top_data and get_dashboard_visitor_IP_TABLE to get data for the top four small modules and Visitor IP Table, respectively. Once we have the data, we show it to the front end:

Next, we need to improve the content of Chart.

The chart shows

As you can see here, our Dashboard uses a very beautiful form, chart.js, which is a very useful Chart library. Official website address:

www.chartjs.org/

Since we need to pass the value from the background to the front end first, and the icon is a JS document, we should write some JS code in the HTML code. Our home_visit_chat.html code should look like this:

<script>
    $(document).ready(function () {
        var ticksStyle = {
            fontColor: '# 495057'.fontStyle: 'bold'
        }
        var $visitorsChart = $('#visitors-chart')
        var visitorsChart2 = new Chart($visitorsChart, {
            data: {
                labels: {{ date_time_list }},
                datasets: [{
                    type: 'line'.data: {{ week_data_list }},
                    backgroundColor: 'transparent'.borderColor: '#007bff'.pointBorderColor: '#007bff'.pointBackgroundColor: '#007bff'.fill: true}},options: {
                maintainAspectRatio: false.tooltips: {
                    mode: 'index'.intersect: true
                },
                hover: {
                    mode: 'index'.intersect: true
                },
                legend: {
                    display: false
                },
                scales: {
                    yAxes: [{
                        // display: false,
                        gridLines: {
                            display: true.lineWidth: '4px'.color: 'rgba(0, 0, 0, .2)'.zeroLineColor: 'transparent'
                        },
                        ticks: $.extend({
                            beginAtZero: false.suggestedMax: {{ suggested_max }}
                        }, ticksStyle)
                    }],
                    xAxes: [{
                        display: true.gridLines: {
                            display: false
                        },
                        ticks: ticksStyle
                    }]
                }
            }
        })
    })
</script>
Copy the code

As you can see, there is a lot of data that needs to be backed up to the front end, so we can read all the data and add it to the cms_dashboard() view function:

def get_dashboard_visitor_chart(a):
    days_list = []
    visit_list = []
    max_num = 0
    week_total_num = 0
    for index in range(6.- 1.- 1):
        day, format_date = get_before_date(index)
        days_list.append(int(day))
        day_visit_num = 0
        daynumber_item = DayNumber.objects.filter(day=format_date)
        if daynumber_item:
            day_visit_num = daynumber_item[0].count
        visit_list.append(day_visit_num)
        week_total_num += day_visit_num
        max_num = day_visit_num if day_visit_num > max_num else max_num
    context = {
        'visit_week_total_number': day_visit_num,
        'date_time_list': days_list,
        'week_data_list': visit_list,
        'suggested_max': max_num
    }
    return context
Copy the code

So, our chart is done. Take a look at the results:

The last one is our article browsing situation.

Article Reading status

Article reading, now that we already know the page views of every day, and they visit the address we also know, so, article access we can easily do.

Again, add data to the cms_Dashboard view function.

def get_dashboard_post_view_table(a):
    visitor_day_data = UserIP.objects.filter(day=timezone.now().date(), end_point__contains='/detail/')
    post_map = {}
    post_view_table_list = []
    if visitor_day_data:
        for item in visitor_day_data:
            post_id = item.end_point.split('/') [2]
            if post_id in post_map:
                post_map[post_id] += 1
            else:
                post_map[post_id] = 1
    if post_map:
        for key in post_map:
            key = key
            post_item = Post.objects.filter(time_id=key)
            if post_item:
                post_item[0].inscrease = post_map[key]
                post_view_table_list.append(post_item[0])
    if post_view_table_list:
        post_view_table_list.sort(key=lambda x: x.inscrease, reverse=True)
    context = {
        'post_view_table_list': post_view_table_list,
    }
    return context
Copy the code

Here our operation is rather complicated, mainly through the following steps:

  1. Read the click situation of the articles on that day;
  2. Retrieve the list of articles, and store the data in a dictionary, key is id, name is the number of articles;
  3. These articles are retrieved from the Post and sorted back to the front end for display.

Finally, let’s look at the overall effect:

You can see that the whole page is divided into four sections, and then Monitor is made on the left side, in which UserIP management and article reading details are corresponding respectively. In fact, the writing of Dashboard can be more flexible, the key is to complete according to their actual needs.

This article statistics

Finally, let’s add a chapter about article statistics.

The students who read the article carefully must have found that the value of our previous article statistics is not correct, so we want to realize the article statistics, we have the following ideas:

  1. Each time we request an article, we read the article object from the database and Post itread_numAdd one and put it in;
  2. Set up the cache a little bit, through the F expression, to do lazy load processing;
  3. MemoryCache or Reddis is a place to put the “up and one” feature of an article.

The characteristics of these ideas are as follows:

  1. The implementation is simple, but the cost of database overhead is serious;
  2. The implementation is general, which can alleviate some database overhead, but when the site size increases, high concurrency can cause problems;
  3. Implementation is difficult, but can withstand high concurrency problems.

Since our Peekpa.com is not an ordinary small website, I will choose the second implementation method to show you.

Here’s a quick idea:

When a user accesses article details, a UID is generated for the user, which is cached in different articles for 1 minute. Repeated visits within one minute are not counted as traffic volume. Then lazy load update database.

This time, we’re going to use middleware. In the Post application, create a Python package for middleware and implement a middleware package called user_id:

class UserIDMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):
        uid = self.generate_uid(request)
        request.uid = uid
        response = self.get_response(request)
        response.set_cookie(USER_KEY, uid, max_age=TEN_YEARS, httponly=True)
        return response

    def generate_uid(self, request):
        try:
            uid = request.COOKIES[USER_KEY]
        except KeyError:
            uid = uuid.uuid4().hex
        return uid
Copy the code

Next, we’ll add this MIDDLEWARE in the first place in settings.py:

MIDDLEWARE = [
    'apps.poster.middleware.user_id.UserIDMiddleware',]Copy the code

Finally, we add the logic we mentioned above in the article details request page:

@peekpa_tracking
def detail(request, time_id):
    handle_visited(request, time_id)
    return render(request, 'post/detail.html', context=context)
    
def handle_visited(request, time_id):
    increase_post_view = True
    uid = request.uid
    pv_key = 'pv:%s:%s' % (uid, request.path)
    if not cache.get(pv_key):
        increase_post_view = True
        cache.set(pv_key, 1.2*60)

    if increase_post_view:
        Post.objects.filter(time_id=time_id).update(read_num=F('read_num') + 1)
Copy the code

In this way, we have perfectly implemented the function of page access to The Plus One.

Technical summary

So just to conclude,

Writing a CMS Dashboard:

  1. We created UserIP, VisitNumber, and DayVisitNumberr to manage single clicks, total clicks, and daily clicks.
  2. Dashboard is still divided into four small squares at the top and then divided into four tables.
  3. incms_dashboard()This view function adds data back to the front end;
  4. Add data, according to the module step by step processing;
  5. Chartjs, here we have JavaScript code inside the HTML template, as well;
  6. Articles are sorted by daily access insideend_pointThe value gets the id of the article, and then goes to Post to find the article according to the ID, and finally displays it;
  7. Add one to a page, which uses MiddleWare to add a UID to a request. Then, when a request reaches a view function, the UID is in the cache to determine if it needs to be added.
  8. The completion of

The only way to get the code: follow “PI Ye Lu code” and reply “code” to get it.

Long press the two-dimensional code below to pay attention to, if the article is inspiring to you, welcome to look at and forward.