جواد جهانگیری
جواد جهانگیری
خواندن ۱۱ دقیقه·۳ سال پیش

آموزش نحوه کار با Django ORM | Django ORM | جنگو ORM

به نام آن که جان را فکرت آموخت / چراغ دل به نور جان برافروخت

با عرض سلام و وقت بخیر خدمت کاربران محترم سایت ویرگول، در این مقاله آموزشی که چکیده آموزش جنگو ORM از سایت Django documentation بهمراه مطالب تکمیلی تر , سعی شده یک آموزش کاربردی و پروژه محور از جنگو ORM ارایه گردد.ایده این سری مقاله های آموزشی از این موضوع سرچشمه می گیرد که بخشی از خوانندگان وجود دارد که به محتوای نوشتاری آنلاین بهتر پاسخ می دهند و ترجیج می دهند مهارت های جدید را به سرعت از طریق خواندن افزایش دهند.این سری آموزش ها با ارایه اولین پکیج آموزشی در خصوص جنگو آغاز می شود که انتظار می رود با واکنش مثبت کاربران همراه شود.

Django ORM
Django ORM

توجه: این مقاله به مرور زمان، ویرایش و یا تکمیل می‌شود!
تقاضا: در صورتی که با مشکل تایپی، دستوری و یا مفهومی در این مقاله برخورد کردید، از شما دوست عزیز و گرامی، صمیمانه تقاضا می‌کنم که اینجانب را مطلع کرده، تا نسبت به تصحیح و یا تکمیل آن، در اسرع وقت، اقدام نمایم. با کمال تشکر جواد جهانگیری
شماره تلفن همراه: 09149431772
نشانی پست الکترونیکی: javad.jahangiri.niopdc@gmail.com
فیلم‌های آموزشی در آپارات:جواد جهانگیری (CTO) - آپارات
فیلم آموزشی در یوتویب: javad jahangiri - YouTube
نسخه مقاله: ۱.۱ - تاریخ بروزرسانی: 1401/01/01
برای دیدن فیلم اموزشی مربوطه به کانال آپاراتی بنده به ادرس جواد جهانگیری (CTO) - آپارات مراجعه نمایید
دقت شود برای دانلود سورس پروژه می توانید به گیت هاب بنده به ادرس زیر مراجعه نمایید
https://github.com/javadjahangiriniopdc/djangoormtutorials

در این آموزش، بحث کاملی در مورد کوئری های ORM جنگو و نحوه استفاده از آنها برای دستکاری داده ها خواهیم داشت.

Django ORM یکی از بهترین ابزارهای جنگو است و نقش بسیار اساسی در انجام وظایف مربوط به پایگاه داده ایفا می کند.

Django ORM از انتزاع سهولت استفاده تشکیل شده است. "چیزهای ساده آسان و چیزهای سخت را ممکن می کند.

در اینجا توضیح مفصلی در مورد هر پرس و جوی ORM خواهیم داشت و همچنین پرس و جوهای SQL مرتبط با آنها را مشاهده می کنیم.

ابتدا یک پروژه جنگو ایجاد می کنیم پیشنهاد می شود برای فعالیت حرفه ای با جنگو از IDE حرفه ای PyCharm شرکت JetBrains که برای کار حرفه با پایتون و فریم های ورک های پایتونی ایجاد شده است استفاده شود


ابتدا یک myappجدید ایجاد می کنیم

و app جدید به پروژه اضافه می کنیم

سپس نسبت migrate اولیه پروژه اقدام می کنیم

و نسبت به ایجاد سوپر کاربر اقدام می کنیم:

سپس به روش ذیل به دیتابیس SQLLite وصل می شویم

سپس فایل SQLite را از مسیر پروژه باز می کنیم

سپس مطمن می شویم که سوپر کاربر ایجاد شده است

سپس از طریق Django Admin وارد پانل ادمین جنگو می شویم:

در نهایت پانل ادمین به شرح زیر قابل مشاهده خواهد بود:


Creating Table in Database using Model


ابتدا یک پایگاه داده نمونه با استفاده از مدل جنگو ایجاد می کنیم که شامل مقداری داده است و کوئری را روی آن پایگاه داده اجرا می کنیم.

برای این کار وارد فایل ماژول مربوط به app جدید می شویم:

model.py

# Create your models here. class Student(models.Model): username = models.CharField(max_length=20) first_name = models.CharField(max_length=30) last_name = models.CharField(max_length=30) mobile = models.CharField(max_length=10) email = models.EmailField() def __str__(self): return &quot%s %s&quot % (self.first_name, self.last_name)

و سپس دستور زیر را در کنسول manage.py اجرا کنید.

python manage.py makemigrations
python manage.py migrate

سپس نسبت اضافه کردن مدل جدید به Admi جنگو به شکل زیر اقدام می کنیم:

اگر دقت کنید مدل دانشجو به پنل ادمین جنگو اضافه گردید:

و نسبت به درج چندین رکورد در این مدل به شرح ذیل اقدام می کنیم

ما قرار است پرس و جو را اجرا کنیم.

How to get all records from table(Model)

ما یک مدل داریم به نام دانشجو. برای دریافت تمام رکوردها از مدل، از Student.objects.all() استفاده می کنیم. برای انجام این کار، Shell جنگو را برای اجرای پرس و جو باز کنید.

ممکن است تعجب کنید که جنگو ORM چگونه پرس و جوهای ما را اجرا می کند یا کد مربوط به کدی که می نویسیم چیست. دریافت پرس و جوی SQL بسیار ساده است، ما باید از str() استفاده کنیم و آبجکت queryset را همراه با پرس و جو ارسال کنیم.

Corresponding SQL Query

How to add record to table(Model)

ما از Student.objects.create() استفاده می کنیم و فیلدها را به همراه مقدار آن به عنوان آرگومان ارسال می کنیم. بیایید مثال زیر را ببینیم.

توجه داشته باشید که برای ذخیره رکورد جدید ایجاد شده در جدول، باید از متد .save() روی آبجکت query استفاده کنیم، در غیر این صورت در پایگاه داده نمایش داده نخواهد شد.


Retrieving Single Objects from QuerySets

فرض کنید برای تطبیق نتیجه به یک شی خاص از یک مجموعه کوئری نیاز داریم. می توانیم این کار را با استفاده از متد get() انجام دهیم. get() مستقیماً شی واحد را برمی گرداند. بیایید مثال زیر را ببینیم.

مثال دوم:

همانطور که در هر دو مثال می بینیم، شی واحد را دریافت می کنیم نه مجموعه پرس و جو از یک شی واحد. اگر نتیجه ای وجود نداشته باشد، با پرس و جو مطابقت داشته باشید، get() یک استثنای DoesNotExist را ایجاد می کند. از طرف دیگر، اگر چندین فیلد منطبق وجود داشته باشد، MultipleObjectReturned را افزایش می دهد که یک ویژگی از خود کلاس مدل است.

مثالDoesNotExist :

مثال MultipleObjectReturned:

Filtering the Records

در مثال قبلی، QuerySet برگردانده شده توسط all() رکورد all را در جدول پایگاه داده توصیف می کند. اما گاهی لازم است زیرمجموعه مجموعه کامل شی را انتخاب کنیم و با افزودن شرایط فیلتر می توان این کار را انجام داد

نکته - تفاوت بین متد get() و filter() در این است که متد filter() مجموعه query شی(ها) را برمی گرداند که در آن متد get() یک شی را برمی گرداند.

Using exclude() Method

یک QuerySet جدید حاوی اشیایی را برمی گرداند که با پارامتر جستجوی داده شده مطابقت ندارند. به عبارت دیگر، رکوردها را با توجه به شرایط جستجو حذف کرد. بیایید مثال زیر را درک کنیم

How to make OR queries in Django ORM?

عملیات OR زمانی انجام می شود که به فیلترینگ رکورد با دو یا چند شرط نیاز داشته باشیم. در مثال زیر، دانش‌آموزی را دریافت می‌کنیم که نامش با «A» و نام خانوادگی‌اش با «M» شروع می‌شود.

Django allows us to do this in two ways.

  • queryset_1 |queryset_2
  • filter(Q(<condition_1>) | Q(<condition_2>

Creating Multiple Object in One Shot

گاهی اوقات می خواهیم چندین شی را در یک shot ایجاد کنیم. فرض کنید می خواهیم یکباره اشیاء جدیدی ایجاد کنیم و نمی خواهیم چندین کوئری را در پایگاه داده اجرا کنیم. bulk_create را برای ایجاد چندین شی به یک روش فراهم می کند

from myapp.models import Student Student.objects.all().count() 3 Student.objects.bulk_create([Student(first_name='fn1',last_name='ln1',mobile='0914',email='fn1@test.com'),Student(first_name='fn2',last_name='ln2',mobile='0913',email='fn2@test.com')]) [<Student: fn1 ln1>, <Student: fn2 ln2>] Student.objects.all().count() 5


Limiting QuerySets


ما می‌توانیم با استفاده از دستور برش فهرست پایتون، محدودیت را در مجموعه query تنظیم کنیم. این عملیات معادل بندهای LIMIT و OFFSET SQL است. بیایید پرس و جو زیر را ببینیم.

جستجوی زیر اولین رکورد تا رکورد پنجم برمی گرداند.

دقت شود رکورد از جنگو از رکورد صفر شماره گذاری می شود
دقت شود در جنگو Negative indexing پشتیبانی نمی شود. با این حال، ما می توانیم از Stepدر QuerySets استفاده کنیم.


How to order a QuerySets in ascending or descending order?


جنگو متد order_by را برای مرتب سازی مجموعه query ارائه می دهد. این متد نام فیلدی را می گیرد که می خواهیم نتیجه را مرتب کنیم (صعودی و نزولی). بیایید مثال زیر را ببینیم

Example - Ascending order

برای مرتب سازی نزولی، قبل از فیلد پرس و جو از Not '-' استفاده می کنیم.

همچنین می توانیم چندین فیلد را در تابع order_by پاس کنیم.

How to order on a field from a related model (with foreign key)?

حال، یاد خواهیم گرفت که چگونه می توانیم داده ها را در مدل های رابطه ای واکشی کنیم . مدل دیگری به نام Teacher ایجاد می کنیم که یک مدل مرتبط با مدل Student است.

فایل Model پروژه را به شرح ذیل تغییر می دهیم:

Models.py

from django.db import models class Teacher(models.Model): teacher_name = models.CharField(max_length=200) def __str__(self): return f'{self.teacher_name}' class Student(models.Model): username = models.CharField(max_length=20) first_name = models.CharField(max_length=30) last_name = models.CharField(max_length=30) mobile = models.CharField(max_length=10) email = models.EmailField() teacher = models.ForeignKey(Teacher, blank=True, null=True, on_delete=models.CASCADE) def __str__(self): return &quot%s %s&quot % (self.first_name, self.last_name)

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

admin.py

from django.contrib import admin # Register your models here. from myapp.models import Student, Teacher admin.site.register(Student) admin.site.register(Teacher)

چند تا معلم به جدول Teacher اضافه می کنیم

برای هر کدام از دانشجویان یک معلم اختصاص می دهیم:

from myapp.models import Student
q = Student.objects.select_related('teacher')
print(q.query)
SELECT &quotmyapp_student&quot.&quotid&quot, &quotmyapp_student&quot.&quotusername&quot, &quotmyapp_student&quot.&quotfirst_name&quot, &quotmyapp_student&quot.&quotlast_name&quot, &quotmyapp_student&quot.&quotmobile&quot, &quotmyapp_student&quot.&quotemail&quot, &quotmyapp_student&quot.&quotteacher_id&quot, &quotmyapp_teacher&quot.&quotid&quot, &quotmyapp_teacher&quot.&quotteacher_name&quot FROM &quotmyapp_student&quot LEFT OUTER JOIN &quotmyapp_teacher&quot ON (&quotmyapp_student&quot.&quotteacher_id&quot = &quotmyapp_teacher&quot.&quotid&quot)

Important Field Lookups

جستجوی فیلد پرس و جو چیزی نیست جز شرطی که همان عبارت SQL WHERE را مشخص می کند. آنها به عنوان آرگومان های کلیدواژه متدهای QuerySet مانند filter()، exclude() و get() بیان می شوند.

Example -

زمانی که هیچ نوع جستجویی ارائه نمی شود (مانند Entry.objects.get(id=14)) برای راحتی، نوع جستجو exact فرض می شود.

exact

مطابقت کامل. اگر مقدار ارائه شده برای مقایسه None باشد، به عنوان یک SQL NULL تفسیر می شود

Examples:

Entry.objects.get(id__exact=14) Entry.objects.get(id__exact=None)

SQL equivalents:

SELECT ... WHERE id = 14; SELECT ... WHERE id IS NULL;

MySQL comparisons

در MySQL، تنظیمات «collation» جدول پایگاه داده تعیین می‌کند که آیا مقایسه‌های دقیق به حروف بزرگ و کوچک حساس هستند یا خیر. این یک تنظیمات پایگاه داده است، نه یک تنظیم جنگو. این امکان وجود دارد که جداول MySQL خود را برای استفاده از مقایسه‌های حساس به حروف کوچک و بزرگ پیکربندی کنید،

iexact

تطابق دقیق بدون حساس به حروف کوچک و بزرگ. اگر مقدار ارائه شده برای مقایسه None باشد، به عنوان SQL NULL تفسیر می شود

Example:

Blog.objects.get(name__iexact='beatles blog') Blog.objects.get(name__iexact=None)

SQL equivalents:

SELECT ... WHERE name ILIKE 'beatles blog'; SELECT ... WHERE name IS NULL;

Note the first query will match 'Beatles Blog', 'beatles blog', 'BeAtLes BLoG', etc.

SQLite users

هنگام استفاده از باطن SQLite و رشته های غیر ASCII، یادداشت پایگاه داده در مورد مقایسه رشته ها را در نظر داشته باشید. SQLite تطبیق غیرحساس به حروف بزرگ و کوچک برای رشته های غیرASCII انجام نمی دهد.

contains

Case-sensitive containment test.

Example:

Entry.objects.get(headline__contains='Lennon')

SQL equivalent:

SELECT ... WHERE headline LIKE '%Lennon%';

Note this will match the headline 'Lennon honored today' but not 'lennon honored today'.

SQLite users

SQLite doesn’t support case-sensitive LIKE statements; contains acts like icontains for SQLite.

icontains

Case-insensitive containment test.

Example:

Entry.objects.get(headline__icontains='Lennon')

SQL equivalent:

SELECT ... WHERE headline ILIKE '%Lennon%';

SQLite users

When using the SQLite backend and non-ASCII strings, bear in mind the database note about string comparisons.

in

In a given iterable; often a list, tuple, or queryset. It’s not a common use case, but strings (being iterables) are accepted.

Examples:

Entry.objects.filter(id__in=[1, 3, 4]) Entry.objects.filter(headline__in='abc')

SQL equivalents:

SELECT ... WHERE id IN (1, 3, 4); SELECT ... WHERE headline IN ('a', 'b', 'c');

You can also use a queryset to dynamically evaluate the list of values instead of providing a list of literal values:

inner_qs = Blog.objects.filter(name__contains='Cheddar') entries = Entry.objects.filter(blog__in=inner_qs)

This queryset will be evaluated as subselect statement:

SELECT ... WHERE blog.id IN (SELECT id FROM ... WHERE NAME LIKE '%Cheddar%')

If you pass in a QuerySet resulting from values() or values_list() as the value to an __in lookup, you need to ensure you are only extracting one field in the result. For example, this will work (filtering on the blog names):

inner_qs = Blog.objects.filter(name__contains='Ch').values('name') entries = Entry.objects.filter(blog__name__in=inner_qs)

This example will raise an exception, since the inner query is trying to extract two field values, where only one is expected:

# Bad code! Will raise a TypeError. inner_qs = Blog.objects.filter(name__contains='Ch').values('name', 'id') entries = Entry.objects.filter(blog__name__in=inner_qs)

Performance considerations

در مورد استفاده از پرس و جوهای تو در تو محتاط باشید و ویژگی های عملکرد سرور پایگاه داده خود را درک کنید برخی از پشتیبان های پایگاه داده، به ویژه MySQL، پرس و جوهای تودرتو را به خوبی بهینه نمی کنند. در این موارد، استخراج لیستی از مقادیر و ارسال آن به کوئری دوم کارآمدتر است. یعنی به جای یک کوئری از دو کوئری استفاده کنید:

values = Blog.objects.filter( name__contains='Cheddar').values_list('pk', flat=True) entries = Entry.objects.filter(blog__in=list(values))


startswith

Case-sensitive starts-with.

Example:

Entry.objects.filter(headline__startswith='Lennon')

SQL equivalent:

SELECT ... WHERE headline LIKE 'Lennon%';

SQLite doesn’t support case-sensitive LIKE statements; startswith acts like istartswith for SQLite.

istartswith

Case-insensitive starts-with.

Example:

Entry.objects.filter(headline__istartswith='Lennon')

SQL equivalent:

SELECT ... WHERE headline ILIKE 'Lennon%';

SQLite users

When using the SQLite backend and non-ASCII strings, bear in mind the database note about string comparisons.

endswith

Case-sensitive ends-with.

Example:

Entry.objects.filter(headline__endswith='Lennon')

SQL equivalent:

SELECT ... WHERE headline LIKE '%Lennon';

SQLite users

SQLite doesn’t support case-sensitive LIKE statements; endswith acts like iendswith for SQLite. Refer to the database note documentation for more.

iendswith

Case-insensitive ends-with.

Example:

Entry.objects.filter(headline__iendswith='Lennon')

SQL equivalent:

SELECT ... WHERE headline ILIKE '%Lennon'

SQLite users

When using the SQLite backend and non-ASCII strings, bear in mind the database note about string comparisons.

range

Range test (inclusive).

Example:

import datetime start_date = datetime.date(2005, 1, 1) end_date = datetime.date(2005, 3, 31) Entry.objects.filter(pub_date__range=(start_date, end_date))

SQL equivalent:

SELECT ... WHERE pub_date BETWEEN '2005-01-01' and '2005-03-31';

You can use range anywhere you can use BETWEEN in SQL — for dates, numbers and even characters.

Warning

Filtering a DateTimeField with dates won’t include items on the last day, because the bounds are interpreted as “0am on the given date”. If pub_date was a DateTimeField, the above expression would be turned into this SQL:

SELECT ... WHERE pub_date BETWEEN '2005-01-01 00:00:00' and '2005-03-31 00:00:00';

How to group record in Django ORM?

جنگو ORM تسهیلات گروه بندی را با استفاده از توابع تجمعی مانند Max، Min، Avg و Sum فراهم می کند. گاهی اوقات ما نیاز داریم که مقادیر کل را از اشیا بدست آوریم. بیایید مثال زیر را درک کنیم.

>>> from django.db.models import Avg, Max, Min, Sum, Count >>> Student.objects.all().aggregate(Avg('id')) {'id__avg': 5.5} >>> Student.objects.all().aggregate(Min('id')) {'id__min': 1} >>> Student.objects.all().aggregate(Max('id')) {'id__max': 10} >>> Student.objects.all().aggregate(Sum('id')) {'id__sum': 55}

How to perform truncate like operation using Django ORM?

توجه شود truncate کوتاه کردن در SQL به معنای پاک کردن داده های جدول برای استفاده در آینده است. جنگو متدهای داخلی را برای کوتاه کردن جدول ارائه نمی دهد، اما می توانیم از متد delete() برای به دست آوردن نتیجه مشابه استفاده کنیم. بیایید مثال زیر را درک کنیم.

>>> Student.objects.all().count() 5 >>> Student.objects.all().delete() (5, {'sampleapp.Student': 5}) >>> Student.objects.all().count() 0 >>> Student.objects.all() <QuerySet []>

How to get union of Data

توجه شود Union به معنای دریافت رکوردی است که در هر دو مجموعه پرس و جو رایج است. بیایید ببینیم چگونه می توانیم این کار را انجام دهیم.

gt

Greater than.

Example:

Entry.objects.filter(id__gt=4)

SQL equivalent:

SELECT ... WHERE id > 4;

gte

Greater than or equal to.

lt

Less than.

lte

Less than or equal to.

q1 = Student.objects.filter(id__gte = 15) >>> q1 <QuerySet [<Student: Megha Bhardwaj>, <Student: Akash Mishra>]> >>> q2 = Student.objects.filter(id__lte = 15) >>> q2 <QuerySet [<Student: Ritesh Tiwari>, <Student: Yash Sharma>, <Student: Arpita Sharma>, <Student: Prince Sharma>, <Student: Megha Bhardwaj>]> >>> q1.union(q2 <QuerySet [<Student: Ritesh Tiwari>, <Student: Yash Sharma>, <Student: Arpita Sharma>, <Student: Prince Sharma>, <Student: Megha Bhardwaj>, <Student: Akash Mishra>]>


What is difference between null=True and blank=True?

در جنگو، ما اغلب از null و blank استفاده می کنیم، به طور پیش فرض مقادیر آنها False است. هر دوی این مقادیر در سطح فیلدی کار می کنند که می خواهیم یک فیلد null یا blank نگه داریم. هر دو مقدار مشابه به نظر می رسند اما در استفاده متفاوت هستند.


If null=True means the field value is set as NULL i.e. no data. It is basically for the database column value.
date = models.DateTimeField(null=True)

The blank = True specifies whether field is required in forms.title = models.CharField(blank=True) // title can be kept blank. In the database ("") will be stored.

If we set null=True blank=True, means that the field is optional in all circumstances.
teacher = models.ForeignKey(null=True, blank=True) // The exception is CharFields() and TextFields(), which in Django are never saved as ?→NULL. Blank values are stored in the DB as an empty string ('').


djangoجنگو
بنده دارای مدارک بین المللی شبکه ,برنامه نویسی, سرورهای ویندوزی و لینوکس هستم بیش از ده سال سابقه تدریس در زمینه های یاد شده را دارم. آموزش تخصص ماست با ما حرفه ای شوید 09149431772 مجتمع فنی ارومیه
شاید از این پست‌ها خوشتان بیاید