vps

ایجاد یک URL کوتاه کننده با Django و GraphQL

GraphQL یک استاندارد API است که توسط فیس بوک به عنوان جایگزینی برای API های REST ایجاد و منبع باز شده است. بر خلاف API های REST ،GraphQL از یک سیستم تایپ شده برای تعریف ساختار داده خود استفاده می کند ، جایی که تمام اطلاعات باید مطابق با یک طرح از پیش تعریف شده ارسال و دریافت شوند. همچنین به جای چندین URL برای منابع مختلف، یک انتهای واحد برای همه ارتباطات در معرض دید قرار می دهد و با بازگرداندن تنها داده های درخواست شده توسط کلاینت ، مشکل overfetching  را حل می کند و از این طریق پاسخ های کوچکتر و مختصر تری ایجاد می کند.
در این آموزش شما یک پس زمینه برای کوتاه کننده URL ایجاد می کنید – خدماتی که هر URL را در اختیار شما قرار می دهد و یک نسخه کوتاهتر و خواندنی تر تولید می کند – در حالی که به مفاهیم GraphQL مانند نمایش داده ها و جهش ها و ابزارهایی مانند رابط GraphiQL می پردازید. ممکن است قبلاً مانند سرویس bit.ly از چنین سرویس هایی استفاده کرده باشید.
از آنجا که GraphQL یک فناوری آگنوستیک زبانی است ، روی زبانها و چارچوبهای مختلف پیاده سازی می شود. در اینجا ، شما از زبان برنامه نویسی Python هدف کلی ، چارچوب وب Django ، و کتابخانه Graphene-Django به عنوان اجرای GraphQL Python با ادغام های ویژه برای Django استفاده خواهید کرد.
پیش نیازها
• برای ادامه این آموزش ، به نصب پایتون نسخه 3.5 یا بالاتر در دستگاه توسعه خود نیاز دارید. برای نصب Python ، آموزش ما را در مورد نحوه نصب و راه اندازی یک محیط برنامه نویسی محلی برای Python 3 برای سیستم عامل خود را دنبال کنید. اطمینان حاصل کنید که یک محیط مجازی نیز ایجاد و راه اندازی کنید؛ برای دنبال کردن این آموزش ، می توانید دیرکتوری پروژه خود را shorty بنامید.
• دانش سطح ورود به Django نیز توصیه میشود ، اما اجباری نیست. اگر کنجکاو هستید ، می توانید مجموعه توسعه Django ایجاد شده توسط انجمن vpsgol را دنبال کنید.
مرحله 1 – تنظیم پروژه Django
در این مرحله تمام ابزارهای لازم برای برنامه را نصب کرده و پروژه Django خود را تنظیم می کنید.
هنگامی که دایرکتوری پروژه خود را ایجاد کردید و محیط مجازی خود را راه اندازی کردید ، همانطور که در پیش نیازها پوشش داده شده است ، بسته های لازم را با استفاده از pip ، مدیر بسته پایتون نصب کنید. در این آموزش Django نسخه 2.1.7 و Graphene-Django نسخه 2.2.0 یا بالاتر نصب می شوند:
⦁ $ pip install “django==2.1.7” “graphene-django>==2.2.0”

اکنون تمام ابزارهای مورد نیاز خود را در کمربند ابزار خود دارید. در مرحله بعد با استفاده از دستور django-admin یک پروژه Django ایجاد خواهید کرد. یک پروژه به طور پیش فرض متن استاندارد Django است – مجموعه ای از پوشه ها و فایل ها با هر چیز لازم برای شروع توسعه یک برنامه وب. در این حالت ، شما پروژه خود را shorty می خوانید و با مشخص کردن نقطه در انتها، آن را در پوشه فعلی خود ایجاد می کنید:
⦁ $ django-admin startproject shorty .

بعد از ایجاد پروژه خود ،  Django migrations را اجرا خواهید کرد. این فایل ها حاوی کد پایتونی هستند که توسط Django تولید شده است و وظیفه تغییر ساختار برنامه را مطابق مدل های Django دارند. به عنوان مثال تغییرات ممکن است شامل ایجاد جدول باشد. به طور پیش فرض ، Django با مجموعه ای از جابه جایی های خود که مسئول زیر سیستم هایی مانند Django Authentication هستند ، همراه است ، بنابراین لازم است آنها را با دستور زیر اجرا کنید:
⦁ $ python manage.py migrate

این دستور از مفسر پایتون برای استناد به اسکریپت Django به نام managet.py استفاده می کند که مسئولیت مدیریت جنبه های مختلف پروژه شما ، مانند ایجاد برنامه ها یا اجرای جا به جایی ها را بر عهده دارد.
این دستور خروجی شبیه به زیر را ارائه می دهد:
Output
Operations to perform:
Apply all migrations: admin, auth, contenttypes, sessions
Running migrations:
Applying contenttypes.0001_initial… OK
Applying auth.0001_initial… OK
Applying admin.0001_initial… OK
Applying admin.0002_logentry_remove_auto_add… OK
Applying admin.0003_logentry_add_action_flag_choices… OK
Applying contenttypes.0002_remove_content_type_name… OK
Applying auth.0002_alter_permission_name_max_length… OK
Applying auth.0003_alter_user_email_max_length… OK
Applying auth.0004_alter_user_username_opts… OK
Applying auth.0005_alter_user_last_login_null… OK
Applying auth.0006_require_contenttypes_0002… OK
Applying auth.0007_alter_validators_add_error_messages… OK
Applying auth.0008_alter_user_username_max_length… OK
Applying auth.0009_alter_user_last_name_max_length… OK
Applying sessions.0001_initial… OK

پس از آماده شدن پایگاه داده Django ، سرور مجازی توسعه محلی خود را شروع کنید:
⦁ $ python manage.py runserver

خروجی زیر را می دهد:
Output
Performing system checks…

System check identified no issues (0 silenced).
March 18, 2020 – 15:46:15
Django version 2.1.7, using settings ‘shorty.settings’
Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.

این دستور اعلان را در ترمینال شما از بین می برد و سرور مجازی را شروع می کند.
از صفحه http://127.0.0.1:8000 در مرورگر محلی خود بازدید کنید. این صفحه را مشاهده خواهید کرد:

برای متوقف کردن سرور مجازی و بازگشت به ترمینال خود ، CTRL + C را فشار دهید. هر زمان که نیاز به دسترسی به مرورگر داشته باشید ، اطمینان حاصل کنید که دستور قبلی در حال اجرا است.
در مرحله بعد ، با فعال کردن کتابخانه Django-Graphene در پروژه ، این مرحله را تمام خواهید کرد. Django دارای محتوای app ، یک برنامه وب با مسئولیت خاص میباشد. یک پروژه از یک یا چندین برنامه تشکیل شده است. در حال حاضر ، فایل shorty / settings.py را در ویرایشگر متن مورد نظر خود باز کنید. این آموزش از vim استفاده خواهد کرد:
⦁ $ vim shorty/settings.py

فایل settings.py تمام تنظیمات موجود در پروژه شما را مدیریت می کند. در داخل آن ، INSTALLED_APPS را جستجو کرده و خط “graphene_django” را اضافه کنید:
shorty/shorty/settings.py

INSTALLED_APPS = [
‘django.contrib.admin’,
‘django.contrib.auth’,
‘django.contrib.contenttypes’,
‘django.contrib.sessions’,
‘django.contrib.messages’,
‘django.contrib.staticfiles’,
‘graphene_django’,
]

این افزونه به Django می گوید که شما از برنامه ای به نام graphene_django که در مرحله 1 نصب کرده اید ، استفاده خواهید کرد.
در پایین فایل ، متغیر زیر را اضافه کنید:
shorty/shorty/settings.py

GRAPHENE = {
‘SCHEMA’: ‘shorty.schema.schema’,
}

این متغیر آخر به طرح اصلی شما اشاره دارد که بعداً ایجاد خواهید کرد. در GraphQL ، یک شماتیک شامل انواع شیء مانند منابع ، جستجوها و جهش ها است. آن را به عنوان مستنداتی که تمام داده ها و عملکردهای موجود در سیستم شما را نشان می دهد ، در نظر بگیرید.
پس از اصلاحات ، فایل را ذخیره کرده و ببندید.
اکنون پروژه Django را پیکربندی کرده اید. در مرحله بعد ، یک برنامه Django و مدل های آن را ایجاد خواهید کرد.
مرحله 2 – تنظیم برنامه و مدل های Django
یک پلتفرم Django معمولاً از یک پروژه و بسیاری برنامه یا app تشکیل شده است. یک app مجموعه ای از ویژگی های درون پروژه ای را توصیف می کند و در صورت طراحی مناسب می تواند در پروژه های Django استفاده مجدد شود.
در این مرحله برنامه ای به نام shortener ایجاد خواهید کرد ، که مسئول ویژگی کوتاه کردن URL واقعی است. برای ایجاد اسکلت اصلی آن ، دستور بعدی را در ترمینال خود تایپ کنید:
⦁ $ python manage.py startapp shortener

در اینجا شما از پارامترهای startapp app_name استفاده کرده و از دستور manage.py برای ایجاد یک app با نام shortener استفاده می کنید.
برای پایان دادن به ایجاد برنامه ، فایل shorty / settings.py را باز کنید
⦁ $ vim shorty/settings.py

نام برنامه را به همان ورودی INSTALLED_APPS که قبلاً اصلاح کرده اید اضافه کنید:
shorty/shorty/settings.py

INSTALLED_APPS = [
‘django.contrib.admin’,
‘django.contrib.auth’,
‘django.contrib.contenttypes’,
‘django.contrib.sessions’,
‘django.contrib.messages’,
‘django.contrib.staticfiles’,
‘graphene_django’
‘shortener’,
]

فایل را ذخیره کنید و ببندید.
با افزودن shortener خود به shorty / settings.py ، می توانید به سمت ایجاد مدل هایی برای پروژه خود بروید. مدل ها یکی از ویژگی های مهم در Django هستند. از آنها برای نشان دادن یک پایگاه داده به روش “Pythonic” استفاده می شود و به شما امکان می دهد داده ها را با استفاده از کد پایتون مدیریت ، پرس و جو و ذخیره کنید.
پیش از باز کردن فایل model.py برای تغییرات ، این آموزش مختصری از تغییراتی را که شما ایجاد خواهید کرد را ارائه می دهد.
پس از تعویض کد موجود ، فایل مدل — shortener / model.py — شامل محتوای زیر خواهد بود:
shorty/shortener/models.py
from hashlib import md5

from django.db import models
در اینجا بسته های مورد نیاز کد مورد نظر خود را وارد می کنید. برای وارد کردن کتابخانه استاندارد Python که برای ایجاد hash  در URL از آن استفاده می شود ، خط from hashlib import md5 را در قسمت بالا اضافه خواهید کرد. خط from django.db import models به Django برای ایجاد مدل ها کمک میکند.
اخطار: این آموزش به hash  به عنوان نتیجه عملکردی که یک ورودی را می گیرد و همیشه همان بازده را برمی گرداند اشاره دارد. این آموزش با استفاده از عملکرد hash  MD5 برای اهداف نمایشی استفاده می شود.
توجه داشته باشید که MD5 دارای مشکلات برخوردی است و باید در تولید از آن جلوگیری کرد.
در مرحله بعد ، یک مدل به نام URL با فیلدهای زیر اضافه خواهید کرد:
⦁ full_url: URL ای که باید کوتاه شود.
⦁ url_hash: یک hash  کوتاه است که URL کامل را نشان می دهد.
⦁ clicks: تعداد دفعاتی که به URL کوتاه دسترسی پیدا شده است.
⦁ created_at: تاریخ و زمانی که URL ایجاد شده است.
shorty/shortener/models.py

class URL(models.Model):
full_url = models.URLField(unique=True)
url_hash = models.URLField(unique=True)
clicks = models.IntegerField(default=0)
created_at = models.DateTimeField(auto_now_add=True)

شما می توانید url_hash را با اعمال الگوریتم hash MD5 در قسمت full_url و با استفاده از فقط 10 کاراکتر اول برگردانده شده در طی روش save() در مدل ، تولید کنید ، که هر بار Django ورودی را در پایگاه داده ذخیره می کند، اجرا می شود. علاوه بر این ، کوتاه کننده های URL معمولاً تعداد دفعاتی که روی پیوند کلیک شده است را دنبال می کنند. با فراخوانی روش clicked() در هنگام بازدید از URL توسط کاربر ، به این هدف دست خواهید یافت.
عملیات ذکر شده با این کد در مدل URL شما اضافه می شود:
shorty/shortener/models.py

def clicked(self):
self.clicks += 1
self.save()

def save(self, *args, **kwargs):
if not self.id:
self.url_hash = md5(self.full_url.encode()).hexdigest()[:10]

return super().save(*args, **kwargs)

اکنون که کد را مرور کرده اید ، فایل shortener/models.py را باز کنید:
⦁ $ vim shortener/models.py

کد را با محتوای زیر جایگزین کنید:
shorty/shortener/models.py
from hashlib import md5

from django.db import models

class URL(models.Model):
full_url = models.URLField(unique=True)
url_hash = models.URLField(unique=True)
clicks = models.IntegerField(default=0)
created_at = models.DateTimeField(auto_now_add=True)

def clicked(self):
self.clicks += 1
self.save()

def save(self, *args, **kwargs):
if not self.id:
self.url_hash = md5(self.full_url.encode()).hexdigest()[:10]

return super().save(*args, **kwargs)

حتما فایل را ذخیره کنید و ببندید.
برای اعمال این تغییرات در پایگاه داده ، باید با اجرای دستور زیر migrations  را ایجاد کنید:
⦁ $ python manage.py makemigrations

این کار خروجی زیر را به شما می دهد:
Output
Migrations for ‘shortener’:
shortener/migrations/0001_initial.py
– Create model URL

سپس migrations را اجرا کنید:
⦁ $ python manage.py migrate

خروجی زیر را در ترمینال خود مشاهده خواهید کرد:
Output
Operations to perform:
Apply all migrations: admin, auth, contenttypes, sessions, shortener
Running migrations:
Applying shortener.0001_initial… OK

اکنون که مدل ها را تنظیم کرده اید ، در مرحله بعدی نقطه پایانی GraphQL و یک جستار ایجاد خواهید کرد.
مرحله 3 – ایجاد جستارها (Queries)
معماری REST منابع مختلفی را در نقاط پایانی مختلف در معرض دید قرار می دهد ، هرکدام دارای یک ساختار داده به خوبی تعریف شده هستند. به عنوان مثال ، ممکن است لیست کاربران را از /api/users دریافت کنید ، که همیشه انتظار فیلدهای مشابه دارید. از طرف دیگر GraphQL یک نقطه پایانی واحد برای همه تعامل ها دارد و از جستارها برای دسترسی به داده ها استفاده می کند. اصلی ترین و با ارزش ترین تفاوت این است که می توانید از Query برای بازیابی همه کاربران خود در طی یک درخواست استفاده کنید.
با ایجاد یک Query برای واکشی همه URL ها شروع کنید. به چند مورد نیاز خواهید داشت:
• نوع URL ، مربوط به مدل تعریف شده قبلی شما.
• یک عبارت پرس و جو به نام urls .
• روشی برای کار با Query ، به معنای واکشی کلیه آدرس ها از پایگاه داده و برگرداندن آنها به کلاینت.
یک فایل جدید به نام shortener / schema.py ایجاد کنید:
⦁ $ vim shortener/schema.py

با افزودن عبارتات import  پایتون شروع کنید:
shorty/shortener/schema.py
import graphene
from graphene_django import DjangoObjectType

from .models import URL

اولین خط ، کتابخانه اصلی graphene  است، که شامل انواع پایه GraphQL مانند Listاست.
. DjangoObjectType کمکی برای ایجاد تعریف شماتیک از هر مدل Django ، و خط سوم مدل ایجاد URL قبلی شما را وارد می کند.
پس از آن ، با افزودن خطوط زیر ، یک نوع GraphQL جدید برای مدل URL ایجاد کنید:
shorty/shortener/schema.py

class URLType(DjangoObjectType):
class Meta:
model = URL

در آخر ، این خطوط را اضافه کنید تا یک نوع Query برای مدل URL ایجاد شود:
shorty/shortener/schema.py

class Query(graphene.ObjectType):
urls = graphene.List(URLType)

def resolve_urls(self, info, **kwargs):
return URL.objects.all()

این کد یک کلاس Query با یک فیلد به نام urls ایجاد می کند ، که لیستی از URLType قبلاً تعریف شده است. هنگام حل Query از طریق روش remove_urls ، تمام URL های ذخیره شده در پایگاه داده را برمی گردانید.
فایل کامل shortener/schema.py در اینجا نشان داده شده است:
shorty/shortener/schema.py
import graphene
from graphene_django import DjangoObjectType

from .models import URL

class URLType(DjangoObjectType):
class Meta:
model = URL

class Query(graphene.ObjectType):
urls = graphene.List(URLType)

def resolve_urls(self, info, **kwargs):
return URL.objects.all()

فایل را ذخیره کنید و ببندید.
اکنون باید تمام Query ها به طرح اصلی اضافه شوند. آن را به عنوان نگه دارنده تمام منابع خود تصور کنید.
یک فایل جدید در مسیر shorty / schema.py ایجاد کنید و آن را با ویرایشگر خود باز کنید:
⦁ $ vim shorty/schema

بسته های Python بعدی را با اضافه کردن خطوط زیر وارد کنید. اولین مورد ، همانطور که قبلاً نیز گفته شد ، شامل انواع پایه GraphQL است. خط دوم فایل شماتیک قبلاً ایجاد شده را وارد می کند.
shorty/shorty/schema.py
import graphene

import shortener.schema

سپس ، کلاس اصلی Query را اضافه کنید. به صورت موروثی ، تمام جستارها و عملیات ایجاد شده آینده را نگه میدارد:
shorty/shorty/schema.py

class Query(shortener.schema.Query, graphene.ObjectType):
pass

در آخر ، متغیر شماتیک را ایجاد کنید:
shorty/shorty/schema.py

schema = graphene.Schema(query=Query)

تنظیم SCHEMA که در مرحله 2 تعریف کرده اید به متغیر schema  که اخیراً ایجاد کرده اید اشاره می کند.
فایل کامل shorty/schema.pyدر اینجا نشان داده شده است:
shorty/shorty/schema.py
import graphene

import shortener.schema

class Query(shortener.schema.Query, graphene.ObjectType):
pass

schema = graphene.Schema(query=Query)

فایل را ذخیره کنید و ببندید.
در مرحله بعد ، نقطه انتهایی GraphQL و رابط GraphiQL را فعال کنید که یک رابط وب گرافیکی مورد استفاده برای تعامل با سیستم GraphQL میباشد.
فایل shorty / urls.py را باز کنید:
⦁ $ vim shorty/urls.py

برای اهداف یادگیری ، محتوای فایل را حذف کرده و آن را ذخیره کنید ، تا بتوانید از ابتدا شروع کنید.
اولین سطرهایی که اضافه خواهید کرد عبارت ورودی پایتون است:
shorty/shorty/urls.py
from django.urls import path
from django.views.decorators.csrf import csrf_exempt

from graphene_django.views import GraphQLView

تابع path  توسط Django برای ایجاد یک URL در دسترس برای رابط GraphiQL استفاده می شود. پس از آن ، csrf_exempt را وارد می کنید ، که به کلاینت ها امکان می دهد داده ها را به سرور مجازی ارسال کنند. توضیحات کامل را می توان در مستندات Graphene یافت. در آخرین خط ، کد واقعی مسئول رابط را از طریق GraphQLView وارد کردید.
سپس ، یک متغیر به نام urlpatterns ایجاد کنید.
shorty/shorty/urls.py

urlpatterns = [
path(‘graphql/’, csrf_exempt(GraphQLView.as_view(graphiql=True))),
]

با این کار تمام کدهای لازم برای ایجاد رابط GraphiQL در مسیر graphql/ در کنار هم قرار می گیرد:
فایل کامل shortener/urls.py در اینجا آمده است:
shorty/shorty/urls.py
from django.urls import path
from django.views.decorators.csrf import csrf_exempt

from graphene_django.views import GraphQLView

urlpatterns = [
path(‘graphql/’, csrf_exempt(GraphQLView.as_view(graphiql=True))),
]

فایل را ذخیره کنید و آن را ببندید.
به ترمینال برگردید ، دستور runderver python management.py را اجرا کنید (اگر قبلاً اجرا نشده است):
⦁ $ python manage.py runserver

مرورگر وب خود را در آدرس http: // localhost: 8000 / Graphql باز کنید. به شما این صفحه نمایش داده می شود:

GraphiQL رابطی است که در آن می توانید عبارت GraphQL را اجرا کرده و نتایج را مشاهده کنید. یکی از ویژگی ها، بخش Docs در بالا سمت راست میباشد. از آنجا که همه چیز در GraphQL تایپ شده است ، در مورد انواع ، پرس و جوها ، جهش ها و غیره مطالب رایگان دریافت می کنید.
پس از جستجو در صفحه ، اولین Query خود را در قسمت متن اصلی وارد کنید:
query {
urls {
id
fullUrl
urlHash
clicks
createdAt
}
}

این محتوا چگونگی ساخت یک جستار GraphQL را نشان می دهد: ابتدا ، از کلیدواژه query استفاده می کنید تا به سرور مجازی بگویید که شما فقط می خواهید برخی داده ها را پس بگیرید. در مرحله بعد ، از فیلد url تعریف شده در فایل shortener / schema.py در داخل کلاس Query استفاده می کنید. از این طریق ، به طور صریح تمام فیلدهای تعریف شده در مدل URL را با استفاده از سبک شتر ، که پیش فرض آن برای GraphQL است ، درخواست می کنید.
حالا روی play arrow button در سمت چپ بالای صفحه کلیک کنید.
پاسخ ذیل را دریافت خواهید کرد ، که نشان میدهد شما هنوز URL ندارید:
Output
{
“data”: {
“urls”: []
}
}

این نشان می دهد که GraphQL در حال کار است. در ترمینال خود ، CTRL + C را فشار دهید تا سرور مجازی شما متوقف شود.
شما در این مرحله کارهای بسیاری انجام داده اید ، نقطه پایانی GraphQL را ایجاد کردید، یک جستار برای دریافت همه URL ها تهیه کردید و رابط GraphiQL را فعال نمدید. اکنون ، برای تغییر بانک اطلاعاتی ، جهش هایی ایجاد خواهید کرد.
مرحله 4 – ایجاد جهش ها
اکثر برنامه ها با اضافه کردن ، به روزرسانی یا حذف داده ها راهی برای تغییر وضعیت پایگاه داده دارند. در GraphQL ، این عملیات Mutations نامیده می شود. Mutations یا جهش ها مانند Query به نظر می رسند اما از آرگومانهایی برای ارسال داده به سرور مجازی استفاده می کنند.
برای ایجاد اولین جهش خود ، Shortener / schema.py را باز کنید:
⦁ $ vim shortener/schema.py

در پایان فایل ، با اضافه کردن یک کلاس جدید به نام CreatURL شروع کنید:
shorty/shortener/schema.py

class CreateURL(graphene.Mutation):
url = graphene.Field(URLType)

این کلاس کمک کننده graphene.Mutation را به ارث می برد تا از قابلیت های یک جهش GraphQL برخوردار باشد. همچنین دارای یک ویژگی به نام url است که محتویاتی را که پس از اتمام جهش توسط سرور مجازی برگردانده می شود ، تعریف می کند. در این حالت ، ساختار داده URLType خواهد بود.
در مرحله بعد ، زیرکلاسی به نام Argument را به کلاس از قبل تعریف شده اضافه کنید:
shorty/shortener/schema.py

class Arguments:
full_url = graphene.String()

این کلاس تعریف می کند که چه داده هایی توسط سرور مجازی پذیرفته می شوند. در اینجا ، در انتظار یک پارامتر به نام full_url با محتوای String هستید:
اکنون خطوط زیر را برای ایجاد روش mutate  اضافه کنید:
shorty/shortener/schema.py

def mutate(self, info, full_url):
url = URL(full_url=full_url)
url.save()

این روش mutate  با دریافت داده ها از کلاینت و ذخیره آن در پایگاه داده ، کارهای زیادی را انجام می دهد. در پایان ، خود کلاس را که حاوی آیتم تازه ایجاد شده است ، برمی گرداند.
در آخر ، یک کلاس Mutation  ایجاد کنید تا با اضافه کردن این خطوط ، تمام جهش ها را برای برنامه خود نگه دارید:
shorty/shortener/schema.py

class Mutation(graphene.ObjectType):
create_url = CreateURL.Field()

تا کنون ، شما فقط یک جهش به نام create_url خواهید داشت.
فایل کامل shortener/schema.py در اینجا نشان داده شده است:
shorty/shortener/schema.py
import graphene
from graphene_django import DjangoObjectType

from .models import URL

class URLType(DjangoObjectType):
class Meta:
model = URL

class Query(graphene.ObjectType):
urls = graphene.List(URLType)

def resolve_urls(self, info, **kwargs):
return URL.objects.all()

class CreateURL(graphene.Mutation):
url = graphene.Field(URLType)

class Arguments:
full_url = graphene.String()

def mutate(self, info, full_url):
url = URL(full_url=full_url)
url.save()

return CreateURL(url=url)

class Mutation(graphene.ObjectType):
create_url = CreateURL.Field()

فایل را ذخیره کنید و ببندید.
برای اتمام اضافه کردن جهش ، فایل shorty / schema.py را تغییر دهید:
⦁ $ vim shorty/schema.py

فایل را تغییر دهید تا کد هایلایت شده زیر را شامل میشود:
shorty/shorty/schema.py

import graphene

import shortener.schema

class Query(shortener.schema.Query, graphene.ObjectType):
pass

class Mutation(shortener.schema.Mutation, graphene.ObjectType):
pass

schema = graphene.Schema(query=Query, mutation=Mutation)

فایل را ذخیره کنید و ببندید. اگر در حال اجرای سرور مجازی محلی نیستید ، آن را شروع کنید:
⦁ $ python manage.py runserver

در مرورگر وب خود به http: // localhost: 8000 / Graphql بروید. اولین جهش خود را در رابط وب GraphiQL با اجرای جمله زیر انجام دهید:
mutation {
createUrl(fullUrl:”https://www.vpsgol.net/community”) {
url {
id
fullUrl
urlHash
clicks
createdAt
}
}
}

شما جهش را با نام CreatURL ، آرگومان fullUrl و داده هایی که می خواهید در پاسخ در فیلد url تعریف شود را تهیه کردید.
خروجی شامل اطلاعات URL شما میباشد که اکنون در قسمت data  در GraphQL ایجاد شده است ، همانطور که در اینجا نشان داده شده:
Output
{
“data”: {
“createUrl”: {
“url”: {
“id”: “1”,
“fullUrl”: “https://www.vpsgol.net/community”,
“urlHash”: “077880af78”,
“clicks”: 0,
“createdAt”: “2020-01-30T19:15:10.820062+00:00”
}
}
}
}

با این کار ، همانطور که در قسمت urlHash مشاهده می کنید ،URL با نسخه hashed خود به بانک اطلاعاتی اضافه شد. سعی کنید Query را که در آخرین مرحله ایجاد کرده اید اجرا کنید تا نتیجه آن را ببینید:
query {
urls {
id
fullUrl
urlHash
clicks
createdAt
}
}

خروجی URL ذخیره شده را نشان می دهد:
Output
{
“data”: {
“urls”: [
{
“id”: “1”,
“fullUrl”: “https://www.vpsgol.net/community”,
“urlHash”: “077880af78”,
“clicks”: 0,
“createdAt”: “2020-03-18T21:03:24.664934+00:00”
}
]
}
}

همچنین می توانید همان Query را اجرا کنید ، اما فقط فیلدهایی را که می خواهید درخواست کنید.
سپس ، یک بار دیگر آن را با URL متفاوت امتحان کنید:
mutation {
createUrl(fullUrl:”https://www.vpsgol.net/write-for-donations/”) {
url {
id
fullUrl
urlHash
clicks
createdAt
}
}
}

خروجی به صورت زیر خواهد بود:
Output
{
“data”: {
“createUrl”: {
“url”: {
“id”: “2”,
“fullUrl”: “https://www.vpsgol.net/write-for-donations/”,
“urlHash”: “703562669b”,
“clicks”: 0,
“createdAt”: “2020-01-30T19:31:10.820062+00:00”
}
}
}
}

اکنون سیستم قادر به ایجاد URL های کوتاه و لیست آنهاست. در مرحله بعد ، شما کاربران را قادر خواهید ساخت تا با نسخه کوتاه آن به یک URL دسترسی پیدا کنند و آنها را به صفحه صحیح هدایت کنید.
مرحله 5 – ایجاد نقطه پایان دسترسی
در این مرحله ، از Django Views استفاده می کنید – روشی که یک درخواست را می گیرد و پاسخی را برمی گرداند- تا هر شخصی که به نقطه پایان http: // localhost: 8000 / url_hash دسترسی دارد را به آدرس اینترنتی کامل آن هدایت کنید.
فایل shortener / views.py را با ویرایشگر خود باز کنید:
⦁ $ vim shortener/views.py

برای شروع ، دو بسته را با جایگزین کردن محتوا با سطرهای زیر وارد کنید:
shorty/shortener/views.py
from django.shortcuts import get_object_or_404, redirect

from .models import URL

در ادامه اینها با جزئیات بیشتری توضیح داده می شوند.
سپس ، Django Views را با نام root ایجاد می کنید. این قطعه کد که مسئول View  در انتهای فایل شماست را اضافه کنید:
shorty/shortener/views.py

def root(request, url_hash):
url = get_object_or_404(URL, url_hash=url_hash)
url.clicked()

return redirect(url.full_url)

آرگومانی به نام url_hash را از URL دریافت می کند که توسط کاربر درخواست شده است. در داخل تابع ، خط اول سعی می کند URL را با استفاده از آرگومان url_hash از پایگاه داده دریافت کند. در صورت عدم یافتن ، خطای HTTP 404 را به کلاینت باز می گرداند ، به این معنی که منبع از دست رفته است. پس از آن ، ویژگی clicked  در ورود URL را افزایش می دهد ، و اطمینان حاصل میکند که تعداد دفعات دسترسی به URL را ثبت کرده است. در پایان ، کلاینت را به URL درخواست شده هدایت می کند.
فایل کامل shortener/views.py در اینجا نشان داده شده است:
shorty/shortener/views.py
from django.shortcuts import get_object_or_404, redirect

from .models import URL

def root(request, url_hash):
url = get_object_or_404(URL, url_hash=url_hash)
url.clicked()

return redirect(url.full_url)

فایل را ذخیره کنید و ببندید.
سپس ، shorty / urls.py را باز کنید:
⦁ $ vim shorty/urls.py

کد هایلایت شده زیر را برای فعال کردن نمای root اضافه کنید.
shorty/shorty/urls.py

from django.urls import path
from django.views.decorators.csrf import csrf_exempt

from graphene_django.views import GraphQLView

from shortener.views import root

urlpatterns = [
path(‘graphql/’, csrf_exempt(GraphQLView.as_view(graphiql=True))),
path(‘<str:url_hash>/’, root, name=’root’),
]

نمای root در مسیر / سرور مجازی شما قابل دسترسی خواهد بود و url_hash را به عنوان یک پارامتر رشته قبول می کند.
فایل را ذخیره کنید و ببندید. اگر در حال اجرای سرور مجازی محلی نیستید ، آن را با اجرای فرمان python manage.py runserver شروع کنید.
برای آزمایش متعلقات جدید ، مرورگر وب خود را باز کرده و به URL http: // localhost: 8000 / 077880af78 دسترسی پیدا کنید. توجه داشته باشید که قسمت آخر، URL hash باشد که توسط جهش از مرحله 5 ایجاد شده است. شما به صفحه URL hash هدایت می شوید .
اکنون که تغییر مسیر URL کار می کند ، با اجرای خطا هنگام اجرای جهش ، برنامه را ایمن تر می کنید.
مرحله 6 – اجرای مدیریت خطا
مدیریت خطاها بهترین روش در همه برنامه ها است ، زیرا برنامه نویسان معمولاً چیزی که برای سرور مجازی ارسال می کنند را کنترل نمیکنند. در این حالت ، می توانید سعی کنید نواقص را پیش بینی کنید و تأثیرات آنها را به حداقل برسانید. در سیستم پیچیده ای مانند GraphQL ، بسیاری از موارد ممکن است اشتباه پیش بروند ، از درخواست کلاینت برای داده های اشتباه تا از دست دادن دسترسی سرور مجازی به پایگاه داده.
به عنوان یک سیستم تایپ شده ، GraphQL می تواند هر کاری را که کلاینت درخواست کرده و در عملیاتی به نام Schema Validation دریافت می کند را تأیید نماید. با ساختن یک جستار با یک فیلد غیر موجود می توانید این کار را در عمل مشاهده کنید.
یک بار دیگر به مرورگر خود به http: // localhost: 8000 / Graphql بروید و جستار بعدی را در رابط GraphiQL با فیلد iDontExist اجرا کنید:
query {
urls {
id
fullUrl
urlHash
clicks
createdAt
iDontExist
}
}

از آنجا که هیچ فیلد iDontExist تعریف شده در جستار شما وجود ندارد ، GraphQL یک پیام خطا را برمی گرداند:
Output

{
“errors”: [
{
“message”: “Cannot query field \”iDontExist\” on type \”URLType\”.”,
“locations”: [
{
“line”: 8,
“column”: 5
}
]
}
]
}

این مسئله مهمی است زیرا ، در سیستم تایپ شده GraphQL ، هدف ارسال و دریافت اطلاعاتی است که قبلاً در این شماتیک تعریف شده است.
برنامه فعلی، هر رشته دلخواه را در قسمت full_url می پذیرد. مشکل این است که اگر شخصی آدرس اینترنتی ضعیفی ارسال کند ، هنگام امتحان کردن اطلاعات ذخیره شده ، کاربر را به ناکجا هدایت خواهید کرد. در این حالت ، باید تأیید کنید که آیا full_url قبل از ذخیره کردن آن در بانک اطلاعاتی به خوبی قالب بندی شده است ، و در صورت بروز هرگونه خطایی ، استثناء GraphQLError را با یک پیام سفارشی اعلام کنید.
بیایید این قابلیت را در دو مرحله پیاده سازی کنیم. ابتدا فایل shortener / models.py را باز کنید:
⦁ $ vim shortener/models.py

خطوط هایلایت شده را در بخش ورودی ها اضافه کنید:
shorty/shortener/models.py
from hashlib import md5

from django.db import models
from django.core.validators import URLValidator
from django.core.exceptions import ValidationError

from graphql import GraphQLError

URLValidator یاور Django است که اعتبار یک رشته URL را تأیید می کند و از GraphQLError توسط گرافن برای اعلام استثنائات با یک پیام سفارشی استفاده می شود.
سپس ، مطمئن شوید که URL دریافت شده توسط کاربر را قبل از ذخیره کردن آن در پایگاه داده ، اعتبار دهید. این عملکرد را با اضافه کردن کد هایلایت شده در فایل shortener / models.py فعال کنید:
shorty/shortener/models.py
class URL(models.Model):
full_url = models.URLField(unique=True)
url_hash = models.URLField(unique=True)
clicks = models.IntegerField(default=0)
created_at = models.DateTimeField(auto_now_add=True)

def clicked(self):
self.clicks += 1
self.save()

def save(self, *args, **kwargs):
if not self.id:
self.url_hash = md5(self.full_url.encode()).hexdigest()[:10]

validate = URLValidator()
try:
validate(self.full_url)
except ValidationError as e:
raise GraphQLError(‘invalid url’)

return super().save(*args, **kwargs)

ابتدا این کد URLValidator را در متغیر validate  معرفی می کند. در داخل بلوک try/except ، URL دریافت شده را تأیید می کنید و اگر چیزی اشتباه باشد ، یک GraphQLErr را با پیام سفارشی invalid url مطرح می کنید.
فایل کامل shortener/models.py در اینجا نشان داده شده است:
shorty/shortener/models.py
from hashlib import md5

from django.db import models
from django.core.validators import URLValidator
from django.core.exceptions import ValidationError

from graphql import GraphQLError

class URL(models.Model):
full_url = models.URLField(unique=True)
url_hash = models.URLField(unique=True)
clicks = models.IntegerField(default=0)
created_at = models.DateTimeField(auto_now_add=True)

def clicked(self):
self.clicks += 1
self.save()

def save(self, *args, **kwargs):
if not self.id:
self.url_hash = md5(self.full_url.encode()).hexdigest()[:10]

validate = URLValidator()
try:
validate(self.full_url)
except ValidationError as e:
raise GraphQLError(‘invalid url’)

return super().save(*args, **kwargs)

فایل را ذخیره کنید و ببندید. اگر در حال اجرای سرور مجازی محلی نیستید ، آن را با دستور python manage.py runserver شروع کنید.
سپس ، خطای جدید خود را در آدرس http: // localhost: 8000 / Graphql آزمایش کنید. سعی کنید یک URL جدید با full_url نامعتبر در رابط GraphiQL ایجاد کنید:
mutation {
createUrl(fullUrl:”not_valid_url”){
url {
id
fullUrl
urlHash
clicks
createdAt
}
}
}

هنگام ارسال URL نامعتبر ، استثناء شما با پیام سفارشی مطرح می شود:
Output

{
“errors”: [
{
“message”: “invalid url”,
“locations”: [
{
“line”: 2,
“column”: 3
}
],
“path”: [
“createUrl”
]
}
],
“data”: {
“createUrl”: null
}
}

اگر به ترمینال خود نگاه کنید جایی که فرمان python manage.py runserverدر حال اجرا است ، خطایی ظاهر می شود:
Output


graphql.error.located_error.GraphQLLocatedError: invalid url

[30/Jan/2020 19:46:32] “POST /graphql/ HTTP/1.1” 200 121

یک نقطه پایانی GraphQL همیشه با کد وضعیت HTTP 200 مواجه خواهد شد ، که معمولاً نشان دهنده موفقیت است. به یاد داشته باشید که ، حتی اگر GraphQL طبق HTTP ساخته شده باشد ، از مفاهیم کدهای وضعیت HTTP یا روشهای HTTP مانند REST استفاده نمی کند.
با استفاده از خطای عملی شده ، اکنون می توانید مکانیزمی را برای فیلتر کردن جستارهای خود ایجاد کنید ، که اطلاعات را توسط سرور مجازی به حداقل برساند.
مرحله 7 – اجرای فیلترها
تصور کنید که برای افزودن پیوندهای شخصی خود ، از استفاده از ابزار کوتاه کننده URL استفاده کرده اید. پس از مدتی ، ورودی های زیادی وجود خواهند داشت که پیدا کردن ورودی درست دشوار خواهد شد. می توانید با استفاده از فیلترها این مسئله را حل کنید.
فیلترینگ یک مفهوم رایج در API های REST است ، که معمولاً یک پارامتر Query با یک فیلد و مقدار در URL اضافه می شود. به عنوان نمونه ، برای فیلتر کردن تمام کاربران با نام jojo ، می توانید از GET /api/users?name=jojo استفاده کنید.
در GraphQL از آرگومان های Query به عنوان فیلتر استفاده خواهید کرد. که یک رابط درست و تمیز ایجاد می کنند.
با اجازه دادن به کلاینت جهت فیلتر کردن نام آدرس های اینترنتی با استفاده از فیلد full_url میتوانید مشکل دشواری در یافت URL را حل کنید. برای پیاده سازی، فایل shortener/schema.py را در ویرایشگر مورد علاقه خود باز کنید.
⦁ $ vim shortener/schema.py
ابتدا روش Q را در خط هایلایت شده وارد کنید:
shorty/shortener/schema.py
import graphene
from graphene_django import DjangoObjectType
from django.db.models import Q

from .models import URL

این مورد برای فیلتر کردن جستار پایگاه داده شما استفاده می شود.
در مرحله بعد ، کل کلاس Query را با محتوای زیر بازنویسی کنید:
shorty/shortener/schema.py

class Query(graphene.ObjectType):
urls = graphene.List(URLType, url=graphene.String())

def resolve_urls(self, info, url=None, **kwargs):
queryset = URL.objects.all()

if url:
_filter = Q(full_url__icontains=url)
queryset = queryset.filter(_filter)

return queryset

تغییراتی که شما ایجاد می کنید عبارتند از:
⦁ اضافه کردن پارامتر فیلتر url در متغیر url و روش resolve_url.
⦁ در داخل resolve_url اگر پارامتری به نام url داده شده باشد ، با استفاده از روش Q (full_url__icontains = url) تنها URL هایی را که حاوی مقدار داده شده هستند ، برگردانید.
فایل کامل shortener/schema.py در اینجا نشان داده شده است:
shorty/shortener/schema.py
import graphene
from graphene_django import DjangoObjectType
from django.db.models import Q

from .models import URL

class URLType(DjangoObjectType):
class Meta:
model = URL

class Query(graphene.ObjectType):
urls = graphene.List(URLType, url=graphene.String())

def resolve_urls(self, info, url=None, **kwargs):
queryset = URL.objects.all()

if url:
_filter = Q(full_url__icontains=url)
queryset = queryset.filter(_filter)

return queryset

class CreateURL(graphene.Mutation):
url = graphene.Field(URLType)

class Arguments:
full_url = graphene.String()

def mutate(self, info, full_url)
url = URL(full_url=full_url)
url.save()

return CreateURL(url=url)

class Mutation(graphene.ObjectType):
create_url = CreateURL.Field()

فایل را ذخیره کنید و ببندید. اگر در حال اجرای سرور مجازی محلی نیستید ، آن را با اجرای python manage.py runserver شروع کنید.
آخرین تغییرات خود را در http: // localhost: 8000 / Graphql آزمایش کنید. در رابط GraphiQL عبارت زیر را بنویسید. این عبارت کلیه آدرس ها با کلمه community را فیلتر می کند:
query {
urls(url:”community”) {
id
fullUrl
urlHash
clicks
createdAt
}
}
خروجی فقط یک ورودی است زیرا شما فقط یک URL را با رشته community  در آن اضافه کرده اید. اگر URL های بیشتری را قبل از آن اضافه کرده باشید ، ممکن است خروجی شما متفاوت باشد.
Output

{
“data”: {
“urls”: [
{
“id”: “1”,
“fullUrl”: “https://www.vpsgol.net/community”,
“urlHash”: “077880af78”,
“clicks”: 1,
“createdAt”: “2020-01-30T19:27:36.243900+00:00”
}
]
}
}

اکنون این امکان را دارید که آدرس های اینترنتی خود را جستجو کنید. با این حال ، با ایجاد پیوندهای فراوان ، ممکن است کلاینت های شما از این که لیست URL ، داده های بیشتری نسبت به ظرفیت برنامه هایشان برمیگرداند، شکایت کنند. برای حل این مسئله ، صفحه بندی را اجرا خواهید کرد.
مرحله 8 – پیاده سازی صفحه بندی
کلاینت هایی که از پشت خط شما استفاده می کنند ممکن است شکایت کنند که زمان پاسخگویی خیلی طول می کشد یا اگر تعداد ورودی های URL بیش از حد زیاد باشد ، شاکی باشند که اندازه آن خیلی بزرگ است. حتی پایگاه داده شما ممکن است برای جمع آوری مجموعه عظیمی از اطلاعات با مشکل مواجه شود. برای حل این مسئله ، می توانید به کلاینت اجازه دهید با استفاده از تکنیکی به نام صفحه بندی ، تعداد موارد مورد نظر خود را در هر درخواست مشخص کند.
هیچ راه پیش فرضی برای اجرای این ویژگی وجود ندارد. حتی در API های REST ، ممکن است آن را در هدرهای HTTP یا پارامترهای پرس و جو ، با نام ها و رفتارهای مختلف مشاهده کنید.
در این برنامه با فعال کردن دو آرگومان دیگر برای جستار URL ، صفحه بندی را پیاده سازی می کنید: first  و skip. first  تعداد متغیر اول عناصر را انتخاب می کند و skip تعداد عناصری را که از ابتدا باید رد شوند، مشخص می کند. به عنوان مثال ، با استفاده از first == 10 و skip == 5 ، 10 URL اول را بدست می آورید ، اما 5 تا از آنها را رد می کنید و 5 مورد باقی مانده را برمیگردانید.
اجرای این راه حل مشابه اضافه کردن فیلتر است.
فایل shortener / schema.py را باز کنید:
⦁ vim shortener/schema.py

در فایل ، کلاس Query را با اضافه کردن دو پارامتر جدید به متغیر url و روش resolve_urls که در کد زیر هایلایت شده است ، تغییر دهید:
shorty/shortener/schema.py
import graphene
from graphene_django import DjangoObjectType
from django.db.models import Q

from .models import URL

class Query(graphene.ObjectType):
urls = graphene.List(URLType, url=graphene.String(), first=graphene.Int(), skip=graphene.Int())

def resolve_urls(self, info, url=None, first=None, skip=None, **kwargs):
queryset = URL.objects.all()

if url:
_filter = Q(full_url__icontains=url)
queryset = queryset.filter(_filter)

if first:
queryset = queryset[:first]

if skip:
queryset = queryset[skip:]

return queryset

این کد از پارامترهای تازه ایجاد شده first  و skip  موجود در روش resolve_urls برای فیلتر کردن پرس و جو از پایگاه داده استفاده میکند.
فایل را ذخیره کنید و ببندید. اگر در حال اجرای سرور مجازی محلی نیستید ، آن را با اجرای python manage.py runserver شروع کنید.
برای آزمایش صفحه بندی ، جستار زیر را در رابط GraphiQL به آدرس http: // localhost: 8000 / Graphql:صادر کنید:
query {
urls(first: 2, skip: 1) {
id
fullUrl
urlHash
clicks
createdAt
}
}

کوتاه کننده URL شما URL دوم ایجاد شده در پایگاه داده شما را برمی گرداند:
Output

{
“data”: {
“urls”: [
{
“id”: “2”,
“fullUrl”: “https://www.vpsgol.net/write-for-donations/”,
“urlHash”: “703562669b”,
“clicks”: 0,
“createdAt”: “2020-01-30T19:31:10.820062+00:00”
}
]
}
}

این نشان می دهد که ویژگی صفحه بندی کار می کند. به راحتی افزودن آدرس های اینترنتی بیشتر و آزمایش مجموعه های مختلف first  و skip را انجام دهید.
نتیجه
تمام اکوسیستم GraphQL هر روز در حال رشد است و جامعه ای فعال در پشت آن وجود دارد. این محصول توسط شرکت هایی مانند GitHub و Facebook به اثبات رسیده است و اکنون می توانید این فناوری را برای پروژه های خود اعمال کنید.
در این آموزش شما با استفاده از مفاهیمی مانند Query و Mutations یک سرویس کوتاه کننده URL با استفاده از GraphQL ، Python و Django ایجاد کرده اید. اما فراتر از آن ، اکنون می دانید که چگونه می توانید با استفاده از چارچوب وب Django به این فناوری ها اعتماد کنید تا بتوانید برنامه های وب ایجاد کنید.
می توانید اطلاعات بیشتری در مورد GraphQL و ابزارهای مورد استفاده در اینجا را در وب سایت GraphQL و وب سایت های مطالب Graphene کسب کنید.

 

 

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

استفاده از nsh برای دستورات از راه دور اوبونتو 18 –  میزبانی وب سایت با Caddy اوبونتو 18

تنظیم سرور ذخیره سازی آبجکت با استفاده از Minio در اوبونتو 18  –  ضبط و اشتراک گذاری ترمینال با Terminalizer اوبونتو

تنظیم مسیریابی شرطی و پاسخگو با React Router v4  –  ایجاد یک URL کوتاه کننده با Django و GraphQL

یک برنامه ردیابی سلامت را با React ،GraphQL و Okta –  ساخت برنامه چت زمان حقیقی React و GraphQL

به روزرسانی فیلترهای مرتب سازی Angular (زاویه ای) –  با استفاده از React ، Superagent و API اینستاگرام

نحوه ساختن یک برنامه جهانی با Nuxt.js و Django –  دکمه دانلود با ریزتعاملات با CSS ، anime.js و segment.js

نحوه اضافه کردن عکسهای پیشرفته در Node و Express  –  با Vue ،GraphQL و Apollo Client یک وبلاگ ساخت

یک برنامه SSR با روتر Preact ، Unistore و Preact بسازید  –  ساخت برنامه های وب پیشرونده با Angular

اشکال زدایی JavaScript در تولید با نقشه های منبع  –  می توان با Koa برنامه “سلام جهانی” ساخت

ساختن یک برنامه با Node ، React ، Okta  –   مدیریت حالت فرم در React با Redux Form

نحوه تنظیم Laravel ، Nginx و MySQL  –  ارتقاء از AngularJS به Angular با ngUpgrade

استفاده از ویژوال استودیو از راه دور  –  احراز هویت API با JSON Web Tokens و Passport

راه اندازی یک پروژه React با Parcel  –  ایجاد Swiper مانند Netflix را در Vue

ساختن یک ربات تلگرام با Laravel و BotMan  –  استفاده از map، filter، و reduce در جاوااسکریپت

چگونه می توان موتور جستجوی زمان واقعی را با Vue  –  ساختن سیستم مستندات (Documentation) با Vue و VuePress

استفاده از اشتراک زنده با کد ویژوال استودیو  –  ساخت یک مقیاس اندازه گیری قدرت رمز عبور را در React

شروع عملی GraphQL با Node.js و Express  –  ساخت یک برنامه آب و هوا در Django

نحوه نصب Discourse روی Ubuntu 18  –  تأیید رمز عبور با استفاده از درخواست فرم Laravel

نحوه نصب MySQL در CentOS 8  –  استفاده از پسوند PDO PHP برای انجام تراکنش MySQL

نصب و پیکربندی SNMP Daemon و Client در Ubuntu 18  –  نصب Linux، Nginx، MariaDB،PHP در Debian 10

 

 

کلمات کلیدی خرید سرور

خرید vps – خرید سرور مجازی – خرید سرور – سرور هلند – فروش vps – سرور مجازی آمریکا – خریدvps – سرور مجازی هلند – فروش سرور مجازی – سرور آمریکا – vps – سرور مجازی انگلیس – سرور مجازی آلمان – سرور مجازی کانادا – خرید vps آمریکا – خرید وی پی اس – سرور – خرید سرور مجازی هلند – vps خرید – سرور مجازی فرانسه – سرور مجازی هلند – خرید vps آمریکاخرید سرور مجازی ارزان هلندvpsخرید vps هلندخرید سرور مجازی آمریکاخرید vps فرانسهتست vpsسرور مجازی تستسرور مجازی ویندوزارزانترین vpsخرید وی پی اسvps ارزان – 


https://vpsgol.net/product/vps-germany/

https://vpsgol.net/product/vps-usa/

https://vpsgol.net/product/vps-france/

https://vpsgol.net/product/vps-canada/

https://vpsgol.net/product/vps-poland/

https://vpsgol.net/product/vps-netherlands/

https://vpsgol.net/product/vps-england/