Django Queryset API является достаточным.


Давайте изучим Django Queryset API более подробно.


Составление эффективных запросов к базе данных – один из самых важных навыков в работе любого бэкенда. Запросы могут либо сделать ваше приложение, либо уничтожить его. Оптимизация вашего приложения с бэкенда заключается в написании эффективных алгоритмов. Разработчики Django потратили достаточно времени на написание этих сложных алгоритмов для повторного использования другими разработчиками. Если вам, как и мне, интересно узнать, что происходит. Вам следует изучить проект django на Github.

Сегодня мы сосредоточимся на приложении на базе Django и на том, как мы можем использовать встроенный API queryset, чтобы ускорить не только время разработки, но и время отклика вашего приложения.

Наши модели

from django.db import models
from django.conf import settings

class BaseModel(models.Model):
    created_at = models.DateTimeField(auto_now_add=True)
    modified_at = models.DateTimeField(auto_now=True)
    user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)

    class Meta:
        abstract = True


class Investment(BaseModel):
    title = models.CharField(max_length=200)
    interest = models.DecimalField(decimal_places=2, max_digits=4)
    min_invest = models.DecimalField(decimal_places=2, max_digits=8)
    max_invest = models.DecimalField(decimal_places=2, max_digits=8)
    duration = models.DurationField()
    active = models.BooleanField(default=False)

   def __str__(self) -> str:
       return self.title

   class Meta:
        verbose_name_plural = "Investment"
        ordering = "-created_at"


class UserInvest(BaseModel):
     amount = models.DecimalField(max_digits=4, decimal_places=2)
     package = models.ForeignKey(Investment, on_delete=models.PROTECT)
     started = models.BooleanField(default=False)

     def __str__(self) -> str:
        return f"{self.user.username} invested {self.amount} in {self.package.title) package"

     ''' other methods for comes in. 
I love writing fat models because it makes my work easy 
and makes the application code to have one source of truth 

Note: You should always use django.utils.translation for translation.

'''

Вход в полноэкранный режим Выход из полноэкранного режима

Наши представления

Здесь начинается самое интересное. Мы затронем каждую часть queryset api и покажем вам более сложные методы запросов к базе данных.

Получите все запросы в обратном порядке.

'''
We will make database queries through our models.
Note: we assume that we have enough data in our database to work with.
'''

from django.views.generic import ListView
from django.db.models.query import Q

from myapp.investment.models import Investment, UserInvest


class InvestmentListView(ListView):
    template_name = "investment/investment_list.html"
    model = Investment
    context_object_name = "investment"

    def get_queryet(self, **kwargs):
        return super().get_queryset(self, kwargs).order_by("-created_at")
Войти в полноэкранный режим Выход из полноэкранного режима

Запрос выше перечисляет все инвестиционные пакеты, которые есть у компании, начиная с самого последнего. Django предлагает эффективный способ оптимизации. Вместо использования встроенных методов python, django предоставляет хороший api для оптимизации такого запроса.

Примечание: Не используйте встроенные методы python, если django предоставил альтернативу. вместо reverse(queries) используйте
queries.order_by() или передайте ключевые слова упорядочивания в мета-классе модели.

#You can pass in the ordering keywords with the model to re-order your data. like

class Meta:
    ordering = "-created_at"

# OR use

def get_querset(self, **kwargs):
    return super().get_queryset(self, kwargs).order_by("-created_at")

Вход в полноэкранный режим Выход из полноэкранного режима

Альтернативы распространенным запросам

вместо использования this для проверки существования объектов.

for investment in Investment.objects.all():
    if investment.title == "UBA stock":
       print(f"investment.title exists")
Войти в полноэкранный режим Выйти из полноэкранного режима

Сделать это

Investment.objects.filter(title="UBA stock").exist()
Войти в полноэкранный режим Выйти из полноэкранного режима

Для подсчета объектов используйте

Investment.objects.count()
Войти в полноэкранный режим Выйти из полноэкранного режима

Для выделения нескольких первых/последних элементов используйте нарезку

Investment.objects.all()[:5]
Войти в полноэкранный режим Выйти из полноэкранного режима

Чтобы использовать условия при получении объектов, попробуйте отфильтровать их по такому условию,

from django.db.model.query import Q

Investment.objects.filter(active=True, created_at__month=datetime.datetime.now().month)

## complex queries use Q objects
invest = Q(Investment.objects.filter(active=True) | Investment.objects.filter(completed=True))
Войти в полноэкранный режим Выйти из полноэкранного режима

Чтобы исключить некоторые объекты с определенными условиями, попробуйте следующее

Investment.objects.exclude(created_at__gt=datetime.date(2022, 6, 2), title='Morgan Stock')
Войти в полноэкранный режим Выйти из полноэкранного режима

NB: Вы можете объединить эти отдельные запросы в цепочку для выполнения более сложных запросов.

Чтобы отменить запросы

Investment.objects.reverse()
Войдите в полноэкранный режим Выйти из полноэкранного режима

Чтобы получить запросы, которые имеют разные значения

Investment.objects.order_by('created_at').distinct('created_at')
Войдите в полноэкранный режим Выйти из полноэкранного режима

Чтобы выполнить запрос по значениям

Investment.objects.filter(title__istartswith="UBA")
Investment.objects.filter(title__iendswith="stock")
Investment.objects.filter(title__icontains="stock")

## These are case sensitive operations, so i prefer using i to prefix the startswith or endswith

Войти в полноэкранный режим Выйти из полноэкранного режима

Что из дат

>>> Investment.objects.dates('created_at', 'year')
[datetime.date(2022, 1, 1)]
>>> Investment.objects.dates('created_at', 'month')
[datetime.date(2022, 2, 1), datetime.date(2022, 3, 1)]
>>> Investment.objects.dates('created_at', 'week')
[datetime.date(2022, 2, 14), datetime.date(2022, 3, 14)]
>>> Investment.objects.dates('created_at', 'day')
[datetime.date(2022, 2, 20), datetime.date(2022, 3, 20)]
>>> Investment.objects.dates('created_at', 'day', order='DESC')
[datetime.date(2022, 3, 20), datetime.date(2022, 2, 20)]
>>> Investment.objects.filter(title__contains='UBA').dates('pub_date', 'day')
[datetime.date(2022, 3, 20)]
Войти в полноэкранный режим Выйти из полноэкранного режима

Если вы хотите объединить несколько разных запросов, используйте объединение

invest1 = Investment.objects.filter(active=True)
invest2 = Investment.objects.filter(completed=True)
invest3 = Investment.objects.filter(active=False)

invest = invest1.union(invest2)
invest4 = invest1.union(invest2, invest3)
Войти в полноэкранный режим Выйти из полноэкранного режима

Чтобы получить пересечение двух запросов, используйте

invest1 = Investment.objects.filter(active=True)
invest2 = Investment.objects.filter(completed=True)
invest3 = Investment.objects.filter(active=False)

invest = invest1.intersection(invest2)

Войти в полноэкранный режим Выйти из полноэкранного режима

Чтобы получить разность двух запросов, используйте

invest1 = Investment.objects.filter(active=True)
invest2 = Investment.objects.filter(completed=True)
invest3 = Investment.objects.filter(active=False)

invest = invest1.difference(invest2)

Войти в полноэкранный режим Выйти из полноэкранного режима

Если у вас есть объекты, между которыми есть связи, и вы не хотите делать несколько запросов к базе данных для получения связей, используйте функцию select_related или prefetch_related

UserInvest.objects.select_related("package").get(id="7")
UserInvest.objects.filter(amount__gte=200).prefetch_related("package")
UserInvest.objects.filter(amount__gte=200).select_related("package")
Войти в полноэкранный режим Выход из полноэкранного режима

Есть много вещей, происходящих при использовании select_related или prefetch related. Я предлагаю вам посмотреть документацию django и понять, как они обе выполняют свои запросы.

Вместо того, чтобы писать сырые запросы, используя объекты курсора, используйте django select и дополнительную функцию


Investment.objects.extra(select={'is_recent': "created_at > '2022-01-01'"})

UserInvest.objects.extra(
    select={
        'entry_count': 'SELECT COUNT(*) FROM userinvest_entry WHERE userinvest_entry.userinvest_id = userinvest_userinvest.id'
    },
)

## This query might not make much sense, but it shows what is possible.
Войти в полноэкранный режим Выйти из полноэкранного режима

В некоторых сложных ситуациях моделирования данных ваши модели могут содержать множество полей, некоторые из которых могут содержать большое количество данных (например, текстовые поля) или требовать дорогостоящей обработки для преобразования их в объекты Python. Если вы используете результаты набора запросов в ситуации, когда вы не знаете, нужны ли вам эти конкретные поля при первоначальном получении данных, вы можете сказать Django не извлекать их из базы данных. используйте defer в этом случае

UserInvest.objects.defer("package")
Войти в полноэкранный режим Выйти из полноэкранного режима

Если вы хотите отложить все остальные поля, кроме некоторых, используйте only.

Investment.objects.only("title", "duration").only("user")
Войти в полноэкранный режим Выйти из полноэкранного режима

Если вы подключены к нескольким базам данных и хотите использовать определенную базу данных, используйте using для указания базы данных.

Investment.objects.using('backup')
Войти в полноэкранный режим Выйти из полноэкранного режима

К первому или последнему запросу

p = Investment.objects.order_by('title', 'created_at').first()
q = Investment.objects.order_by('title', 'created_at').last()
Войти в полноэкранный режим Выйти из полноэкранного режима

Чтобы подсчитать или суммировать поле, используйте функцию Агрегат и Сумма

from django.db.models.aggregates import Sum, Count
q = Investment.objects.aggregate(Count('title'))
total_amount = UserInvest.objects.aggregate(Sum("amount"))
Войти в полноэкранный режим Выйти из полноэкранного режима

Django предоставляет множество api для выполнения высоко оптимизированных запросов. Все, что вам нужно сделать, это прочитать документацию

Счастливого кодинга!!!

Оцените статью
Procodings.ru
Добавить комментарий