Tuesday, March 22, 2016

Django | user model redefined



როდესაც მომხმარებელზე მიდგება საქმე და მითუმეტეს, როდესაც მომხმარებელი პროგრამისაა და არა დავუშვათ ხილ-ბოსტანის მაღაზიის, თავის ტკივილი მაშინვე იღვიძებს და ტვინის ჭმაც იწყება. მოკლედ ამ პოსტში მინდა განვიხილო django-ს მომხმარებლის მოდელი და დემონსტრირება გავაკეთო, როგორ შეიძლება ჩვენს მიერ განსაზღვრული მოდელით ჩავანაცვლოთ ის. ასევე მაქვს პატივი წარმოგიდგინთ url-ები, view-ები და ფორმები.

(ღმერთი არს ჩვენთან) ვიწყებთ... :(
მოკლე მიმოხილვა რომ გავაკეთო ჯანგოს აქვს თავისი სტანდართული მომხმარებლის მოდელი, რომელიც მოთავსებულია django.contrib.auth-ში. ველები საკმაოდ პრიმიტიული აქვს, მაგრამ იმ საქმეს ემსახურება რაც საჭიროა:

  • username - ავტორიზაციისთვის საჭირო ველი (ჩემი აზრით, იდიოტობა)
  • first_name
  • last_name
  • email - ჩემს მოდელში მეილს ვიყენებ ავტორიზაციისთვის (ანალოგია ბევრი აქვს)
  • password
  • groups
  • user_permissions
  • is_staff
  • is_active
  • is_superuser
  • last_login
  • date_joined
ველები რომლებიც ბოლდად არის გამოყოფილი, იმის მანიშნებელია, რომ ეს ველები ახალ მოდელშიც უნდა გვქონდეს, რომ ადმინ პანელმა გამართულად იმუშაოს (თუ არ იყენებთ ჯანგოს ადმინ პანელს, მაშინ თამამად მოაშორეთ და ექსეფშენის დროს რაც გინდათ ის გიქნიათ!). ასევე აქვს, "რამდენიმესა" და "ძალიან ბევრს" შორის მდგომი რაოდენობის მეთოდი, რომლებსაც შეგიძლიათ გაეცნოთ ოფიციალურ დოკუმენტაციაში, რომელიც საკმაოდ მომწონს სხვა ფრეიმვორკებთან შედარებით. 

დასაწყისისთვის, პროექტში, რომელშიც არ არის მომხმარებლის ჭაჭანება, შეგვიძლია შევქმნათ ახალი აპლიკაცია სახელად authentication ან auth ან რაც გაგიხარდებათ, მაგრამ გაითვალისწინეთ, დაარქვით "კარგი" სახელი (ეს რჩევა შვილის შემთხვევაში უფრო გამოგადგებათ, აქ შეუცვლით მაინც, ნუ შვილსაც შეუცვლით, მაგრამ ძვირია).


არ ვფიქრობ, რომ რახან ამ პოსტს კითხულობთ ჯანგოს პროფესიონალი მოთამაშეები ხართ, მაგრამ მგონია, რომ უნდა იცოდეთ როგორ უნდა შექმნათ ახალი აპლიკაცია და ამიტომ, არ ვაპირებ ამის აქ დაწერას. მოკლედ შევქმენით ახალი აპლიკაცია სახელით authentication (ჩემს შემთხვევაში). სანამ ყველაფერს ავამუშავებდეთ, უნდა დავიწყოთ იმით, რომ განვსაზღვროთ urls.py-ში ჩვენი მისამართები, აუთენტიპიკაციისთვის, დეაუთენტიპიკაციისთვის (ახალი სიტყვა) და რეგისტრაციისთვის და ბოლოს მეილით გააქტიურებისთვის (ამ ბოლოს არ ვიცი ახლა მოვასწრებ თუ არა ამ პოსტში, მაგრამ ოდესღაც, ამ იმედით შეინახეთ ამ პოსტის ლინკი, ეს ფუნქციაც აქ იქნება.

მოკლე აღწერა, რომ გავაკეთო, რა ხდება. როგორც ბევრი მიხვდებოდა (იმედია) ვიყენებ class based view-ებს და ამიტომ აქვე მაქვს გამოყენებული login_required დეკორატორი (იდეაში, როგორც დეკორატორს ისე მაინც ვერ ვიყენებ, მაგრამ ჰქვია დეკორატორი - დაე იყოს დეკორატორი). ბევრი ძებნის შემდეგ ყველაზე კარგ გზად ამ დეკორატორის აქ გამოყენება მიმაჩნია. დასაწყისში გვაქვს იმპორტები, და შემდეგ მისამართის ნიმუშები (patterns), რომლებიც იყენებს ჯანგოს class based view-ს as_view() მეთოდს. სახელებიც, ვფიქრობ რელევანტურია.

დავიწყე მისამართებით, რადგან ყველაზე პატარა რამაა რაც არის საჭიროა და წინ გადადგმულ ნაბიჯადაც ითვლება. ამის შემდეგ მოდი გავაგრძელებ მოდელით (ებით). სანამ კოდს ჩავამატებ, მანამდე მინდა მოსამზადებელი რიტორიკა. 


-რა არის ჩვენი მოდელი თუ არა მომხმარებელი?1
-არაფერი!
(დიალოგის ნაწყვეტი სერიიდან "საუბრები საკუთარ მესთან")

მოკლედ როდესაც ვსაუბრობდი ჯანგოს ჩაშენებულ მოდელზე უნდა აღმენიშნა, რომ მოდელის მშობელი არის AbstractBaseUser, რომელიც ცხოვრობს (ვიღაცისგან გავიგე ამ კონტექსტში და საკმაოდ სახალისოა გამოთქმა - ცხოვრობს) django.contrib.auth.models-ში, ისევე როგორც BaseUserManager, რომელიც უნდა გამოვიყენო მომხმარებლის მოდელის მენეჯერის შესაქმნელად.

- მათთვის ვინც არ იცის რა არის მენეჯერი ჯანგოს მოდელისთვის -> მენეჯერი არის მონაცემთა ბაზის ინტერფეისი (უხეში ნათქვამია), რომლის დახმარებითაც ვანხორციელებთ მოდელის queries (არ ვიცი ქართული შესიტყვება). Django managers doc.

ჩემი მენეჯერის კლასის სახელია AccountManager, რომელიც პირდაპირი მემკვიდრეა BaseUserManager-ის. ამ მენეჯერში მჭირდებოდა ორი მეთოდის გადაფარვა (override):

  1. create_user( ... ), რომელიც პასუხს აგებს ახალი მომხმარებლის შექმნაზე
  2. create_superuser( ... ), რომელიც ასევე აგებს პასუხს რაღაცაზე და ეს რაღაცა ადმინისტრატორის შექმნაა (super user)
ამ ორ მეთოდს შორის განსხვავება ის არის, რომ ადმინისტრატორის შექმნის დროს ვნიშნავ ორ ველს როგორც აქტიურს (True) და ვიყენებ უბრალოდ create_user მეთოდს. ხოლო create_user მეთოდი ქმნის ახალ მომხმარებელს, მას შემდეგ რაც შემოსული ინფორმაცია გადის პრიმიტიულ შემოწმებას.

ამის შემდეგ უკვე მოდის Account მოდელი, რომელიც მემკვიდრეა AbstractBaseUser-ის. შემდეგი ველები მოხვდნენ Account მოდელის ველთა სიაში
  • email
  • firstname
  • lastname
  • sex
  • age
  • status
ეს ველები რა თქმა უნდა არ არის აუცილებელი და არის უბრალო გემოვნების ამბავი, ვის რა უნდა, რომ თავის მომხმარებელს ჰქონდეს. ასევე მაქვს სურათის მოდელთან ურთიერთობა, მაგრამ აქ არ გვინდა, რადგან საქმე არ უნდა გართულდეს. ამის შემდეგ უკვე მოდის ის ველები, რომლებმაც გამაწამეს, რადგან, როგორც ჩანს ისინი აუცილებელია მომხმარებლის მოდელში 
  • is_staff
  • is_active
  • is_admin
  • created_at
  • updated_at
ამის შემდეგ ვნიშნავთ მოდელის მენეჯერად ჩემს მიერ განსაზღვრულ AccountManager-ს, ვუთითებთ აუთენტიფიკაციისთვის საჭირო ველს - email (ან რომელიც გინდათ, მაინტერესებდა პაროლი რომ მივუთითოთ ნეტა რა მოხდება - კარგი არაფერი, ალბად), და მოთხოვნად ველებს, რომელბიც არიან სახელი და გვარი. დამატებით გვაქვს მეთოდები, რომელთა დანიშნულებაც სავსებით გასაგები უნდა იყოს. ეს ყველა მეთოდი საჭიროა და გამოიწვევს უთანხმოებას ჯანგოსთან თუ არ იქნება განსაზღვრული :(.


რადგან უკვე მოდელი გვაქვს შეგვიძლია ფორმაც ვიქონიოთ სიმარტივისთვის. ნუ ფორმის განსაზღვრაც არ წარმოადგენს პრობლემას და ჩემს შემთხვევაში საკმაოდ დეტალურადააა ველები აღწერილი, რადგან საჭიროება მოითხოვდა ამას. თქვენც იგივე შეგიძლიათ გააკეთოთ / დარჩეთ "მარტივი". სანამ კოდს ჩავსვავ აქაც გავიაროთ მოთელვა.

მოკლედ მაქვს ModelForm-ის მემკვიდრე ფორმა AccountForm, რომელშიც სათითაოდ არის განსაზღვრული ველები (დაწვრილებით). ერთი რომ ავიღოთ, გვაქვს widget, რომელიც შეგვიძლია აღვიქვათ html-ის ინსტრუქტორად, რომელიც უთითებს თუ რა ტიპის input უნდა იქნას ველის რენდერის დროს გამოყენებული. ვიჯეტს აქვს attrs, რომელიც ჩემს შემთხვევაში ამ input-ს უთითებს, რომ მას ექნება კლასი 'form-control' და იქნება მოთხოვნადი. ამის შემდეგ გვაქვს იარლიყი, რომელიც უნდა გამოჩნდეს input-მდე, და მიაწოდოს მომხმარებელს დანიშნულება თუ რა უნდა შეიყვანოს ველში. ყველა ველი თითქმის იმავე ხელწერას მიჰყვება.

ახლა კი დადგა დრო მივხედოთ view-ებს, რომლებშიც ჩადებულია მთელი ლოგიკა, თუ როგორ უნდა დარეგისტრირდეს, შემოვიდეს/გავიდეს, მომხმარებელი. მაგრამ იცით რა, ჩემი აზრით არ არის ჩადებული აქ არავითარი ლოგიკა, ჩვენს მიერ მაინც, რადგან ეს ყველაფერი ისეთ დონეზეა ავტომატიზირებული (ჯანგოში), რომ რაღაც ზე კომპლექსური დავალება თუ არ არის გასაკეთებელი, მსგავსი სცენარის გაკეთება საკმაოდ მარტივია class-based view-ების გამოყენებით. სიმართლე გითხრათ ამ view-ების გადაკეთება მომიწია, რადგან უკვე არსებულ აპლიკაციაში საკმაოდ ბევრი  რამე მაქვს დამატებული და გადაკეთებისას შეიძლება რაიმე შეცდომა გამპარვოდა, ამიტომ თუ თქვენც მიიღებთ ცუდ შედეგს, მაშინ შემატყობინეთ.

კიდევ ერთი მოკლე აღწერა, სანამ კოდს დავდებდე. აღწერამდე კი კიდევ ერთი დეტალი. თუ გვინდა, რომ ეს მოდული გამოჩნდეს ადმინისტრირების გვერდზე, მაშინ admin.py ფაილში უნდა შევიტანოთ შემდეგი ცვლილებები.

  1. დავაიმპორტოთ admin-ი django.contrib-დან
  2. დავაიმპორტოთ ყველა ის მოდელი, რომელიც გვურს, რომ გამოჩნდეს ადმინში (მხოლოდ ამ აპლიკაციის მოდელები)
  3. თითოეული მოდელისთვის გავიმეოროთ admin.site.register( modelName)
ახლა კი გადავიდეთ view-ებზე. აქ ძალიან ბევრი იმპორტი მაქვს გაკეთებული და ამიტომ ყურადღებას ნუ მიაქცევთ, და გამოიყენეთ მხოლოდ ისინი, რომელიც საჭიროა. HomeView-საკმაოდ მარტივი template view-ა, და ცოტა დატვირთულიც უნდა იყოს ინფორმაციით, რადგან ეს არის homepage-ი მომხმარებლისთვის. 

ამის შემდეგ გვაქვს SigninView, რომელიც არის ასევე TemplateView-ს მემკვიდრე. აქ არ არის მოცემული ცხადად ფორმა, რადგან უბრალოდ ორი ველია შესავსები: ელ.ფოსტა და პაროლი, რაც ხელით მაქვს მითითებული, მაგრამ თუ გსურთ ფორმა შექმნათ, მაშინ არც ეგ იქნება პრობლემა. get და post მეთოდები შესაბამისად არის განსაზღვრული. get-ში ისეთი არაფერია მოცემული, რომ ჯილდო მივიღო. post-ში კი მეტნაკლებად საინტერესო რამ ხდება. აქ "ხელით" ვიღებ ელ.ფოსტასა და პაროლს და ვცდილობ მოვძებნო მომხმარებელი და გავატარო აუთენტიპიკაცია. თუ ყველაფერი კარგად დამთავრდა authenticate მეთოდის გამოყენების შემდეგ, უკვე ხდება login ფუნქციის გამოძახება. თუ რაიმე ექსეფშენი დავიჭირეთ: მომხმარებელი ვერ მოიძებნა/ვერ გადის აუთენტიპიკაციას, მაშინ კონტექსტური ცვლადით ვატყობინებთ ამას ჩვენს პოტენციურ მომხმარებელს. 

SignUpView ალბათ ყველაზე საინტერესოა ამ view-ებს შორის. აქ ხდება მომხმარებლის რეგისტრაცია და მოდელის ობიექტის შექმნა, სწორედ ამიტომ ეს view არის CreateView-ს შთამომავალი. აქ ვუთითებთ model, form_class-სა და response_class-ს. თუ შევსებული ფორმა ვალიდურია, მაშინ get_success_url ის გამოძახებით მომხმარებელი გადამისამართდება სხვა მისამართზე (ჩემს შემთხვევაში, მაქვს საერთო აპლიკაცია, თქვენ შეგიძლიათ მიუთითოთ ნებისმიერი). იმ შემთხვევაში თუ ფორმა არ არის ვალიდური, ფორმა დაუბრუნდება უკან მომხმარებელს შესაბამისი შეცდომებით. ასევე გადაფარული მაქვს render_to_response მეთოდიც, რომელიც (როგორც მახსოვს) იმიტომ დამჭირდა, რომ შეცდომები სწორად გამოეტანა ფორმაში. 

და, ბოლოს, SignoutView, რომელიც არს RedirectView-ს ღირსეული შთამომავალი. რომელშიც მაქვს მხოლოდ get მეთოდი და ვიყენებ logout ფუნქციას (ჯანგოს ფუნქცია). 



ბოლოს არის აქტივაციის კლასიც, მაგრამ ამ ეტაპზე იყოს ისე როგორც არის :).

ამ ყველაფრის შემდეგ გაგიკვირდებათ და კიდევ რამდენიმე ეტაპია მოსაგვარებელი.  Settings.py ფაილი, რომელიც მოთავსებული პროექტის მთავარი აპლიკაციის ფოლდერში უნდა ჩავამატოთ ჩვენი ახალი აპლიკაცია (აუთენტიფიკაციისთვის). და მივუთითოთ
AUTH_USER_MODEL = 'authentication.Account'
LOGIN_URL = 'auth/signin/'
სადაც authentication არის აპლიკაციის სახელი, ხოლო Account მოდელის სახელი. ასევე შესვლის მისამართიც მისათითებელია, აქ შეიძლება reverse ფუნქციის გამოყენება (მე ხელით მაქვს მითითებული). ასევე განსასაზღვრია urls.py ფაილში, რომელიც იმავე ფოლდერშია, სადაც settings.py, ჩვენი აპლიკაციის სახელსივრცე და მისამართი (ჩემს შემთხვევაში სახელსივრცე (namespace) არის 'auth').

საბოლოოდ იმ შემთხვევაში თუ რაიმემ არ იმუშავა (იხ.სურათი)

მოკლედ თუ რამემ არ იმუშავა ჯობს კომენტარების სახით დააფიქსიროთ თქვენი აზრი, დაგეხმარებით და მეც გავასწორე შეცდომებს (თუ რამე გამეპარა), რადგან ეს ყველაფერი მუშაობს რეალურ აპლიკაციაში (აქ დადებული ვერსია სერიოზულად არის გადაკეთებული === შემცირებული). 

No comments:

Post a Comment