کدستانِ من

۲ مطلب با کلمه‌ی کلیدی «دیتابیس» ثبت شده است

  • ۰
  • ۰

مدل ها در جنگو با فیلدهایی مانند CharField، IntegerField، BooleanField و ... تعریف می شوند. این فیلدها برای دیتابیس sqlite3 که بصورت پیش فرض در جنگو وجود دارد مورد استفاده قرار می گیرند.

اگر ما دیتابیس را به جای sqlite3 به Postgres تغییر دهیم این دیتابیس تعدادی فیلدهای مختص خود را به مدل های ما اضافه می کند. این فیلدها شامل JSONField، HStoreField، CITextField، ArrayField و فیلدهای Range هستند. در این پست به معرفی ‌ArrayField می پردازیم.

این فیلد همانطور که از نامش پیداست به ما این امکان را می دهد که آرایه ای از داده ها را به دیتابیس اضافه کنیم. داده های آرایه باید از یک نوع باشند.

class ArrayField(base_field, size=None, **options)

base_field همان نوع داده های ورودی است که تعریف آن اجباری است و نوع آن باید از فیلدهای مدل مشخص شود برای نمونه نوع آن می تواند CharField یا IntegerField تعریف شود. نوع آن می تواند از نوع آرایه هم باشد. یعنی آرایه ای از آرایه ها داشته باشیم. استفاده از همه ی مدل ها به جز فیلدهای ارتباطی یعنی OneToOneField، ForeignKey و ManyToManyField ممکن است.

آرگومان ورودی Size حداکثر سایز آرایه را مشخص می کند و تعریف آن اختیاری است. البته در حال حاضر دیتابیس Postgres اندازه ی آرایه را به این سایر محدود نمی کند و آن را نادیده می گیرد.


from django.contrib.postgres.fields import ArrayField
from django.db import models


class Product(models.Model):
    name = models.CharField(max_length=200)
    colors = ArrayField(models.CharField(max_length=20, blank=True))

جستجو در ArrayField

علاوه بر راه های جستجویی که برای همه ی مدل ها وجود دارد ArrayField تعدادی فیلد جستجوی مختص هم دارد. در این بخش از مدل تعریف شده ی بالا استفاده می شود که سه نمونه شیء زیر از آن در دیتابیس ساخته شده اند.

>>> Product.objects.create(name='Mobile phone Samsung', colors=['red','white','black'])
>>> Product.objects.create(name='Laptop Toshiba 2020', colors=['black'])
>>> Product.objects.create(name='IPad', colors=['white','yellow'])

۱) contains

جستجوی شامل بودن. در واقع مقدار ورودی باید زیرمجموعه ای از داده ها باشد.

>>> Product.objects.filter(colors__contains=['black'])

که نتیجه ی زیر را به ما می دهد:


<QuerySet [<Product: Mobile phone Samsung>, <Product: Laptop Toshiba 2020>]>

۲) contained_by

برعکس جستجوی بالا عمل می کند به طوری که داده های ذخیره شده باید زیرمجموعه ای از مقدار ورودی باشند.

۳) overlap

این جستجو برای این به کار می رود که هرگونه اشتراکی بین داده ها و مقدار ورودی را پیدا کند.

۴) len

طول آرایه را برمیگرداند.

>>> Product.objects.filter(colors__len=1)

که نتیجه ی زیر را به ما می دهد:

 

<QuerySet [<Product: Laptop Toshiba 2020>]>

۵) index transform

جستجوی ایندکسی آرایه را برمیگرداند.
 

>>> Product.objects.filter(colors__1='white')
>>> Product.objects.filter(colors__100='red')

که به ترتیب چنین نتیجه ای دارند:

 

<QuerySet [<Product: Mobile phone Samsung>]>

<QuerySet []>

۶) slice transform

جستجوی بخشی از آرایه را برمیگرداند.

  • سارا الف
  • ۰
  • ۰

همانطور که می دانید Django ORM ابزاری برای ایجاد، حذف، بازیابی و به روز رسانی داده ها در دیتابیس را در اختیار ما قرار داده است. گاهی در ارتباط با دیتابیس به عملیات پیچیده تری نیاز داریم. یکی از ابزارهای در دسترس aggregate و annotate هستند که برای متراکم کردن یا خلاصه سازی اطلاعات به کار می روند. اگر درخواست های ما به دیتابیس شامل عملیاتی مثل شمردن، میانگین گیری، جمع کردن، یافتن ماکزیمم و مینیمم باشد می توان از aggregate و annotate استفاده کرد.

 

در مثال های این بخش از مدل های زیر استفاده شده است:


class Brand(models.Model):
    name = models.CharField(max_length=50)

class Product(models.Model):
    name = models.CharField(max_length=100)
    brand = models.ForeignKey(Brand, on_delete=models.CASCADE)
    price = models.PositiveIntegerField()
    amount = models.PositiveSmallIntegerField()

اگر بخواهیم آمارگیری را از کل یک QuerySet انجام بدهیم از aggregate استفاده می کنیم. برای مثال اگر بخواهیم تعداد کل محصولات را پیدا کنیم یک روش موجود، استفاده از aggregate است.


from django.db.models import Sum

Product.objects.aggregate(Sum('amount'))
>>>{'amount__sum': 114}

همانطور که می بینید aggregate یک دیکشنری پایتون برمی گرداند. در نتیجه نمی توان روی نتیجه ی آن از متدهای کوئری ست مثل filter، values و ... استفاده کرد.

حال می خواهیم تعداد محصولات را در هر برند پیدا کنیم. در این حالت دیگر نمی خواهیم نتیجه را از کل داده ها پیدا کنیم بلکه هدف پیدا کردن نتیجه در هر گروه برندها است. در این صورت دیگر نمی توان از aggregate استفاده کرد و به جای آن باید از annotate استفاده کرد.
متد
annotate در واقع GROUP BY دیتابیس های SQL را پیاده سازی می کند. این متد برخلاف aggregate لیستی از کوئری ست ها را بر می گرداند در نتیجه می توان روی آن عملیاتی مثل filter، values، order_by و ... را انجام داد.
پیدا کردن تعداد محصولات هر برند با
SQL به شکل زیر انجام می شود:

SELECT Brand.name, SUM(Product.amount) AS Brand_sum
FROM Brand LEFT OUTER JOIN Product ON Brand.id=Product.brand
GROUP BY Brand.name;

همین دستور SQL را می توان با annotate به شکل زیر پیاده سازی کرد:
 


from django.db.models import Sum

brands = Brand.objects.annotate(brand_sum=Sum('product__amount'))
for brand in brands:
    print(brand.name, ' : ', brand.brand_sum)

که کوئری متناظر با آن در جنگو ORM به صورت زیر است:

SELECT "test_group_brand"."id", "test_group_brand"."name", SUM("test_group_product"."amount") AS "brand_sum"
FROM "test_group_brand" LEFT OUTER JOIN "test_group_product" ON ("test_group_brand"."id" = "test_group_product"."brand_id")
GROUP BY "test_group_brand"."id", "test_group_brand"."name"

 

البته مسئله ی بالا را می توان به شکل زیر هم نوشت:


from django.db.models import Sum

brands = Product.objects.values('brand__name').annotate(brand_sum=Sum('amount'))


که کوئری متناظر با آن به این صورت است:
 

SELECT "test_group_brand"."name", SUM("test_group_product"."amount") AS "brand_sum"
FROM "test_group_product" INNER JOIN "test_group_brand" ON ("test_group_product"."brand_id" = "test_group_brand"."id")
GROUP BY "test_group_brand"."name"

همانطور که گفته شد می توان متدهای کوئری ست را روی نتیجه ی annotate اعمال کرد. برای مثال اگر بخواهیم نام برندهایی که بیش از ۷۰۰ عدد موجودی دارند را مشخص کنیم از قطعه کد زیر استفاده می کنیم:

 


from django.db.models import Sum

brands = Brand.objects.annotate(brand_sum=Sum('product__amount')).filter(brand_sum__gt=700).values('name','brand_sum')

که کوئری آن برابر است با:

SELECT "test_group_brand"."name", SUM("test_group_product"."amount") AS "brand_sum"
FROM "test_group_brand" LEFT OUTER JOIN "test_group_product" ON ("test_group_brand"."id" = "test_group_product"."brand_id")
GROUP BY "test_group_brand"."id", "test_group_brand"."name"
HAVING SUM("test_group_product"."amount") > 400

  • سارا الف