Памятка Django ORM

Перейдите к следующему слайду, нажав кнопку Вправо

Часто используемые команды при работе с Django ORM

Подготовлено онлайн-курсом

https://dvmn.org

Общие команды

$ sudo apt-get update && sudo apt-get install -y python3 python3-pip
$ sudo pip3 install virtualenv
$ sudo virtualenv --python=$(which python3) env
$ . env/bin/activate
(env) $
 

Установка питона и виртуального окружения

(env) $ pip3 install django==2.2.6
(env) $ django-admin startproject mysite
(env) $ cd mysite
(env) $ python manage.py runserver 0.0.0.0:8000 

Установка джанго и запуск проекта

Запуск shell

(env) $ python manage.py shell
Python 3.6.8 (default, Aug 20 2019, 17:12:48)
[GCC 8.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> from your_app_name.models import Modelname
(env) $ python manage.py startapp app

Создание приложения

Админка

from django.contrib import admin
from .models import Author, Genre, Book, BookInstance

admin.site.register(Book)
admin.site.register(Author)
admin.site.register(Genre)
admin.site.register(BookInstance)

Регистрация моделей

Создание суперпользователя

python3 manage.py createsuperuser

Вход в админку по ссылке http://127.0.0.1:8000/admin/

Достаем данные из БД

from django.db import models

class Post(models.Model):
    title = models.CharField(max_length=200)
    text = models.TextField()
    created_date = models.DateTimeField()
    published_date = models.DateTimeField()

Модель Post

>>> posts = Post.objects.all()
>>> print(posts)
>>> <QuerySet [<Post: Post object>, <Post: Post object>, <Post: Post object>]>

Как достать все данные о постах

Данные о постах в БД выглядят примерно так:

Достаем данные из БД

from django.db import models

class Post(models.Model):
    title = models.CharField(max_length=200)
    text = models.TextField()
    created_date = models.DateTimeField()
    published_date = models.DateTimeField()
>>> some_post = posts[0]
>>> print(some_post.title)
>>> Испытания дрейфующего стратостата. Запуск Рогозина и LoRa в стратосферу

Модель Post

Как достать данные из объекта

Выводим заголовок одного поста

Выводим заголовок всех постов

>>> for post in posts:
        print(post.title)
>>> Испытания дрейфующего стратостата. Запуск Рогозина и LoRa в стратосферу
Telegram. Безлимитный сетевой диск. Бесплатный
13 самых заминусованных статей минувшего года
Почему ['1', '7', '11'].map(parseInt) возвращает [1, NaN, 3] в Javascript?
...

Данные о постах в БД выглядят примерно так:

Фильтруем данные из БД

from django.db import models

class Post(models.Model):
    title = models.CharField(max_length=200)
    text = models.TextField()

    is_deleted = models.BooleanField()
    is_published = models.BooleanField()

Модель Post

published_posts = Post.objects.filter(is_published=True)
deleted_posts = Post.objects.filter(is_deleted=True)
non_published_posts = Post.objects.filter(is_published=False)
non_deleted_posts = Post.objects.filter(is_deleted=False)

Фильтрация по одному полю

Фильтруем данные из БД

from django.db import models

class Post(models.Model):
    title = models.CharField(max_length=200)
    text = models.TextField()

    is_deleted = models.BooleanField()
    is_published = models.BooleanField()

Модель Post

Фильтрация по нескольким полям

posts_to_show = Post.objects.filter(is_published=True, is_deleted=False)

Фильтруем данные из БД

from django.db import models

class Post(models.Model):
    title = models.CharField(max_length=200)
    text = models.TextField()

    is_deleted = models.BooleanField()
    is_published = models.BooleanField()

Модель Post

Операции сравнения

searched_posts = Post.objects.filter(title__contains="питон")

Заголовок содержит строку "питон":

`__gt` — (greater then, в переводе, "больше чем") проверяет, что поле больше, чем то, что передадут справа.
Пример: `filter(likes__gt=10)` — фильтруем посты, у которых больше 10 лайков.

`__lt` — (less then, "меньше чем) аналогично, проверяет, что поле меньше.


Чтобы проверить условие "больше или равно", есть операция сравнения `__gte`,
а "меньше ли равно" — `__lte`.

Связь "Один ко Многим"

from django.db import models

class Post(models.Model):
    author = models.ForeignKey(User, on_delete=models.SET_NULL)
    ...

Модель Post

from django.db import models

class User(models.Model):
    login = models.CharField(max_length=200)
    email = models.EmailField()
    birthday = models.DateField()
    avatar = models.ImageField()
    ...

Модель User

ForeignKey — это особый вид поля. Он говорит о том, что здесь мы храним ссылку на другую таблицу. Теперь можно быстро добраться до автора поста, который на самом деле хранится в другой таблице:

posts = Post.objects.all()
post = posts[0]
author = post.author
print("Логин автора:", author.login)
print("Почта автора:", author.email)
print("День рождения автора:", author.birthday)

Один(автор) ко Многим(постам)

Связь "Один ко Многим"

from django.db import models

class Post(models.Model):
    author = models.ForeignKey(User, on_delete=models.SET_NULL)
    ...

Модель Post

from django.db import models

class User(models.Model):
    login = models.CharField(max_length=200)
    email = models.EmailField()
    birthday = models.DateField()
    avatar = models.ImageField()
    ...

Модель User

Один(автор) ко Многим(постам)

Например, мы хотим найти все статьи автора с логином voron434:

author = User.objects.filter(login="voron434")[0]
posts_by_this_author = Post.objects.filter(author=author)

По-хорошему, этот код следует упаковывать в один-единственный вызов filter:

author = Post.objects.filter(author__username="voron434")

Связь "Один ко Многим"

from django.db import models

class Reporter(models.Model):
    first_name = models.CharField(max_length=30)
    last_name = models.CharField(max_length=30)
    email = models.EmailField()

Создадим журналистов Джона и Пола

>>> reporter_1 = Reporter(first_name='John', last_name='Smith', email='john@example.com')
>>> reporter_1.save()

>>> reporter_2 = Reporter(first_name='Paul', last_name='Jones', email='paul@example.com')
>>> reporter_2.save()

Другой пример



class Article(models.Model):
    headline = models.CharField(max_length=100)
    pub_date = models.DateField()
    reporter = models.ForeignKey(Reporter, on_delete=models.CASCADE)

Связь "Один ко Многим"

from django.db import models

class Reporter(models.Model):
    first_name = models.CharField(max_length=30)
    last_name = models.CharField(max_length=30)
    email = models.EmailField()

Другой пример

>>> from datetime import date
>>> article = Article(id=None, headline="This is a test", \
... pub_date=date(2005, 7, 27), reporter=reporter_1)
>>> article.save()

Создадим статью Джона вот так



class Article(models.Model):
    headline = models.CharField(max_length=100)
    pub_date = models.DateField()
    reporter = models.ForeignKey(Reporter, on_delete=models.CASCADE)

А можно создать статью и так(через объект журналиста Джона)

>>> new_article = reporter_1.article_set.create(headline="John's second story", \
... pub_date=date(2005, 7, 29))
>>>
>>> new_article.reporter
<Reporter: John Smith>
>>> new_article2 = Article(headline="Paul's story", pub_date=date(2006, 1, 17))
>>> new_article2.save()
>>> reporter_2.article_set.add(new_article2)
>>> new_article2.reporter
<Reporter: Paul Jones>

А теперь создадим статью журналиста Пола

ДОДЕЛАТЬ

Связь "Один ко Многим"

from django.db import models

class Reporter(models.Model):
    first_name = models.CharField(max_length=30)
    last_name = models.CharField(max_length=30)
    email = models.EmailField()

Другой пример

>>> reporter_1.article_set.all()
[<Article: John's second story>, <Article: This is a test>]

Посмотрим, что есть у Джона



class Article(models.Model):
    headline = models.CharField(max_length=100)
    pub_date = models.DateField()
    reporter = models.ForeignKey(Reporter, on_delete=models.CASCADE)
>>> reporter_2.article_set.all()
[<Article: Paul's story>]

И у Пола

>>> reporter_2.article_set.add(article)
>>> reporter_2.article_set.all()
[<Article: Paul's story>, <Article: This is a test>]

Добавим статью `article` к  набору статей  Пола и проверим, что она переместилась:

CRUD

from django.db import models

class Post(models.Model):
    title = models.CharField(max_length=200, unique=True)

    text = models.TextField()

При работе с базами данных есть 4 базовые операции: создание (create), чтение (read), редактирование (update) и удаление (delete). Все 4 базовые функции называют коротко CRUD — по первым буквам каждой операции.

Модель Post

Read(чтение)

title = "CRUD"
crud_post = Post.objects.get(title=title)

Если поста с заголовком "CRUD" не окажется в базе, вы получите ошибку:

>>> models.DoesNotExist: Post matching query does not exist.

Это обычное исключение, его можно перехватить и обработать

CRUD

from django.db import models

class Post(models.Model):
    title = models.CharField(max_length=200, unique=True)

    text = models.TextField()

При работе с базами данных есть 4 базовые операции: создание (create), чтение (read), редактирование (update) и удаление (delete). Все 4 базовые функции называют коротко CRUD — по первым буквам каждой операции.

Модель Post

Create(создание)

Post.objects.create(title="Заголовок нового поста", text="Текст нового поста")

Пост создан и лежит в БД:

post = Post.objects.get(title="Заголовок нового поста")
print(post.title)
# Заголовок нового поста

CRUD

from django.db import models

class Post(models.Model):
    title = models.CharField(max_length=200, unique=True)

    text = models.TextField()

При работе с базами данных есть 4 базовые операции: создание (create), чтение (read), редактирование (update) и удаление (delete). Все 4 базовые функции называют коротко CRUD — по первым буквам каждой операции.

Модель Post

Update(редактирование)

post = Post.objects.get(title="Заголовок нового поста")
post.title = "От чего вымерли динозавры?"
post.save()

CRUD

from django.db import models

class Post(models.Model):
    title = models.CharField(max_length=200, unique=True)

    text = models.TextField()

При работе с базами данных есть 4 базовые операции: создание (create), чтение (read), редактирование (update) и удаление (delete). Все 4 базовые функции называют коротко CRUD — по первым буквам каждой операции.

Модель Post

Delete(удаление)

post = Post.objects.get(title="Новый заголовок")
post.delete()  # Удалили пост из БД

Удаление отдельного поста:

Удаление целой выборки - Queryset:

all_posts = Post.objects.all()
all_posts.delete()  # Удалили все посты из БД

Методы QuerySet

from django.db import models

class Blog(models.Model):
    name = models.CharField(max_length=100)
    tagline = models.TextField()

    def __str__(self):              # __unicode__ on Python 2
        return self.name

class Author(models.Model):
    name = models.CharField(max_length=50)
    email = models.EmailField()

    def __str__(self):              # __unicode__ on Python 2
        return self.name

class Entry(models.Model):
    blog = models.ForeignKey(Blog)
    headline = models.CharField(max_length=255)
    body_text = models.TextField()
    pub_date = models.DateField()
    mod_date = models.DateField()
    authors = models.ManyToManyField(Author)
    n_comments = models.IntegerField()
    n_pingbacks = models.IntegerField()
    rating = models.IntegerField()

    def __str__(self):              # __unicode__ on Python 2
        return self.headline

Возвращает количество записей в базе данных отвечающем запросу QuerySet.

Метод count() никогда не вызывает исключение.

# Returns the total number of entries in the database.
Entry.objects.count()

# Returns the number of entries whose headline contains 'Lennon'
Entry.objects.filter(headline__contains='Lennon').count()

Методы QuerySet

Создано для онлайн-курса https://dvmn.org