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

آموزش پیداسازی جستجو در جنگو | Django Search (with Q objects) Tutorial

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

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

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


برای این اموزش از منابع زیر استفاده شده است

Django | Documentation |Making queries |Complex lookups with Q objects

Django | Documentation | Search

نکته:سورس های این پروژه در گیت هاب بنده در مسیر ذیل قابل دسترس می باشد:https://github.com/javadjahangiriniopdc/djangosearch


حتما قبل از شروع به مطالعه این مقاله حتما مقاله قبلی بنده در راستا اموزش Django Orm از طریق لینک ذیل مطالعه فرمایید

https://vrgl.ir/62xzv



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

وارد پنجره run manager.py task به شرح ذیل می شویم

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

و app جدید به app های جنگو به شرح ذیل اضافه می کنیم

در app جدید اضافه شده در فایل models.py یک موجودیت بنام Person به شرح زیر ایجاد می کنیم

درنهایت یک مایگریشن ایجاد کرده و تغییرات بر روی دیتابیس مایگریت می کنیم

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

و موجودیت را به پنل admin اضافه می کنیم

وارد پنل admin جنگو شده و چندین رکورد برای جدول Person درج می کنیم:

به اپ جدید myapp یک فایل urls.py به صورت زیر اضافه می کنیم :

و در نهایت urls.py جدید اضافه شده در app اصلی جنگو به شکل زیر include می کنیم

در نهایت داخل فایل views.py شده و یک function view به شرح ذیل بنام home ایجاد می کنیم

و یک فایل home.html به مسیر template اضافه می کنیم:

دقت شود در جنگو برخی از اسامی دارای معنی خاصی هستند مانند static و templates اگر دقت شود در داخل فایل settings.py در قسمت تنظیمات static و templates تنظیماتی به شرح ذیل اعمال شده این به این معنی می باشد که جنگو در داخل هر app به دنبال پوشه های مذکور می گردد و برای سرویس از این پوشه ها استفاده می کند
در مورد پوشه templates اولویت ابتدا با templates که در مسیر root جنگو می باشد هست و سپس templates موجود در داخل هر app این به این معنی می باشد که اگر شما در داخل پوشه templates که در مسیر root جنگو یک فایل برای مثال index.html داشته باشید و در داخل پوشه templates که در مسیر هر app هم با این نام فایلی موجود باشد اولویت با index.html می باشد که در پوشه templates که در مسیر root جنگو هست

نحوه تنظیم فایل static در جنگو

برای تنظیم فایل های static تنظیمات مقتضی توسط خود جنگو بصورت پیش فرض اعمال شده است و نیازی به اعمال تنظیم خاصی نیست ولی دقت شود در پایان برنامه نویسی پروژه در هنگام collectstatic نیاز به مسیر مربوط STATIC_ROOT دارد که به شکل زیر تنظیم می شود:
STATIC_URL = 'static/' import os STATIC_ROOT = os.path.join(BASE_DIR, 'static')

نکته:

پیشنهاد می شود در داخل هر app دو پوشه بنام های static و templates ایجاد شود و در داخل هر پوشه یاد شده یک پوشه هم نام خود app ایجاد گردد دلیل این پیشنهاد این است که در نهایت که پوشه برای مد product اماده می شود در هنگام collectstatic تمامی فایل موجود در پوشه های static و templates هر app در یک پوشه static و templates در مسیر root جنگو تجمیع می گردد در این صورت اگر فایل هم نامی در app های ما باشد به مشکل جدی برخورد می کنیم ولی وقتی در داخل هر app در پوشه های static و templates یک پوشه بنام خود app ایجاد شود در هنگام تجمیع شدن در نهایت در یک پوشه واحد فایل هر app در داخل پوشه هم نام با خود app کپی می شود این مشکل تداخل نام دیگر وجود نخواهد داشت.
همانطوری که در تصویر بالا مشاهده می کنید در داخل پوشه myapp یک پوشه بنام static ایجاد شده است و در داخل پوشه static هم یک پوشه بنام myapp همان با نام خود app ایجاد شده و همین کار برای پوشه templates هم تکرار شده است این کار مشکل تجمیع فایل در نهایت در پوشه های static و templates (فلش سوم) که در مسیر root پروژه جنگو در نهایت پس از پایان پروژه را مرتفع خواهد نمود.

برای قالب پروژه پیشنهاد می شود از یکی از قالب های اموزشی موجود در سایت w3schools به شرح ذیل استفاده شود

بر روی گزینه try your self کلیک نمایید و کد زیر برای شما نمایش داده می شود:

<!DOCTYPE html> <html lang=&quoten&quot> <head> <title>Bootstrap 4 Website Example</title> <meta charset=&quotutf-8&quot> <meta name=&quotviewport&quot content=&quotwidth=device-width, initial-scale=1&quot> <link rel=&quotstylesheet&quot href=&quothttps://cdn.jsdelivr.net/npm/bootstrap@4.6.1/dist/css/bootstrap.min.css&quot> <script src=&quothttps://cdn.jsdelivr.net/npm/jquery@3.6.0/dist/jquery.slim.min.js&quot> <script src=&quothttps://cdn.jsdelivr.net/npm/popper.js@1.16.1/dist/umd/popper.min.js&quot> <script src=&quothttps://cdn.jsdelivr.net/npm/bootstrap@4.6.1/dist/js/bootstrap.bundle.min.js&quot> <style> .fakeimg { height: 200px; background: #aaa; } </style> </head> <body> <div class=&quotjumbotron text-center&quot style=&quotmargin-bottom:0&quot> <h1>My First Bootstrap 4 Page</h1> <p>Resize this responsive page to see the effect!</p> </div> <nav class=&quotnavbar navbar-expand-sm bg-dark navbar-dark&quot> <a class=&quotnavbar-brand&quot href=&quot#&quot>Navbar</a> <button class=&quotnavbar-toggler&quot type=&quotbutton&quot data-toggle=&quotcollapse&quot data-target=&quot#collapsibleNavbar&quot> <span class=&quotnavbar-toggler-icon&quot></span> </button> <div class=&quotcollapse navbar-collapse&quot id=&quotcollapsibleNavbar&quot> <ul class=&quotnavbar-nav&quot> <li class=&quotnav-item&quot> <a class=&quotnav-link&quot href=&quot#&quot>Link</a> </li> <li class=&quotnav-item&quot> <a class=&quotnav-link&quot href=&quot#&quot>Link</a> </li> <li class=&quotnav-item&quot> <a class=&quotnav-link&quot href=&quot#&quot>Link</a> </li> </ul> </div> </nav> <div class=&quotcontainer&quot style=&quotmargin-top:30px&quot> <div class=&quotrow&quot> <div class=&quotcol-sm-4&quot> <h2>About Me</h2> <h5>Photo of me:</h5> <div class=&quotfakeimg&quot>Fake Image</div> <p>Some text about me in culpa qui officia deserunt mollit anim..</p> <h3>Some Links</h3> <p>Lorem ipsum dolor sit ame.</p> <ul class=&quotnav nav-pills flex-column&quot> <li class=&quotnav-item&quot> <a class=&quotnav-link active&quot href=&quot#&quot>Active</a> </li> <li class=&quotnav-item&quot> <a class=&quotnav-link&quot href=&quot#&quot>Link</a> </li> <li class=&quotnav-item&quot> <a class=&quotnav-link&quot href=&quot#&quot>Link</a> </li> <li class=&quotnav-item&quot> <a class=&quotnav-link disabled&quot href=&quot#&quot>Disabled</a> </li> </ul> <hr class=&quotd-sm-none&quot> </div> <div class=&quotcol-sm-8&quot> <h2>TITLE HEADING</h2> <h5>Title description, Dec 7, 2017</h5> <div class=&quotfakeimg&quot>Fake Image</div> <p>Some text..</p> <p>Sunt in culpa qui officia deserunt mollit anim id est laborum consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco.</p> <br> <h2>TITLE HEADING</h2> <h5>Title description, Sep 2, 2017</h5> <div class=&quotfakeimg&quot>Fake Image</div> <p>Some text..</p> <p>Sunt in culpa qui officia deserunt mollit anim id est laborum consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco.</p> </div> </div> </div> <div class=&quotjumbotron text-center&quot style=&quotmargin-bottom:0&quot> <p>Footer</p> </div> </body> </html>

در داخل پوشه myapp/templates/myapp یک فایل بنام base.html ایجاد می کنیم و از طریق کدهای بالا به شرح ذیل این فایل را تغییر می دهیم

base.html

{% load static %} <!DOCTYPE html> <html lang=&quoten&quot> <head> <title>Bootstrap 4 Website Example</title> <meta charset=&quotutf-8&quot> <meta name=&quotviewport&quot content=&quotwidth=device-width, initial-scale=1&quot> <link rel=&quotstylesheet&quot href=&quot{% static 'myapp/css/bootstrap.min.css' %}&quot> <script src=&quot{% static 'myapp/js/jquery.slim.min.js' %}&quot> <script src=&quot{% static 'myapp/js/popper.min.js' %}&quot> <script src=&quot {% static 'myapp/js/bootstrap.bundle.min.js' %}&quot> <style> .fakeimg { height: 200px; background: #aaa; } </style> </head> <body> {% include 'myapp/header.html' %} <div class=&quotcontainer&quot style=&quotmargin-top:30px&quot> {% block content %} {% endblock %} </div> {% include 'myapp/footer.html' %} </body> </html>

تنظیمات یک:بارگذاری فایل های استاتیک

ابتدا فایل css و js مورد نیاز به شرح ذیل در پوشه myapp/static/myapp در داخل پوشه های cssوjs کپی می کنیم

نحوه استفاده از فایل static در جنگو

  • ابتدا از طریق دستور زیر مسیردهی فایل های استاتیک را load می کنیم
{% load static %}
  • سپس از طریق زیر فایل های static را در فایل base.html لود می کنیم
<script src=&quot{% static 'myapp/js/jquery.slim.min.js' %}&quot> <script src=&quot{% static 'myapp/js/popper.min.js' %}&quot> <script src=&quot {% static 'myapp/js/bootstrap.bundle.min.js' %}&quot>


تنظیمات دوم:ایجاد فایل header.html و include ان در داخل فایل base.html

header.html

<div class=&quotjumbotron text-center&quot style=&quotmargin-bottom:0&quot> <h1>My First Bootstrap 4 Page</h1> <p>Resize this responsive page to see the effect!</p> </div> {% include 'myapp/nav.html' %}

کد مورد نیاز برای include کردن header.html در داخل فایل base.html

{% include 'myapp/header.html' %}

معمولا در پروژه های قسمت navigation ها (منوها) نیز به یک فایل جداگانه منتقل شده و در داخل header.html به شکل بالا include می شود

nav.html

<nav class=&quotnavbar navbar-expand-sm bg-dark navbar-dark&quot> <a class=&quotnavbar-brand&quot href=&quot#&quot>Navbar</a> <button class=&quotnavbar-toggler&quot type=&quotbutton&quot data-toggle=&quotcollapse&quot data-target=&quot#collapsibleNavbar&quot> <span class=&quotnavbar-toggler-icon&quot></span> </button> <div class=&quotcollapse navbar-collapse&quot id=&quotcollapsibleNavbar&quot> <ul class=&quotnavbar-nav&quot> <li class=&quotnav-item&quot> <a class=&quotnav-link&quot href=&quot#&quot>Link</a> </li> <li class=&quotnav-item&quot> <a class=&quotnav-link&quot href=&quot#&quot>Link</a> </li> <li class=&quotnav-item&quot> <a class=&quotnav-link&quot href=&quot#&quot>Link</a> </li> </ul> </div> </nav>

تنظیمات سوم:نحوه block بندی فایل base.html و ایجاد ارث بری صفحه index.html از base.html

<div class=&quotcontainer&quot style=&quotmargin-top:30px&quot> {% block content %} {% endblock %} </div>

index.html

{% extends 'myapp/base.html' %} {% load static %} {% block content %} <div class=&quotrow&quot> <div class=&quotcol-12&quot> <h1>index content</h1> </div> </div> {% endblock %}

کد {% extends 'myapp/base.html' %} زیر برای ارث بری از صفحه base.html استفاده می شود در این صورت در هنگام بارگذاری صفحه index.html ابتدا صفحه base.html بارگذاری شده و سپس در داخل قسمت block content کدهای مربوط به صفحه index.html بارگذاری می شود

تنظیمات قسمت چهارم:نحوه ایجاد فایل footer.html و include کردن فایل footer در base.html

footer.html

<div class=&quotjumbotron text-center&quot style=&quotmargin-bottom:0&quot> <p>Footer</p> </div>

اگر تنظیمات به درستی انجام شود در نهایت شما با خروجی به شکل ذیل روبه رو خواهید شد

نحوه ارسال و نمایش اطلاعات Person در داخل فایل index

from django.shortcuts import render from myapp.models import Person def home(request): persons = Person.objects.all() return render(request, 'myapp/index.html', {'persons': persons})

سپس کدهای مورد نیاز برای ایجاد جدول بوت استرپی را از لینک زیر استفاده کنید

https://getbootstrap.com/docs/4.0/content/tables/

وکدهای جدول بوت استرپی به شرح ذیل به صفحه Index اضافه می کنیم

index.html

{% extends 'myapp/base.html' %} {% load static %} {% block content %} <div class=&quotrow&quot> <div class=&quotcol-12&quot> <table class=&quottable&quot> <thead> <tr> <th scope=&quotcol&quot>name</th> <th scope=&quotcol&quot>description</th> </tr> </thead> <tbody> {% for person in persons %} <tr> <td>{{ person.name }}</td> <td>{{ person.description }}</td> </tr> {% endfor %} </tbody> </table> </div> </div> {% endblock %}

و خروجی به شرح ذیل خواهد بود

نحوه اضافه کردن forms به پروژه جنگو

یک فرم جنگو به پروژه به شرح ذیل اضافه می کنیم


forms.py

from django import forms class SearchForm(forms.Form): search = forms.CharField()

حالا تغییرات ذیل در فرم view.py به شرح ذیل اضافه می کنیم :

  • درقسمت اول :فایل فرم که در مرحلی قبل ایجاد کردیم را در view واکشی می کنیم
  • درقسمت دوم:بررسی می کنیم که اطلاعات ارسالی از سوی فرم که در مرحله بعدی به فایل index اضافه خواهد شد معتبر است یا نه ؟
  • در مرحله سوم: با عنایت به اینکه می خواهیم از پرس و جو پیچیده استفاده کینم از object Q استفاده می کینم برای اطلاعات بیشتر می توانید از طریق لینک ذیل مطالب بیشتری را در این راستا مطالعه فرمایید

https://docs.djangoproject.com/en/4.0/topics/db/queries/#complex-lookups-with-q-objects

همچنین برای جستجو کردن به شرطی که شامل یک عبارت باشد و به حروف کوچیک و بزرگ هم حساس نباشد از icontains استفاده شده است
  • در مرحله چهارم:اطلاعات فرم به صفحه index بصورت دیکشنری ارسال می گردد.

views.py

from datetime import datetime from django.db.models import Q from django.http import HttpResponse from django.shortcuts import render from myapp.forms import SearchForm from myapp.models import Person def home(request): persons = Person.objects.all() form = SearchForm() if 'search' in request.GET: form = SearchForm(request.GET) if form.is_valid(): cd = form.cleaned_data['search'] persons= persons.filter(Q(name__icontains=cd) | Q(description__icontains=cd)) return render(request, 'myapp/index.html', {'persons': persons, 'form': form})


حالا در فایل index.html یک ردیف جدید بوت استرپی ایجاد کرده و به شرح ذیل فرم که در مرحله قبل به این صفحه پاس شده است را به صفحه html اضافه می کنیم:

index.html

{% extends 'myapp/base.html' %} {% load static %} {% block content %} <div class=&quotrow&quot> <div class=&quotcol-12&quot> <form action=&quot&quot> {{ form }} <input type=&quotsubmit&quot value=&quotSearch&quot> </form> </div> </div> <div class=&quotrow&quot style=&quotmargin-top: 50px&quot> <div class=&quotcol-12&quot> <table class=&quottable&quot> <thead> <tr> <th scope=&quotcol&quot>name</th> <th scope=&quotcol&quot>description</th> </tr> </thead> <tbody> {% for person in persons %} <tr> <td>{{ person.name }}</td> <td>{{ person.description }}</td> </tr> {% endfor %} </tbody> </table> </div> </div> {% endblock %}

و در نهایت نتیجه خروجی برنامه به شرح ذیل خواهد بود


باتشکر از مطالعه مقاله ,مثل همیشه کنجکاو باشید !!!

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


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