oruji.github.io
oruji.github.ioPersian Tutorials
ویرایش: 1396/11/13 19:21
A A

آموزش یکپارچه سازی برنامه ها و دیتابیس های Legacy در جنگو (Django)

جنگو مناسب ترین برای به اصطلاح توسعه ی green-field می باشد – بدین معنی که، شروع پروژه های از ابتدا، مثل این که شما یک ساختمان در یک دشت از علف سبز ساخته اید. ولی با وجود این واقعیت که جنگو (Django) از پروژه های از ابتدا طرفداری می کند، یکپارچه سازی فریم ورک یا چارچوب به پایگاه داده ها و برنامه های legacy ممکن است. این آموزش از کتاب، تعدادی از استراتژی های یکپارچه سازی را توضیح می دهد.

یکپارچه سازی با یک پایگاه داده ی Legacy

لایه ی پایگاه داده ی جنگو الگوی SQL را از کد پایتون تولید می کند – ولی با یک پایگاه داده ی legacy، شما قبلا دارای الگوی SQL می باشید. در چنین مواردی، نیاز به ساخت مدل ها برای جداول پایگاه داده موجود خواهید بود. برای این هدف، جنگو با یک ابزاری که می تواند کد مدل را توسط خواندن لایه های جدول پایگاه داده تولید کند ارائه کرده است. این ابزار inspectdb نامیده می شود، و می توان توسط اجرای دستور manage.py inspectdb آن را فراخوانی کرد.

استفاده از inspectdb

مزیت inspectdb پایگاه داده ی اشاره شده توسط فایل تنظیمات درون گرایی می کند، هر نمایش مدل جنگو را برای هر جدول شما تعیین می کند، و کد مدل پایتون به خروجی استاندارد پرینت می کند.

در زیر دستور عمل یکپارچه سازی پردازش از ابتدا وجود دارد. تنها فرض این است که جنگو نصب شده و شما یک پایگاه داده ی legacy دارید.

  1. یک پروژه ی جنگو را توسط اجرای دستور django‑admin startproject mysite (جایی که mysite نام پروژه ی شما می باشد) ایجاد کنید. ما در این مثال از mysite برای نام پروژه استفاده خواهیم کرد.
  2. فایل تنظیمات در آن پروژه یعنی mysite/settings.py را برای تنظیم پارامترهای کانکشن پایگاه داده و نام پایگاه داده ویرایش کنید. به طور خاص، تنظیمات DATABASE_NAME، DATABASE_ENGINE، DATABASE_USER، DATABASE_PASSWORD، DATABASE_HOST و DATABASE_PORT را آماده کنید. (توجه داشته باشید که برخی از این تنظیمات اختیاری می باشند، برای اطلاعات بیشتر به آموزش مدل جنگو مراجعه کنید.)
  3. توسط اجرای دستور python mysite/manage.py startapp myapp یک برنامه ی جنگو درون پروژه خود ایجاد کنید (جایی که myapp نام برنامه ی شما می باشد). ما در اینجا از myapp به صورت نام برنامه استفاده خواهیم کرد.
  4. دستور python mysite/manage.py inspectdb را اجرا کنید. این دستور جداول درون پایگاه داده ی DATABASE_NAME را بازرسی کرده و کلاس مدل تولید شده برای هر جدول را پرینت می کند. برای دریافت آگاهی از آنچه که inspectdb می تواند انجام دهد نگاهی به خروجی بیاندازید.
  5. خروجی را درون فایل models.py درون برنامه خود، با استفاده از تغییر مسیر خروجی استاندارد shell ذخیره کنید.python mysite/manage.py inspectdb > mysite/myapp/models.py
  6. فایل mysite/myapp/models.py برای تمیز کردن مدل های تولید شده و در صورت لزوم سفارشی سازی ویرایش کنید. برخی اشاره ها برای این موضوع را در بخش آینده توضیح داده ایم.

تمیز کردن مدل های تولید شده

همانطور که ممکن است انتظار داشته باشید، درون گرایی پایگاه داده عالی نمی باشد، و نیاز خواهید داشت برخی پاکسازی های سبک در کد مدل نتیجه شده انجام دهید. در زیر تعدادی اشاره کننده ها برای سر و کار داشتن با مدل های تولید شده وجود دارند:

  1. هر جدول پایگاه داده به یک کلاس مدل تبدیل می شود (مثلا، یک رابطه ی یک به یک بین جداول پایگاه داده و کلاس های مدل وجود دارد). این بدین معناست که نیاز خواهید داشت مدل ها را برای هر کدام از جداول join چند به چند به شیء های ManyToManyField تغییر دهید.
  2. هر مدل تولید شده دارای یک attribute برای هر فیلد می باشد، شامل id فیلدهای کلید اصلی. هر چند، فراخوانی دوباره ی آن جنگو در صورتی که یک مدل دارای یک کلید اصلی نباشد، به طور خودکار یک فیلد id کلید اصلی اضافه می کند. در نتیجه، هر خطی که شبیه به زیر باشد را حذف خواهید نمود:id = models.IntegerField(primary_key=True)

    نه تنها این خط ها اضافی می باشند، بلکه می توانند در صورتی که برنامه شما بخواهد رکوردهای جدیدی به جدول ها اضافه کند موجب بروز مشکلاتی می شود.

  3. هر نوع فیلد (مانند، CharField، DateField) توسط نگاه به نوع ستون پایگاه داده (مانند VARCHAR، DATE) تعیین شده است. در صورتی که inspectdb نتواند نوع ستون را به یک نوع فیلد مدل ارتباط دهد، از TextField استفاده خواهد کرد و کامنت پایتون 'This field type is a guess' در کنار فیلد در مدل توضیح داده شده درج می کند. با دقت به آن نگاه کنید، و بنابراین در صورت لزوم نوع فیلد را تغییر دهید.

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

  4. در صورتی که یک نام ستون پایگاه داده یک کلمه ی رزرو شده ی پایتون باشد (از قبیل page، class یا for)، inspectdb، '_field' را به نام attribute اضافه کرده و attribute، db_column را به نام فیلد واقعی قرار می دهد (مانند، pass، class یا for).

    برای مثال، در صورتی که یک جدول دارای یک ستون INT با نام for باشد، مدل تولید شده دارای یک فیلد شبیه به زیر خواهد بود:

    for_field = models.IntegerField(db_column='for')

    inspectdb کامنت پایتون زیر را در کنار فیلد درج خواهد کرد 'Field renamed because it was a Python reserved world.'.

  5. در صورتی که پایگاه داده ی شما حاوی جداولی باشد که به جدول های دیگر رجوع می کند (همانطور که اغلب پایگاه های داده انجام می دهند)، ممکن است نیاز باشد ترتیب مدل های تولید شده را دوباره چیدمان کنید، به طوری که مدل هایی که به مدل های دیگر رجوع می کنند به درستی منظم شوند. برای مثال، در صورتی که مدل Book دارای یک ForeignKey به مدل Author باشد، مدل Author باید قبل از مدل Book تعریف شده باشد. در صورتی که نیاز به ساخت یک رابطه در یک مدلی که هنوز تعریف نشده می باشید، می توانید از یک رشته حاوی نام مدل به جای خود شیء مدل استفاده کنید.
  6. inspectdb برای PostgreSQL، MySQL و SQLite کلیدهای اصلی را شناسایی می کند. این بدین معناست که، inspectdb برای حداقل یک فیلد در هر مدل primary_key=True درج می کند، زیرا مدل های ملزم به داشتن یک فیلد primary_key=True می باشند.
  7. شناسایی Foreign-key تنها با PostgreSQL و با بعضی نوع از جدول های MySQL کار می کند. در بقیه ی موارد، فیلدهای foreign-key به صورت در دست تالیف/ترجمه.

یکپارچه سازی با یک سیستم Authentication

امکان یکپارچه سازی فریم ورک یا چارچوب جنگو با یک سیستم authentication موجود امکان پذیر است – منبع دیگر نام های کاربری و رمزهای عبور یا متدهای authentication.

برای مثال، شرکت شما ممکن است قبلا دارای یک راه اندازی LDAP باشد که یک نام کاربری و رمز عبور را برای هر کارمند ذخیره می کند. در صورتی که کاربران دارای حساب های جدا در LDAP و برنامه های بر اساس جنگو باشند، این برای هر دوی مدیر شبکه و خود کاربران عذاب خواهد بود.

جهت کنترل وضعیت شبیه به این، سیستم authentication اجازه می دهد منابع دیگر authentication را وصل کنید. می توان الگوی پایگاه داده محور پیشفرض جنگو را override کرد، یا می توان از سیستم پیشفرض جفت با سیستم های دیگر استفاده کرد.

تعیین Authentication Backend ها

در پشت صحنه، فریم ورک یا چارچوب جنگو یک لیست از "authentication backend" ها نگه داشته است که authentication را بررسی می کند. هنگامی که شخصی django.contrib.auth.authenticate() را فراخوانی می کند (همانظور که در بخش کاربران عضویت و session توضیح داده شد)، جنگو سعی می کند تمام authentication backend ها را تصدیق کند. در صورتی که اولین متد authentication شکست بخورد، جنگو برای دومی تلاش می کند، و به همین ترتیب پیش می رود، تا تمام backend ها امتحان شوند.

لیست authentication backend ها درون تنظیم AUTHENTICATON_BAKCENDS جهت استفاده تعیین شده اند. این تنظیم یک تاپل از مسیر نام های پایتون می باشد که به کلاس های پایتونی که می دانند چطور تصدیق کنند اشاره می کند. این کلاس ها می توانند هرجایی از مسیر پایتون شما باشند.

به طور پیشفرض، AUTHENTICATION_BACKENDS مانند زیر قرار گرفته است:

('django.contrib.auth.backends.ModelBackend',)

کد فوق اصول پایه ای الگوی authentication می باشد که پایگاه داده ی کاربران جنگو را بررسی می کند.

موضوع نحوه ی ترتیب AUTHENTICATION_BACKENDS اهمیت دارد، بنابراین درصورتی که نام کاربری و رمز عبور همسان در چند backend معتبر باشد، جنگو پردازش را در اولین تطابق مثبت متوقف خواهد کرد.

نوشتن یک Authentication Backend

authentication backend یک کلاس است که دو متد را اجرا می کند: get_user(id) و authentication(**credentials).

متد get_user یک id در یافت می کند – که می تواند یک نام کاربری، id پایگاه داده یا هر چیز دیگری باشد – و یک شیء User بر می گرداند.

متد authenticate، credential هایی را به صورت آرگومان های کیورد دریافت می کند. اغلب اوقات چیزی شبیه به کد زیر می باشد:

class MyBackend(object): def authenticate(self, username=None, password=None): # Check the username/password and return a User.

ولی همچنین می تواند یک token را تصدیق کند، مانند زیر:

class MyBackend(object): def authenticate(self, token=None): # Check the token and return a User.

در هر صورت، authenticate باید credential هایی را که دریافت می کند را بررسی کند، و باید یک شیء User مطابق با آن credential ها می باشد بر گرداند، در صورتی که credential ها معتبر باشند. در صورتی که معتبر نباشند، باید مقدار None را بر گرداند.

سیستم مدیر جنگو به طور محکم همراه شیء User، database-backend خود جنگو می باشد که در بخش کاربران عضویت و session مورد توضیح داده شده است. بهترین روش برای سر و کار داشتن با این موضوع ساختن یک شیء User برای هر کاربر می باشد که برای backend شما وجود دارد (مثلا، درون دایرکتوری LDAP، پایگاه داده ی SQL خارجی شما). همچنین می توان یک اسکریپت برای انجام این موضوع پیشاپیش نوشت یا متد authenticate شما می تواند اولین باری که یک کاربر وارد میشود آن را انجام دهد.

در زیر یک مثال backend وجود دارد که یک متغیر نام کاربری و رمز عبور تعریف شده در فایل settings.py را تصدیق کرده و اولین بار که یک کاربر تصدیق می شود یک شیء User ایجاد می کند:

from django.conf import settings from django.contrib.auth.models import User, check_password class SettingsBackend(object): """ Authenticate against the settings ADMIN_LOGIN and ADMIN_PASSWORD. Use the login name, and a hash of the password. For example: ADMIN_LOGIN = 'admin' ADMIN_PASSWORD = 'sha1$4e987$afbcf42e21bd417fb71db8c66b321e9fc33051de' """ def authenticate(self, username=None, password=None): login_valid = (settings.ADMIN_LOGIN == username) pwd_valid = check_password(password, settings.ADMIN_PASSWORD) if login_valid and pwd_valid: try: user = User.objects.get(username=username) except User.DoesNotExist: # Create a new user. Note that we can set password # to anything, because it won't be checked; the password # from settings.py will. user = User(username=username, password='get from settings.py') user.is_staff = True user.is_superuser = True user.save() return user return None def get_user(self, user_id): try: return User.objects.get(pk=user_id) except User.DoesNotExist: return None

برای اطلاعات بیشتر در مورد authentication backend ها، مستندات رسمی جنگو را مشاهده کنید.

یکپارچه سازی با برنامه های وب legacy

این امکان وجود دارد که یک برنامه ی جنگو در وب سرور همسان را که به صورت یک برنامه ایجاد شده توسط تکنولوژی دیگر می باشد را اجرا کنید. ساده ترین روش برای انجام این کار استفاده از فایل configuration آپاچی یعنی httpd.conf جهت محول کردن الگوهای URL دیگر به تکنولوژی های دیگر می باشد.

کلید این که جنگو (Django) برای یک الگوی URL خاص تنها در صورتی که فایل httpd.con چنین می گوید فعال شده خواهد بود. گسترش پیشفرض فرض می کند می خواهید ایجاد هر صفحه را در دامنه ی خاص انجام دهید:

<Location "/"> SetHandler python-program PythonHandler django.core.handlers.modpython SetEnv DJANGO_SETTINGS_MODULE mysite.settings PythonDebug On </Location>

در اینجا، خط <location "/"> بدین معنی است که "هر URL، در root شروع شود،" با جنگو.

محدود کردن این دایرکتیو <location> برای بعضی دایرکتوری ها کاملا خوب می باشد. برای مثال، تصور کنید شما یک برنامه ی legacy PHP دارید که اغلب صحات در یک دامنه ایجاد شده اند و می خواهید یک سایت مدیر جنگو در /admin/ بدون مزاحمت برای کد PHP ایجاد کنید. برای انجام این کار، تنها کافیست دایرکتیو <location> را با /admin/ تنظیم کنید:

<Location "/admin/"> SetHandler python-program PythonHandler django.core.handlers.modpython SetEnv DJANGO_SETTINGS_MODULE mysite.settings PythonDebug On </Location>

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

توجه داشته باشید که پیوستن جنگو به URL واجد شرایط (از قبیل /admin/ در مثال این بخش) تاثیری بر روی URL تجزیه شده ی جنگو نمی گذارد. جنگو با URL مستقل خود کار می کند (مانند، /admin/people/person/add/)، نه یک نسخه ی "محروم" از URL (مانند، /people/person/add/). این بدین معنی است که URLconf ریشه باید شامل /admin/ آغازین باشد.