[PYTHON] Django Tips-Create a ranking site with Django-

Introduction

Since I made the app with Django for the first time, it is a memorandum of problems and solutions that I had at that time. This time, I made a ranking site for AtCoder. I had a hard time understanding the big picture of the MVC model (MTV for Django?). Reference (http://mimumimu.net/blog/2011/11/21/python-django-%E3%81%97%E3%81%A6%E3%81%BF%E3%81%9F%E3%80 % 82-mtv-model-% E3% 81% AB% E3% 81% A4% E3% 81% 84% E3% 81% A6 /)

0. Develop a web application concept

What kind of service do you want to create in the first place? ->

1. Create an app with Django

$ django-admin startproject project-name
$ cd project-name
$ python manage.py startapp app-name

2. Download Template

Writing HTML, CSS, and JavaScript was a hassle, so download the Bootstrap template.

3. Operate the template

In Django, put HTML in the / project / app / templates folder and CSS, JavaScript in the / project / static / app folder.

HTML file processing:

-Base HTML file- Write the navigation bar and the file to be read as `{% static'project / app / file'%}`. <title>In the contents{% block title %} {% endblock %}、 <body>In the contents{% block body %} {% endblock %}write.

-HTML file to extend- The contents of the HTML file <title>` `` are {% block title%} {% endblock%}, Write the contents of the HTML file ` `` in {% block body%} {% endblock%}.

4. Edit model.py

Implement the Model considered in 0.

In this case, the point is that you can log in as your own User instead of the default. models.py (partial excerpt)

from django.contrib.auth.models import (BaseUserManager, AbstractBaseUser)

class UserManager(BaseUserManager):
    def create_user(self, username, email, password, **extra_fields):
        now = timezone.now()
        if not email:
            raise ValueError('Users must have an email address.')
        email = UserManager.normalize_email(email)
        user = self.model(
            username=username,
            email=email,
            is_active=True,
            last_login=now,
            date_joined=now,
            **extra_fields
        )
        user.set_password(password)
        user.save()
        return user

    def create_superuser(self, username, email, password, **extra_fields):
        user = self.create_user(username, email, password)
        user.is_active = True
        user.is_staff = True
        user.is_admin = True
        user.is_superuser = True
        user.save(using=self._db)
        return user


class User(AbstractBaseUser):
    username = models.CharField(_('username'), max_length=30, unique=True,)
    arc_user_name = models.CharField(_('arc name'), max_length=15, blank=True)
    email = models.EmailField(verbose_name='email address', max_length=255, unique=True)
    is_active = models.BooleanField(default=True)
    is_staff = models.BooleanField(default=False)
    is_admin = models.BooleanField(default=False)
    is_superuser = models.BooleanField(default=False)
    date_joined = models.DateTimeField(_('date joined'), default=timezone.now)
    delete = models.BooleanField(default=0)
    score = models.IntegerField(default=0)
    main_language = models.CharField(max_length=15, default='')
    objects = UserManager()

    USERNAME_FIELD = 'username'
    REQUIRED_FIELDS = ['email']

    def email_user(self, subject, message, from_email=None):
        send_mail(subject, message, from_email, [self.email])

    def has_perm(self, perm, obj=None):
        return True

    def has_module_perms(self, app_label):
        return self.is_admin

    def get_short_name(self):
        "Returns the short name for the user."
        return self.arc_user_name

    def __str__(self):
        return self.username

5. Edit views.py

--Basically, I wrote it using a class-based general-purpose view. --CreateView for user registration and result posting, TemplateView for others. --By using LoginRequiredMixin, only logged-in users can view it. --If you manage external libraries collectively with atcoder_ranking.commons.libraries, the code will be clean.

from django.contrib.auth.mixins import LoginRequiredMixin
from django.views.generic import TemplateView, CreateView
from atcoder_ranking.commons.libraries import *
from .models import *


class IndexView(LoginRequiredMixin, TemplateView):
    template_name = 'index.html'

    def get(self, _, *args, **kwargs):
        users = User.objects.all()
        results = Result.objects.all().select_related('user')
        for user in users:
            user.score = len(results.filter(user=user)) * 100
            language_list = [result.result_language for result in results.filter(user=user)]
            if language_list != []:
                #Select the most numerous language as the main language
                user.main_language = Counter(language_list).most_common(1)[0][0]
            user.save()

        context = super(IndexView, self).get_context_data(**kwargs)
        context['users'] = User.objects.all().order_by('-score')[: 3]

        return render(self.request, self.template_name, context)

6. Edit url.py

Create for the created views.py.

from django.conf.urls import url
from django.contrib import admin

import ranking.views as ranking_view

urlpatterns = [
    # admin
    url(r'^admin/?', admin.site.urls),

    # top page
    url(r'^$', ranking_view.TopView.as_view()),

    # ranking
    url(r'^ranking/?$', ranking_view.IndexView.as_view()),
    url(r'^ranking/result.png$', ranking_view.plotResults),
    url(r'^ranking/create/$', ranking_view.CreateUserView.as_view()),
    url(r'^ranking/problems/$', ranking_view.AtCoderProblemsView.as_view()),
    url(r'^ranking/get_problems/$', ranking_view.GetProblemsView.as_view()),
    url(r'^ranking/posts/$', ranking_view.PostsView.as_view()),
    url(r'^ranking/posts/(?P<posts_id>[0-9]+)/$', ranking_view.PostsDetailView.as_view()),
    url(r'^ranking/create_posts/$', ranking_view.CreatePostsView.as_view()),
    url(r'^ranking/login/$', ranking_view.LoginView.as_view(), name='login'),
    url(r'^ranking/logout/$', ranking_view.logout, name='logout')
]

7. Edit test.py

You can write it as it is, or you can use Selenium. I made a test to create a Model object using factory_boy.

factory.py

from atcoder_ranking.commons.libraries import *

from ranking.models import *


class UserFactory(factory.django.DjangoModelFactory):
    class Meta:
        model = User
    username = factory.Sequence(lambda n: 'testing_user{}'.format(n))
    arc_user_name = factory.Faker('name')
    email = factory.Sequence(lambda n: 'testuser{}@gmail.com'.format(n))
    password = factory.PostGenerationMethodCall(
        'set_password', 'ranking_password')

test.py

class IndexViewTest(TestCase):
    @classmethod
    def setUpTestData(cls):
        cls.user = UserFactory.create()

    def setUp(self):
        self.client = ServiceTestTool.login(Client(), IndexViewTest.user, 'ranking_password')

    def test_index_ranking(self):
        # create 10 testusers
        users = [UserFactory.create() for i in range(10)]
        # create posts for testusers:
        result1 = [ResultFactory.create(user=users[1]) for i in range(30)]
        result2 = [ResultFactory.create(user=users[2]) for i in range(20)]
        result3 = [ResultFactory.create(user=users[3]) for i in range(40)]
        result4 = [ResultFactory.create(user=users[4]) for i in range(10)]
        result5 = [ResultFactory.create(user=users[5]) for i in range(5)]
        result6 = [ResultFactory.create(user=users[6]) for i in range(50)]

        response = self.client.get('/ranking/')

        self.assertContains(response, users[1].username)
        self.assertContains(response, users[3].username)
        self.assertContains(response, users[6].username)
        self.assertNotContains(response, users[2].username)
        self.assertNotContains(response, users[4].username)
        self.assertNotContains(response, users[5].username)
        self.assertNotContains(response, users[0].username)

8. Try running test

$ python manage.py test

9. Move the page

$ python manage.py runserver
スクリーンショット 2017-07-01 14.44.58.png

If it is displayed like this, it is complete!

Recommended Posts

Django Tips-Create a ranking site with Django-
Create a homepage with django
Deploy a Django application with Docker
Build a web application with Django
Make a filter with a django template
Create a file uploader with Django
A site that helped me study Django
A simple RSS reader made with Django
Let's scrape a dynamic site with Docker
Creating a login screen with Django allauth
A note on enabling PostgreSQL with Django
I made a WEB application with Django
Internationalization with django
CRUD with Django
How to develop a cart app with Django
Start Django in a virtual environment with Pipenv
[Python] Build a Django development environment with Docker
Build a Django environment with Vagrant in 5 minutes
Create a dashboard for Network devices with Django!
A story about implementing a login screen with django
Build a Django development environment with Doker Toolbox
Create a one-file hello world application with django
A simple to-do list created with Python + Django
Configure a module with multiple files in Django
Quickly build a Python Django environment with IntelliJ
Access a site with client certificate authentication with Requests
Try to create a Todo management site using WebSocket with Django (Swamp Dragon)
Authenticate Google with Django
Upload files with Django
Development digest with Django
Create a Django schedule
Create a Todo app with Django REST Framework + Angular
I tried to create a table only with Django
Output PDF with Django
Markdown output with Django
Looking back on creating a web service with Django 1
A4 size with python-pptx
Twitter OAuth with Django
Create a Todo app with the Django REST framework
Getting Started with Django 1
Send email with Django
Create a Todo app with Django ③ Create a task list page
Looking back on creating a web service with Django 2
File upload with django
Use LESS with Django
[CRUD] [Django] Create a CRUD site using the Python framework Django ~ 2 ~
Pooling mechanize with Django
Transit to the update screen with the Django a tag
A memo about building a Django (Python) application with Docker
Deploy a Django app made with PTVS on Azure
Launch Django on a Docker container with docker-compose up
Use MySQL with Django
Start a Django project
Live a Haml life with Django1.8 + Jinja2 + hamlish-jinja (Python3)
Decorate with a decorator
Create a Todo app with Django ⑤ Create a task editing function
Build a development environment with Poetry Django Docker Pycharm
[CRUD] [Django] Create a CRUD site using the Python framework Django ~ 3 ~
[CRUD] [Django] Create a CRUD site using the Python framework Django ~ 4 ~
Start today with Django
[CRUD] [Django] Create a CRUD site using the Python framework Django ~ 5 ~