Python Django Tutorial (8)

This is a material for study sessions. In this tutorial, a supplementary explanation for Django's Model and I will introduce a library that extends the functions of django, and try various operations on the shell.

Other tutorials

Model supplement

There was an opinion that the relationship between Model, Field, and instance is difficult to understand, so I will supplement it.

Relationship between python code and DB (table)

Model represents a DB table. It can be changed by setting the table name to Meta, but by default it will be named app name_model name. For the Question model in the polls app, the table name will be polls_question.

The models. ~ Field defined in the Model correspond to the columns on the table. The id column is automatically added if there is no field for which PrimaryKey is set as.

An instance of Model means one record on the DB table.

polls/models.py


class Question(models.Model):
    class Meta:
        verbose_name = 'Question'
        verbose_name_plural = 'Plural of questions'
        ordering = ['-pub_date']

    question_text = models.CharField(max_length=200)
    pub_date = models.DateTimeField('date published')

Kobito.CVWNC3.png

This and that for getting records (instances)

It is necessary to issue a SQL statement to get the record from the table on the DB. To do this, Model has a Manager class. The QuerySet class is responsible for the actual issuance and generation of SQL, and after issuing sql, the instance of the base Model is returned. Operations such as record acquisition and creation are performed through this QuerySet class. The Manager class acts as a relay between Model and QuerySet, and is especially closely related to QuerySet.

Kobito.hB5eZg.png

QuerySet also has methods like get and create to get and create records pinpointly. Since iterator is provided, the records (= instances) to be acquired can be acquired in order by turning itself in a for loop.

qs = Question.objects.all()
for q in qs:
   #  q <---This is the acquired record and becomes an instance of Question

Method isolation

Source → 8a9d88559ae94bea8bb706468eaa6459127c6f59

Since Model = table and instance = record, the process you want to perform on the record is defined by the instance method. Conversely, the processing you want to perform on the table itself is defined as a class method.

For example, the was_published_recently created in the tutorial It is an instance method because it is "determination of whether the record (= instance) has been published recently".

Apart from this, in the case of the method "Get published from Question table", make it a class method.

polls/models/py


class Question(models.Model):
...
    @classmethod
    def get_published_data(cls):
        return cls.objects.filter(pub_date__lte=timezone.now())

In the case of a filter that gets "published" as shown in the example It's a bit verbose, but it's also a good idea to extend the QuerySet.

polls/models.py(QuerySet extension)


import datetime

from django.db import models
from django.utils import timezone


class QuestionQuerySet(models.query.QuerySet):
    def is_published(self):
        return self.filter(pub_date__lte=timezone.now())


class Question(models.Model):
...

    objects = models.Manager.from_queryset(QuestionQuerySet)()

...

    @classmethod
    def get_published_data(cls):
        return cls.objects.is_published()

In either case You can get the published queryset by doing Question.get_published_data ().

However, when Model is extended directly, pk is 10 or less and has been published. You cannot put a condition in the middle.

Question.get_published_date().filter(pk__lte=10) Like, if the condition is "published, pk is 10 or less", it will be applied.

On the other hand, in the case of the extension of QuerySet, you can apply a filter to get "published ones" wherever you like. Question.objects.filter(pk__lte=10).is_published()

Play with shell

In django, you can directly operate Model etc. by operating with manage.py shell command. I will introduce a library to use the shell a little more conveniently.

First of all, ʻipython. If you put this in, it will be able to colorize the shell and complete commands. Next, django-extensions`. It provides various extensions to django, as the name implies, as well as the shell.

Both can be easily installed with pip, so please try them. $ pip install ipython $ pip install django-extensions

For ipython, just execute $ ./manage.py shell and the appearance will change automatically. django-extensions needs to be added to INSTALL_APPS in settings.

tutorial/settings.py


...
INSTALLED_APPS = (
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'django_extensions',  #←←← Add this
    'bootstrap3',
    'polls',
)
...

If set to ʻINSTALLED_APPS, the manage.py` command will allow you to run commands for django_extensions.

$ ./manage.py

Type 'manage.py help <subcommand>' for help on a specific subcommand.

Available subcommands:
...
[django_extensions]
    admin_generator
    clean_pyc
    clear_cache
    compile_pyc
    create_app
    create_command
    create_jobs
    create_template_tags
    describe_form
    drop_test_database
    dumpscript
    export_emails
    find_template
    generate_secret_key
    graph_models
    mail_debug
    notes
    passwd
    pipchecker
    print_settings
    print_user_for_session
    reset_db
    runjob
    runjobs
    runprofileserver
    runscript
    runserver_plus
    set_default_site
    set_fake_emails
    set_fake_passwords
    shell_plus
    show_template_tags
    show_templatetags
    show_urls
    sqlcreate
    sqldiff
    sqldsn
    sync_s3
    syncdata
    unreferenced_files
    update_permissions
    validate_templates
...

This time, we will use shell_plus, which is an extension of the shell command. By adding the --print-sql option at startup, you can also see the SQL statement at the time of instance acquisition, so let's add it.

$ ./manage.py shell_plus --print-sql
# Shell Plus Model Imports
from django.contrib.admin.models import LogEntry
from django.contrib.auth.models import Group, Permission, User
from django.contrib.contenttypes.models import ContentType
from django.contrib.sessions.models import Session
from polls.models import Choice, Question
# Shell Plus Django Imports
from django.db import transaction
from django.core.urlresolvers import reverse
from django.utils import timezone
from django.core.cache import cache
from django.db.models import Avg, Count, F, Max, Min, Sum, Q, Prefetch, Case, When
from django.conf import settings
Python 3.5.1 (default, Jan 23 2016, 02:16:23)
Type "copyright", "credits" or "license" for more information.

IPython 4.2.0 -- An enhanced Interactive Python.
?         -> Introduction and overview of IPython's features.
%quickref -> Quick reference.
help      -> Python's own help system.
object?   -> Details about 'object', use 'object??' for extra details.

In [1]:

In shell, I had to manually import the Model I wanted to use, shell_plus will automatically load the model when you start it.

Let's execute the get_published_data command created earlier.

In [1]: Question.get_published_data()
Out[1]: SELECT "polls_question"."id", "polls_question"."question_text", "polls_question"."pub_date" FROM "polls_question" WHERE "polls_question"."pub_date" <= '2016-06-23 06:45:46.716854' ORDER BY "polls_question"."pub_date" DESC LIMIT 21

Execution time: 0.001740s [Database: default]

[<Question:Second question>, <Question: what's up?>, <Question:Third question>]

In [2]:

This time, the --print-sql option is added, so you can check the SQL statement executed in this way.

Try to register the data

There are two ways to register data, one is from the Manager (queryset) and the other is to directly operate the instance.

Let's try from create first. Since it is necessary to put the date in pub_date, import django.utils.timezone in advance and specify today's date and time in pud_date.

In [3]: from django.utils import timezone

In [4]: Question.objects.create(pub_date=timezone.now())
BEGIN

Execution time: 0.000028s [Database: default]

INSERT INTO "polls_question" ("question_text", "pub_date") VALUES ('', '2016-06-23 07:02:01.013534')

Execution time: 0.000638s [Database: default]

Out[4]: <Question: >

This will register a new record in the DB.

In [5]: Question.objects.count()
SELECT COUNT(*) AS "__count" FROM "polls_question"

Execution time: 0.000154s [Database: default]

Out[5]: 4

Next, let's try creating from an instance. In the case of an instance, just creating it will not be reflected in the DB record. By executing save () of the instance, if the record exists, it will be updated, and if it does not exist, it will be inserted.

In [6]: ins = Question(pub_date=timezone.now(), question_text='Create from instance')

In [7]: ins
Out[7]: <Question:Create from instance>

In [8]: Question.objects.count()
SELECT COUNT(*) AS "__count" FROM "polls_question"

Execution time: 0.000177s [Database: default]

Out[8]: 4  #←←←←←←← Not made yet at this point.

In [9]: ins.save()  #←←←←←← Record update method execution here
BEGIN

Execution time: 0.000032s [Database: default]

INSERT INTO "polls_question" ("question_text", "pub_date") VALUES ('Create from instance', '2016-06-23 07:07:46.485479')

Execution time: 0.001240s [Database: default]


In [10]: Question.objects.count()
SELECT COUNT(*) AS "__count" FROM "polls_question"

Execution time: 0.000167s [Database: default]

Out[10]: 5  #←←←←←←← inserted

filter various

After registering some data, let's try various things by getting records. There are several methods, but for the time being, there is no problem if you remember filter and ʻexclude` to narrow down by conditions. The filter will leave records that match the conditions. Exclude is the opposite, and records that do not match the conditions will remain.

Pass field name = condition as an argument of filter. By adding a character such as __lte after the field name, it is not an exact match, and the conditions can be changed as follows. Please refer to Official Document for what conditions can be used.

OR search

Official Documents

Finally, the method of specifying the OR condition is described. Since all filters (exclude) are AND, use the Q class to perform an OR search for conditions. Q creates an instance with field name = condition as specified by filter. OR search can be realized by passing the conditions created there to the filter of QuerySet. For Q, the logical symbols & (and) | (or) ~ (not) can be used.

In [12]: from django.db.models import Q

In [13]: q1 = Q(pk=1)

In [14]: q2 = Q(pk=2)

In [15]: Question.objects.filter(q1|q2)
Out[15]: SELECT "polls_question"."id", "polls_question"."question_text", "polls_question"."pub_date" FROM "polls_question" WHERE ("polls_question"."id" = 1 OR "polls_question"."id" = 2) ORDER BY "polls_question"."pub_date" DESC LIMIT 21

Execution time: 0.000390s [Database: default]

[<Question:Second question>, <Question: what's up?>]

The next tutorial is undecided.

Other tutorials

Recommended Posts

Python Django Tutorial (5)
Python Django Tutorial (2)
Python Django Tutorial (8)
Python Django Tutorial (6)
Python Django Tutorial (7)
Python Django Tutorial (1)
Python Django tutorial tutorial
Python Django Tutorial (3)
Python Django Tutorial (4)
Python Django tutorial summary
Python tutorial
Python Django Tutorial Cheat Sheet
Python tutorial summary
django tutorial memo
Start Django Tutorial 1
Django 1.11 started with Python3.6
[Docker] Tutorial (Python + php)
Django python web framework
Django Polymorphic Associations Tutorial
django oscar simple tutorial
Try Debian + Python 3.4 + django1.7 ...
[Personal notes] Python, Django
Python OpenCV tutorial memo
[Python tutorial] Data structure
Django Girls Tutorial Note
Cloud Run tutorial (python)
Python Django CSS reflected
Do Django with CodeStar (Python3.6.8, Django2.2.9)
Get started with Django! ~ Tutorial ⑤ ~
Introduction to Python Django (2) Win
[Python tutorial] Control structure tool
Python
Do Django with CodeStar (Python3.8, Django2.1.15)
Python3 + Django ~ Mac ~ with Apache
Create ToDo List [Python Django]
Getting Started with Python Django (1)
Django
Getting Started with Python Django (4)
Getting Started with Python Django (3)
Get started with Django! ~ Tutorial ⑥ ~
Install Python 3.7 and Django 3.0 (CentOS)
[Python] Decision Tree Personal Tutorial
GAE + python + Django addictive story
Getting Started with Python Django (6)
Getting Started with Python Django (5)
Until Python [Django] de Web service is released [Tutorial, Part 1]
8 Frequently Used Commands in Python Django
Create new application use python, django
python + django + scikit-learn + mecab (1) on heroku
python + django + scikit-learn + mecab (2) on heroku
Run python3 Django1.9 with mod_wsgi (deploy)
Django Girls Tutorial Summary First Half
Stumble when doing the django 1.7 tutorial
Deploy the Django tutorial to IIS ①
Install Python framework django using pip
Introduction to Python Django (2) Mac Edition
[Python Tutorial] An Easy Introduction to Python
Learning history for participating in team app development in Python ~ Django Tutorial 5 ~
Learning history for participating in team app development in Python ~ Django Tutorial 4 ~
Learning history for participating in team app development in Python ~ Django Tutorial 1, 2, 3 ~
Learning history for participating in team app development in Python ~ Django Tutorial 6 ~