إنشاء تطبيق Todo باستخدام Django. الجزء الأول

مرحبا مجددا. تحسبًا لبدء دورة Python Web Developer ، أعد كاتبنا المستقل بعض المواد المثيرة للاهتمام التي يسعدنا مشاركتها معك.




Django هو إطار تطبيق ويب قوي. في البداية ، تم إنشاء Django من أجل إنشاء مواقع إخبارية بسرعة ، على سبيل المثال ، (أو مواقع أخرى تحتاج إلى إنشائها في أسرع وقت ممكن). وبعد PHP الأصلي ، لا يترك الشعور بأنك تركب آلة تطوير سريعة جدًا. لمشاهدة جميع ميزاته للتطوير السريع ، سنحاول إنشاء تطبيق Todo بسيط.



لنبدأ بصيغة t.z. القصيرة سيكون لدينا تطبيق ويب صغير مع تخطيط على Bulma (نعم ، أنا أحب Bulma حقًا. ربما في يوم من الأيام سأوقف تشغيل Bootstrap أو Picnic ، ولكن كل شيء لديه الوقت). ليس لدينا (حتى الآن) تفويضات ويمكن للمستخدم إنشاء وتعديل وحذف إما فئة المهام أو بطاقة المهام ، المرتبطة بأي فئة أنشأها المستخدم. يمكن حذف بطاقة أو فئة Todo عن طريق تحديد مربع الاختيار والنقر فوق زر الحذف.

مفاهيم جانغو الأساسية


لنتحدث قليلا عن Django. تطبق Django النموذج المعماري MVT (نموذج عرض النموذج) ، والذي يختلف قليلاً عن MVC (وحدة تحكم عرض النموذج) المألوفة التي تدير Ruby on Rails و Laravel.

نموذج و نموذج في جانغو يصف مخطط البيانات في قاعدة البيانات. باستخدام Django ORM ، يمكنك بشكل مستقل وصف الحقول وأي أنواع بيانات أخرى ، وإجراء عمليات ترحيل لتبسيط التطوير.

عرض في طريقة العرض في Django ، يمكنك تعيين المنطق والخوارزميات الأساسية للتطبيق ، أو الحصول على بيانات متنوعة من قاعدة البيانات أو معالجتها. عادةً ما يستند العرض إلى دالات الطلب \ الاستجابة. عادة ما تكون الاستجابة هي إعادة توجيه HTTP أو خطأ HTTP (404) أو أنواع Mime أو نوع من النمط.

قالبالقالب في Django هو رمز HTML بسيط بلغة قالب خاصة Django. DTL (لغة قالب Django) هي لغة يمكنك من خلالها تغيير محتوى الصفحة ديناميكيًا (على سبيل المثال ، قم بتغيير اسم المستخدم على الصفحة ، اعتمادًا على اسم المستخدم المصرح له).

الإعدادات ملف الإعدادات في Django ، الذي يحتوي على جميع الإعدادات لتطبيق الويب الخاص بك. يتضمن مفتاحًا سريًا ومجلدات قوالب ووسائط متوسطة (وهي مسؤولة ، على سبيل المثال ، عن منع المستخدمين الآخرين من رؤية ألبوماتك الخاصة) ، واتصال قاعدة بيانات ، وأكثر من ذلك بكثير.

عنوان Url ملف تكوين التوجيه هو نفسه الموجود في Angular أو Laravel. يؤدي هذا إلى ربط العرض بطلبات url.

صفحة الإدارة نظرًا لأن Django تم تصميمه في الأصل للنماذج الأولية السريعة ونشر المواقع الإخبارية ، يتم تضمين لوحة الإدارة بشكل افتراضي.

قم بتثبيت Python و Django


خلوة خلاقة
( ) . Python . , . , .

إصدارات بايثون


حتى وقت قريب ، تم دعم وتطوير فرعين رئيسيين في Python: 2.7 و 3.x. سأستخدم الإصدار 3.7.3 في هذه المقالة ، ولكنه في الواقع ليس مهمًا جدًا. إذا كنت تريد حقًا معرفة الفرق بين الاثنين ، فهناك ويكي خاص . من ناحية أخرى ، الآن ليس من المنطقي استخدام Python الإصدار 2.7 - توقف تحديث اللغة عند 2.7.17 (إذا فهمت الوثائق الموجودة على الموقع الرسمي بشكل صحيح). هذا يعني أنه من المنطقي نقل المشاريع المكتوبة في Python 2.7.x إلى فرع جديد ، ولكن كتابة مشاريع جديدة في نسختين لا معنى له على الإطلاق.

تركيب بايثون


إذا كنت تعمل على Mac أو Ubuntu ، فمن المحتمل أن يكون لديك Python مثبتًا بالفعل ، ولكن هناك إصداران. يجب تنزيل Python من الإصدار الثالث بشكل منفصل ، ويمكنك الاتصال به على سطر الأوامر من خلال python3. على أي حال ، من الأفضل تنزيل أحدث إصدار هنا .

إنشاء البيئة الافتراضية الخاصة بك


في الواقع ، يمكنك البدء في تطوير التطبيق الأول على Django دون إنشاء بيئة افتراضية خاصة بك ، ولكن مهارة إنشاء بيئة افتراضية يمكن أن تكون مفيدة إذا قمت ، على سبيل المثال ، بتطوير تطبيق بإصدار محدد من المكتبة ولا ترغب في تثبيت المكتبات عالميًا وترمي نظامك.

فكيف تستخدم env الظاهري؟



1) الخيار الأسهل. يمكنك تنزيل IDE الرائع من JET BRAINS PyCharm Community Edition من هنا . بعد تثبيت PyCharm ، قم بإنشاء مشروع جديد ، وسيقدم لك Pycharm إنشاء Virtual Env افتراضيًا ، حيث سيكون من الممكن تثبيت الإصدار المطلوب من Django (أو بشكل افتراضي أحدث إصدار ، والذي كان وقت كتابة هذا المقال 3.0.2):

pip3 install django

2) خيار أكثر تشددًا قليلاً:

ماذا لو كنت تريد تشغيل Django في env الظاهري ، على سبيل المثال ، في مجلدك المفضل؟
أولاً ، قم بإنشاء مجلد سنقوم فيه بإنشاء:

	mkdir myfirstdjango && cd myfirstdjango

بعد ذلك ، أدخل الأوامر التالية لتنشيط venv ، حيث django_env هو اسم بيئتنا الافتراضية:

	python3 -m venv django_env
	source django_env/bin/activate

علاوة على ذلك ، تم تنشيط بيئتنا الافتراضية. يمكننا توريد الحزم اللازمة. في حالتنا ، هذا هو جانغو:

	pip3 install django

إذا كنت ترغب في إيقاف تشغيل البيئة الافتراضية من أجل العودة إلى الثعبان العام (العودة إلى سياق النظام) ، فأدخل الأمر التالي:

    deactivate

حسنًا ، آمل أننا اكتشفنا البيئة الافتراضية. إذا كان لديك أي مشاكل وأسئلة إضافية، وصلات مفيدة ويمكن الاطلاع هنا و هنا .

إنشاء المشروع نفسه


لنفترض أنك اخترت إحدى الطرق لإنشاء البيئة الافتراضية الخاصة بك (أو حتى القيام بكل شيء على مستوى العالم ، حسنًا ، لا أحد يمنعك من القيام بذلك). ننتقل الآن إلى مجلد المشروع ونبدأ في إنشائه:

    django-admin startproject todo  #    
    cd todo #  
    python manage.py startapp todolist  #   todolist
	python3 manage.py runserver 8100 #      , 8000  
 

لذا ، بعد أن فتح Django صفحة البداية ، تحتاج إلى تثبيت تطبيق todolist الخاص بنا في التطبيق الرئيسي. افتح settings.pyوأضف إلى قائمة التطبيقات الحالية لدينا قائمة الأشياء الخاصة بنا:

INSTALLED_APPS = [
	# ,     ,     
    'todolist',
]

الخطوة التالية هي ربط التطبيق بقاعدة البيانات. إذا لم تكن قواعد البيانات هي ما تريد العبث به ، فيجب عليك استخدام الحل الافتراضي SQlite. قررت استخدام PostgreSQL - إنه شائع ويرتبط بشكل كلاسيكي بـ Django ، بالإضافة إلى ذلك ، فقد نرغب في زيادة أداء التطبيق. هناك الكثير من الإرشادات حول كيفية تثبيت PostgreSQL على جميع أنظمة التشغيل. أنا أتطور لنظام MacOS ومع بعض الرقصات الصغيرة باستخدام الدف ، قمت بتثبيت قاعدة البيانات هذه عن طريق تنزيل Postgres.app من هنا . أما بالنسبة لواجهات قاعدة البيانات ، فقد استخدمت Postico هناوإصدار تجريبي لتطوير التطبيق يكفي بالنسبة لنا (على الرغم من أنه ، من حيث المبدأ ، يمكنك الاستغناء عنه ، لأن كل تفاعلنا مع قاعدة البيانات سيتم بناؤه من خلال تطبيق الويب نفسه والترحيل). بالإضافة إلى ذلك ، كان علي أن أضع psycopg2 في البيئة الافتراضية للمشروع (بدون برنامج التشغيل هذا ، لن يعمل تطبيقك مع قاعدة البيانات).

بعد ذلك ، تحتاج إلى تكوين عمل الإحصائيات. ما زلنا نقوم بتحرير الملف settings.py، والآن في النهاية نضيف العمل مع الإحصائيات:

STATIC_URL = '/static/'
PROJECT_ROOT = os.path.dirname(os.path.abspath(__file__))
STATIC_ROOT = os.path.join(PROJECT_ROOT, 'static')
STATICFILES_STORAGE = 'whitenoise.django.GzipManifestStaticFilesStorage'

لكي تعمل الإحصائيات الخاصة بك ، تحقق من أن الحزمة المسؤولة عن الإحصائيات موجودة في قائمة INSTALLED_APPS :

django.contrib.staticfiles,في حالة حدوث خطأ.
وآخر شيء في العمل التحضيري ، ما زلنا بحاجة إلى تكوين العمل الأساسي لعنوان url في المشروع:

	from django.conf.urls import url
	from django.contrib import admin
	from todolist.views import todo
	from todolist.views import category
	from todolist.views import redirect_view
 
urlpatterns = [
	url(r'$^', redirect_view ),
	url(r'^admin/', admin.site.urls),
	url(r'^todo/', todo, name="TodoList"),
	url(r'^category/', category, name="Category"),
]

لقد أضفت إعادة توجيه لأنني أريد أن يذهب المضيف المحلي مباشرة إلى الصفحة الفرعية للفئة من الصفحة الافتراضية (لذلك لا قدر الله أن يفقد المستخدم). لدينا أيضًا توجيه من صفحتين: الفئات والحالات.

لذا ، آمل أن يتعطل تطبيقك. بعد ذلك ، يمكننا أخيرًا الانتقال إلى إنشاء التطبيق نفسه:

إنشاء نموذج وفئات تودو


بعد ذلك ، سنبدأ في إنشاء نموذج يتفاعل بشكل أساسي مع قاعدة بياناتنا. لإنشاء نموذج ، افتح الملف models.pyفي قائمة المهام وابدأ في الإنشاء. لنبدأ بإنشاء جدول الفئات:

from django.utils import timezone #     todo
from django.db import models
 
class Category(models.Model): #     models.Model
    name = models.CharField(max_length=100) #varchar.    
	class Meta:
    	verbose_name = ("Category") #   
    	verbose_name_plural = ("Categories")  #    
    def __str__(self):
        return self.name  # __str__      

غرامة! نعم ، سيكون لدينا هنا عمودين فقط في جدول الفئات: المعرف والاسم. بعد ذلك ، قم بإنشاء جدول لشئوننا. أعتقد أن كل شيء واضح من التعليقات:

class TodoList(models.Model):
	title = models.CharField(max_length=250)
	content = models.TextField(blank=True) # 
	created = models.DateField(default=timezone.now().strftime("%Y-%m-%d")) #  
	due_date = models.DateField(default=timezone.now().strftime("%Y-%m-%d")) #      
	category = models.ForeignKey(Category, default="general",on_delete=models.PROTECT) # foreignkey          
	class Meta: #       
        ordering = ["-created"] #     
	def __str__(self):
    	return self.title

بعد أن يصبح نموذجك جاهزًا ، تحتاج إلى إنشاء عمليات ترحيل:

	python3 manage.py makemigrations

ثم قم بإجراء عمليات الترحيل نفسها:

	python3 manage.py migrate

إنشاء عرض


افتح الملف view.pyفي todolist وقم بتحريره. أولاً ، أضف الواردات اللازمة وأعد التوجيه من الرئيسي إلى الفئة:

from django.shortcuts import render, redirect #      
from django.http import HttpResponse
from .models import TodoList, Category #   
 
def redirect_view(request):
	return redirect("/category") #     

ثم نبدأ في إنشاء أعمالنا. يحتوي مثيل الحالة على حقول النص نفسها ، وتاريخ إكمال الحالة ، وفئة الحالة ، والمحتوى المدمج:

def todo(request):
	todos = TodoList.objects.all() #   todo   
    categories = Category.objects.all() #    

بعد ذلك ، أضف وظائف إضافة وحذف الحالات:

if request.method == "POST": #     POST
	if "Add" in request.POST: #   todo
    	title = request.POST["description"] # 
    	date = str(request.POST["date"]) #,      
        category = request.POST["category_select"] #,      .
        content = title + " -- " + date + " " + category #   
    	Todo = TodoList(title=title, content=content, due_date=date, category=Category.objects.get(name=category))
    	Todo.save() #   
        return redirect("/todo") #   (        )
    if "Delete" in request.POST: #     
        checkedlist = request.POST.getlist('checkedbox') #    ,    
        for i in range(len(checkedlist)): # -    
            todo = TodoList.objects.filter(id=int(checkedlist[i]))
        	todo.delete() # 
return render(request, "todo.html", {"todos": todos, "categories": categories})

هذا كله مع أصابع القدم. ثم يمكننا الذهاب إلى صفحة الفئات. نقوم بإنشاء دالة للفئات التي سيكون لدينا فيها أيضًا وظيفة إضافة وحذف فئة. بشكل أساسي ، لن يكون هناك شيء جديد هنا ، سيكون لدينا أيضًا القدرة على الإضافة والإزالة:

def category(request):
	categories = Category.objects.all()  #   
	if request.method == "POST": #    POST
    	if "Add" in request.POST: #  
        	name = request.POST["name"] #  
        	category = Category(name=name) #     
            category.save() #   
        	return redirect("/category")
    	if "Delete" in request.POST: #    
            check = request.POST.getlist('check') #       todo,       
            for i in range(len(check)):
            	try:
                	ateg = Category.objects.filter(id=int(check[i]))
                	ateg.delete()   # 
            	except BaseException: #        ,       
                	return HttpResponse('<h1>     )</h1>')
	return render(request, "category.html", {"categories": categories})

هذا هو المكان الذي ننتهي فيه بالملف viewويمكننا الانتقال إلى القوالب:

العمل مع القوالب


كما تتذكر ، لكي لا أكتب css مرة أخرى ، اعتدت bulma.cssعلى تبسيط التخطيط. لان ستكون صفحات فئاتنا والمهام
base.htmlالتي نقوم بها متشابهة جدًا ، لقد قمت بإنشاء ثلاثة ملفات: والتي ستشمل كل ما لدينا على الصفحات ، وفي category.htmlموقع todo.htmlالاختلافات:



قم بإنشائه base.htmlوتحريره:

<!DOCTYPE html>
<html lang="ru">
<head>
  <meta charset="UTF-8">
  <title>   </title>
  {% load static %}
	<link rel="shortcut icon" type="image/png" href="{% static 'favicon.png' %}"/>
   <link rel="stylesheet" type="text/css" href="{% static 'bulma.min.css' %}">
	<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css">
</head>
<body>
<div django-app="TaskManager">
	<nav class ="navbar is-success" role="navigation" aria-label="main navigation">
     	<div class="navbar-menu ">
        	<div class="navbar-start">
        	<a class="navbar-item" href="../category"> </a>
        	<a class="navbar-item" href="../todo">   </a>
        	</div>
         </div>
	</nav>
<!--               -->
{% block content %}
{% endblock %}
</div>
</body>
</html>

بعد ذلك ، سنذهب إلى الصفحة todo.htmlو category.html:

Tudushka:

{% extends 'base.html' %}
{% block content %}
<div class="columns has-background-black-ter is-centered has-text-white-bis" style="min-height:101vh;">
	<!--        hero,     inline-css -->
	<div class="column is-half">
    	<h1 class="is-size-3 has-text-centered">   </h1>
    	<form action="" method="post">
        	{% csrf_token %}
        	<!-- csrf      -->
            <div class="field has-text-centered">
            	<label for="description" class="label has-text-white-bis"> </label>
            	<div class="control">
             	   <input type="text" id="description" class="input" placeholder="  ?"
                    	name="description" required>
            	</div>
        	</div>
        	<div class="columns">
            	<div class="column">
                	<label for="category"></label>
                	<div class="control">
                    	<div class="select">
                        	<select id="category" class="select" name="category_select" required>
                            	<!--  required,       .    -->
                            	<option class="disabled" value="">  </option>
                    	        {% for category in categories %}
 	                           <option class="" value="{{ category.name }}" name="{{ category.name }}">
                                    {{ category.name }}</option>
                            	{% endfor %}
                        	</select>
    	                </div>
                	</div>
            	</div>
            	<div class="column">
                	<label for="dueDate"> </label>
                	<input type="date" id="dueDate" class="input calendar" name="date" required>
            	</div>
        	</div>
        	<div class="column">
            	<div class="field">
                	<button class="button is-primary" name="Add" type="submit">
                    	<span class="icon is-small">
                        	<i class="fa fa-plus"></i>
                    	</span>
                    	<span> </span>
                	</button>
             	   <button class="button is-link" name="Delete" formnovalidate="" type="submit">
                    	<span class="icon is-small">
                        	<i class="fa fa-trash-o"></i>
                    	</span>
                    	<span>
                        	 
                    	</span>
                	</button>
            	</div>
        	</div>
        	<div class="list is-hoverable">
            	{% for todo in todos %}
            	<!--   django- for loop -->
            	<div class="list-item">
                	<label class="checkbox">
                    	<input type="checkbox" class=" checkbox" name="checkedbox" value="{{ todo.id }}">
                    	<span class="complete-">{{ todo.title }}</span>
                	</label>
                	<span class=" category-{{ todo.category }} has-text-info">{{ todo.category }}</span>
                	<strong class="is-pulled-right"><i class="fa fa-calendar"></i>{{ todo.created }} -
                    	{{ todo.due_date }}</strong>
            	</div>
            	{% endfor %}
        	</div>
    	</form>
	</div>
</div>
{% endblock %}

و category.html. في ذلك ، ليس لدينا الكثير من التغييرات ، ولا تختلف اختلافًا جوهريًا عن todo.html:

{% extends 'base.html' %}
{% block content %}
<div class="columns has-background-link has-text-white is-centered" style="min-height: 101vh;">
	<div class="column is-half">
    	<h1 class="is-size-4 has-text-centered">    </h1>
    	<form action="" method="post">
        	{% csrf_token %}
        	<!-- csrf      -->
            <div class="field has-text-centered">
            	<label for="description" class="label has-text-white-bis">   </label>
            	<div class="control">
     	           <input type="text" id="description" class="input" placeholder="    ?"
                    	name="name" required>
            	</div>
            	<div class="field">
                	<button class="button is-primary" name="Add" type="submit">
                    	<span class="icon is-small">
                        	<i class="fa fa-plus"></i>
                    	</span>
                    	<span> </span>
                	</button>
                	<button class="button is-danger" name="Delete" formnovalidate="" type="submit">
                    	<span class="icon is-small">
           	             <i class="fa fa-trash-o"></i>
                    	</span>
	                    <span>   </span>
                	</button>
            	</div>
            </div>
 
            <!--  c   -->
            <div class="list is-hoverable">
            	{% for category in categories %}
            	<div class="list-item">
                	<label class="checkbox">
                    	<input type="checkbox" class="checkbox" name="check" value="{{category.id}}">
                    	<span class="complete-">{{ category.name }}</span>
                	</label>
            	</div>
            	{% endfor %}
 
        	</div>
    	</form>
	</div>
    {% endblock %}
 

شكرا للجميع! هذا كل شئ. ربما ، في مكان ما ، التخطيط ليس مثاليًا ، أو هناك اقتراحات أخرى لتحسين التطبيق ، أنا في انتظار الجميع في التعليق. حسب التقاليد ، بعض الروابط المفيدة:

  1. Django, 3
  2. ,
  3. PostgreSQL

All Articles