Blog

  • Як стати Software Engineer: моя історія

    Як стати Software Engineer: моя історія

    Для кого ця стаття?

    Для таких як я сам, хто в часи пандемії та суттєвої трансформації життя, вирішив змінити професію.

    Досвід

    Я — Сергій Купрієнко, зараз працюю Junior Software Engineer у великій аутсорсінговій компанії. До цього мав досвід у різних сферах: займався продажами, видавничою діяльністю, робив переклади, був редактором енциклопедії, науковцем-істориком, екскурсоводом, ученим секретарем музею. Захистив кандидатську дисертацію по історії інків та отримав науковий ступень PhD. Часто все це було паралельно, оскільки одночасно навчався та працював на 2-3 роботах.

    Хобі

    Хотів би згадати про свої хобі: історія, література (художня, нон-фікшн, наукова), переклади з іспанської мови, ведення блогу. На ентузіазмі я видав більше 10 книжок із перекладами джерел по історії Доколумбової Америки, а це, гадаю, більше, ніж було зроблено за 100 років до того. Маючи якесь хобі, як правило, згодом я отримував роботу, пов’язану з ним.

    Я мало був пов’язаний з IT-сферою напряму, аж поки не увійшов до команди Великої української енциклопедії, яка розробляла першу універсальну українську енциклопедію. Я був куратором розробки її онлайн-порталу, тобто, фактично, Project-Manager’ом, і разом із командою ми запустили у 2019 році.

    Switch

    А тепер розкажу про те, як я здійснив свійswitchіз науковця-історика в Software Engineer. В цілому, весь процес зайняв 1 рік 😊.

    Рішення про зміну професії я прийняв, порадившись із дружиною, в січні 2020 року, оскільки побачив перспективи розвитку та попит на IT-спеціалістів. Вона сказала, що варто спробувати. Це звучало фантастично, бо я не знав достеменно, що вивчати, скільки це займе часу і через що доведеться проходити. На той момент я працював у музеї на адміністративній посаді. 

    Чому я думав, що це реально? Бо на той час я опанував кілька корисних методик, які суттєво прискорювали процес самонавчання плюс інтерес до навчання, складних задач, віра, що все можливе, та інтерес до комп’ютерної сфери. 

    Методики

    Перша методика —швидкочитанняза допомогою технології Text-to-Speech. Для того, щоб нею скористатися, потрібно лише мати смартфон з Android, додаток PocketBook. В додатку треба включити аудіо режим Text-to-Speech, але на швидкості 2Х, тобто в два рази швидше звичайної вимови. І тоді будь-яку книгу можна прочитати дуже швидко. Ось моя публікація з цього приводу. Загалом, за 2018-2019 роки я прочитав більше 700 книг найрізноманітнішої тематики.

    Друга методика — швидкоперегляд. Усі навчальні відео я так само переглядав на швидкості 2Х. Гадаю, в майбутньому всі діти будуть навчатися, читаючи та переглядаючи відео зі швидкістю 2Х. 

    Python

    Коли задумався, яку мову програмування вивчати, то я вирішив обрати Python, як найпростішу для розуміння і найпоширенішу у викладанні. В березні 2020 побачив знижку на курси Data Science/Data Analytics відDatacamp, а підписка за $100 на рік – це крута інвестиція, то не вагаючись її купив. Далі подумав, як спланувати навчання і тут натрапив на сайт від компанії Epam, де можна було детально прописати всі можливі цілі, яких потрібно досягнути для рівня Junior. У мене було бажання стати Data Analyst. Під це і сформував свій план розвитку. Хоча в подальшому я і змінив своє ставлення до цієї цілі. Тож не варто цементувати в бетоні речі, доцільно бути гнучким до вимог ринку, роботодавця або клієнтів.

    Звідси, мої поради для таких, як я: потрібно поставити ціль; визначити конкретні кроки для її досягнення; бути готовим змінювати ціль, якщо вона застаріла.

    Закладки

    Також я мав за гарну звичку додавати будь-який цікавий сайт в закладки свого браузера Chrome. Пізніше з цих закладок я зробив репозиторій на GitHub, де розподілив посилання на сайти по категоріях. Паралельно я перечитав сотні статей про Python наMedium.com— і, скажу, що це один із найкращих ресурсів для розробників. Загалом за рік я переглянув чи перечитав більше 1500 статей по Python.

    Поради: зберігайте важливі сайти в закладках; структуруйте за темами.

    Paternity leave

    Звідки у мене було стільки вільного часу на все це? Доволі просто — я перебував уpaternity leaveзі своїм малятком. І скажу, що це був найкращий час у моєму житті, сповнений барвистими емоціями і новими враженнями. Власне, необтяжений якоюсь іншою роботою, я зміг себе присвятити батьківству та навчанню.

    Резюме та тестові завдання

    Поки тривало навчання, я робив мало своїх проектів. І це було найбільшою помилкою. Усвідомив я це лише в літку 2020 року. Тоді я почав надсилати свої перші резюме й отримувати перші відгуки. А це було неабияким випробуванням, адже майже усюди для новачків обов’язкова умова — виконати тестове завдання. Більшість тестових завдань були міні-проектами, частина – алгоритмічні задачки. Іноді ламав голову по три-чотири дні. Часто не міг вирішити одне чи два завдання з переліку в три-п’ять пунктів. На тиждень міг опустити руки. Але потім почав розуміти поразки як стимул поліпшити свої знання та навички. І все це давало змогу вивчити невідомі раніше теми.

    Поради: починайте робити власні проекти якомога раніше; продовжувати йти незважаючи на поразки, бо саме поразки вас загартовують.

    Перші проекти на Python

    В основному підтягував знання по напрямку Software Engineer наLinkedIn Learning, де зібрано чудові високоякісні курси по будь-якій мові програмування (підписка на перший рік коштувала 27 Євро). Я, мабуть, переглянув та протестував сотні цих курсів на різні теми по Python, Data Science, Machine Learning, NLP, Django та Flask.

    Саме веб-фреймворки Django і Flask мене зацікавили найбільше. І коли почав ними займатися, то відчув, що це і є ті речі, з яких можна зробити реальні пет-проекти, які можна вказувати в резюме. 

    Прокачайте свій Github-профіль

    Але перші реальні пропозиції роботи почали надходити лише в грудні 2020, і то лише тому, що я завів акаунт на GitHub зі своїми проектами і паралельно розміщував цікаві тематичні статті на своєму сайті.

    Вважаю, що чим більше ви як Software Engineer урізноманітните свій GitHub-профіль та резюме, тим більше шансів у вас буде отримати першу роботу в IT. Ось який профіль я зробив собі.

    До речі, на замітку рекрутерам, саме через такий тематичний пошук мене знайшла рекрутерка і запропонувала тему, яка цікавила мене і яка потрібна була замовнику. Тобто win-win ситуація. 

    Поради: розміщуйте власні пет-проекти на github, вказуйте їх у резюме.

    Прокачайте свій LinkedIn-профіль

    Паралельно, раджу прокачати свій профіль в LinkedIn, бо саме звідти часто надходять пропозиції від рекрутерів. Для цього я скористався особистими порадами Юлії Шишенко та її статтею. А також додав у друзі більше 2000 людей (HR, рекрутерів, Python-розробників, Data Scientist’ів і т.п.). Також створіть профіль на Djinni (https://djinni.co/), але новачкам отримати офер там може бути тривалим випробуванням, хоча як не дивно, саме там я отримав перший дивний офер.

    Поради: оптимізуйте профіль у LinkedIn, адже саме там вас будуть шукати рекрутери.

    Перший офер

    Найцікавіше почалося, коли мені запропонували перший офер у листопаді 2020 року…

    Але трохи передісторії 😊 

    Перша спроба потрапити в IT-компанію була доволі дивна. В листопаді 2020 року після інтерв’ю та тестового завдання на логіку я отримав офер на посаду Technical Customer Support від продуктової компанії. Мені здавалося, що так я зможу потрапити в IT, але не з парадного входу. Тим більше ризиковано для мене було, тому що основний стек у компанії був PHP. Домовилися, що я вийду на роботу 1 грудня. Коли я прийшов, то мені виділили комп’ютер з усіма налаштуваннями та доступом до HelpDesk. Я почав читати документацію. Та вже в перший день мені дали опрацьовувати перші запити від клієнтів. Оскільки не все було зрозуміло, то я почав радитись у свого менеджера, але на всі мої запитання була одна відповідь (усно або в чатах): “Ти маєш сам все вирішити та зрозуміти”. Це було дивно чути. На наступний день було те саме, але ще й комп’ютер почав самовільно перезавантажуватися разів чотири чи п’ять, після чого постійно доводилося наново все запускати і це нервувало. Та вже по обіді стало зрозуміло, що ніякої підтримки я не отримаю, мов, “розбирайся сам”, і я вирішив, що не хочу тут працювати. Сказав, що мене це не влаштовує, і роботодавець та я зрозуміли, що на тому і бути, ми розійшлися. Пропрацював я лише півтора дні, і це була моя найкоротша робота в житті. Я й досі не можу зрозуміти такого підходу роботодавця, коли новачок має розбиратися сам без будь-якої підтримки, і  його залишають сам на сам із невирішеною проблемою та неробочою технікою.  

    Коучинг-сесія

    Далі почалися “темні” дні пошуку роботи. І вже коли я був на самому емоційному дні, бо я ж хотів самостійно знайти роботу, без чиєїсь допомоги, моя дружина Любов Купрієнко, психолог та психотерапевт, запропонувала провести для мене коучинг-сесію. Це було 15 січня 2021 року. Я не уявляв, для чого воно треба. Але коучинг був крутий і збувся в усіх деталях, змінивши мій стан відчаю від довгого пошуку роботи на стан натхнення від бажаного результату. Ми поставили ряд цілей та конкретних формулювань, які я б хотів почути від майбутнього роботодавця:
    1) роботу мають запропонувати до 1 лютого 2021 (тобто протягом двох тижнів!),
    2) я маю почути фразу, якої чекав: “Ми раді запропонувати вам офер…”
    3) я хотів, щоб мені також сказали, що у мене буде ментор.

    І тут почалося! Стали надходити пропозиції одна за одною. 

    Офер та контр-офер

    Спочатку рекрутерка однієї з найбільших аутсорсінгових IT-компаній України пропонує мені пройти кільки етапів інтерв’ю на позицію Software Engineer та виконати непросте, але цікаве тестове завдання. І вже коли ми були на останньому етапі, на мене вийшла рекрутерка іншої — продуктової компанії. Теж запропонувала провести одне (замість традиційних 2-3) інтерв’ю з їхньою командою розробників. Я спочатку не знав, що відповісти, а потім подумав, що це найкращий шанс дізнатися про свій рівень та оцінити самого себе, тому я погодився.

    На наступний день після інтерв’ю в продуктову компанію, їхня рекрутерка запропонувала мені контр-офер з вищим рейтом, ніж в аутсорсінговій компанії. На цю нову пропозицію я сказав, що вже в процесі обговорення з іншою компанією і залишилося лише останнє підтвердження від клієнта. Клієнт підтвердив. 

    Дилема

    І почалася дилема.

    Вибрати першу, але велику компанію, з меншим рейтом, хоча і з ментором, або другу компанію, з більшим рейтом та одразу на позицію Junior. 

    Я вибрав першу. Бо мав ще навчитися багато чому новому, плюс буде ментор, який допоможе спрямувати мій розвиток у правильному напрямку. 

    Від Trainee до Junior Software Engineer

    І отримав джоб-офер своєї мрії, саме такий, як я описував у коучінгу, і саме в ті терміни, тобто протягом двох тижнів!

    За три місяці випробувального строку у якості Trainee Software Enginee, я вивчаю також Bash, основи C language, ознайомився з компіляторами.

    По завершенні випробувального терміну, отримав промоушен до рівня Junior Software Engineer.

    Продовжую вивчати все нові і нові речі – CI/CD, pipelines, Docker, можливо, Cloud-платформи або щось інше. Як то кажуть “нєсть їм числа”. 

    А тепер можна і відпочити та взяти коротку відпустку, щоб набратися нових сил, бо шлях програміста — то довгий та звивистий шлях постійного навчання і поліпшення своїх навичок 

    Ах, так, забув сказати, що моє хобі зараз – це програмування. Бо це різновид творчості. А я це люблю.

    Джерело: Highload

  • Useful Git commands

    Useful Git commands

    Git is afree and open sourcedistributed version control system designed to handle everything from small to very large projects with speed and efficiency.

    Its goals include speed, data integrity, and support for distributed, non-linear workflows (thousands of parallel branches running on different systems).

    Git was created by Linus Torvalds in 2005 for development of the Linux kernel, with other kernel developers contributing to its initial development. Since 2005, Junio Hamano has been the core maintainer. As with most other distributed version-control systems, and unlike most client–server systems, every directory on every computer is a full-fledged repository with complete history and full version-tracking abilities, independent of network access or a central server. Software is distributed under GNU General Public License Version 2.

    Create with Git

    # Clone an existing repository
    
    git clone ssh://user@domain.tld/repo.git
    
    # Clone a unique branch from an existing repository
    
    git clone -b <branchname> --single-branch ssh://user@domain.tld/repo.git
    
    # Clone an existing repository and all its sub-modules recursively
    
    git clone --recurse-submodules ssh://user@domain.tld/repo.git
    
    # Create a new local repository
    
    git init

    Git Configuration

    # Set the name attached to all your commits
    
    git config [--global] user.name <name>
    
    # Set the email attached to all your commits
    
    git config [--global] user.email <email>
    
    # Set colorization of command line output for all repos
    
    git config --global color.ui auto
    
    # Print set name (in current repository or globally)
    
    git config [--global] user.name
    
    # Print set email (in current repository or globally)
    
    git config [--global] user.email
    

    Local Changes

    # List changed files in your working directory
    
    git status
    
    # List changes to tracked files
    
    git diff
    
    # Add all current changes in file to the next commit
    
    git add <file>
    
    # Add all current changes to the next commit
    
    git add .
    
    # Add changes to the next commit interactively
    
    git add -p <file>
    
    # Rename file and add it to next commit
    
    git mv <file> <new file name>
    
    # Delete file and add its deletion to next commit
    
    git rm <file>
    
    # Commit all local changes in tracked files
    
    git commit -a
    
    # Commit previously staged changes
    
    git commit
    
    # Change the last commit
    
    git commit --amend
    
    # Note: You shouldn't amend published commits!

    Commit History

    # Show all commits
    
    git log
    
    # Show changes over time for a specific file
    
    git log -p <file>
    
    # Show changes over time for a specific committer
    
    git log --author=<committer name>
    
    # Note: <committer name> is a pattern, so Ed will match Edward Smith. Quotes are optional if the pattern doesn't contain spaces.
    
    # Search (grep) commit messages for the given string
    
    git log --grep=<string>
    
    # Who changed what and when in file
    
    git blame <file>
    
    # Store changes temporarily
    
    git stash
    
    # Remove and apply stashed changes
    
    git stash pop
    
    # Remove file from all previous commits but keep it locally
    
    git rm --cached <file>
    

    Branches & Tags

    # List all existing branches
    
    git branch
    
    # Switch HEAD branch
    
    git checkout <branch>
    
    # Create a new branch based on your current HEAD
    
    git branch <new-branch>
    
    # Create a new tracking branch based on a remote branch
    
    git branch --track <new-branch> <remote-branch>
    
    # Delete a local branch
    
    git branch -d <branch>
    
    # Delete a remote branch
    
    git push origin --delete <branch>
    
    # Rename a branch locally
    
    git branch -m <old name> <new name>
    
    # Rename a branch on remote
    
    git push <remote> :<old name>
    git push <remote> <new name>
    
    # Tag the current commit
    
    git tag <tag-name>

    Update & Publish

    # List all currently configured remotes
    
    git remote -v
    
    # Show information about a remote
    
    git remote show <remote>
    
    # Add new remote repository
    
    git remote add <remote> <url>
    
    # Rename a remote
    
    git remote rename <old-name> <new-name>
    
    # Download all changes from remote, but don't merge into HEAD
    
    git fetch <remote>
    
    # Download all changes from remote, but don't merge into HEAD and clean up deleted branches from origin
    
    git fetch -p <remote>
    
    # Download changes and directly merge into HEAD
    
    git pull <remote> <branch>
    
    # Publish local changes on a remote
    
    git push <remote> <branch>
    
    # Track a remote repository
    
    git remote add --track <remote-branch> <remote> <url>
    
    # Publish your tags
    
    git push --tags
    

    Merge & Rebase

    # Merge branch into your current HEAD
    
    git merge <branch>
    
    # Rebase your current HEAD onto branch
    
    git rebase <branch>
    
    # Note: You shouldn't rebase published commits!
    
    # Abort a rebase
    
    git rebase --abort
    
    # Continue a rebase after resolving conflicts
    
    git rebase --continue
    
    # Resolve conflicts using your configured merge tool
    
    git mergetool
    
    # Manually resolve conflicts using your editor and mark file as resolved
    
    git add <resolved-file>
    git rm <resolved-file>

    Undo

    # Discard all local changes in your working directory
    
    git reset --hard HEAD
    
    # Discard local changes in a specific file
    
    git checkout HEAD <file>
    
    # Revert a commit by providing a new commit with contrary changes
    
    git revert <commit>
    
    # Restore a specific file from a previous commit
    
    git checkout <commit> <file>
    
    # Reset your HEAD pointer to a previous commit
    
    ## Discarding local changes:
    
    git reset --hard <commit>
    
    ## Preserving all changes as unstaged changes:
    
    git reset <commit>
    
    ## Preserving uncommitted local changes:
    
    git reset --keep <commit>

    Maybe conda commands also will be useful.

  • Useful ASCII tables

    Useful ASCII tables

    ASCII Tables

    ASCIIabbreviated fromAmerican Standard Code for Information Interchange, is a character encoding standard for electronic communication. ASCII codes represent text in computers, telecommunications equipment, and other devices. Most modern character-encoding schemes are based on ASCII, although they support many additional characters.

    TheInternet Assigned Numbers Authority(IANA) prefers the nameUS-ASCIIfor this character encoding.

    ASCII is one of the IEEE milestones.

    ASCII Control Codes

    BinOctDecHexSymbolHTML EntityName
    0000000000000x00␀ (NUL)&#000;Null char
    0000000100110x01␁ (SOH)&#001;Start of heading
    0000001000220x02␂ (STX)&#002;Start of text
    0000001100330x03␃ (ETX)&#003;End of text
    0000010000440x04␄ (EOT)&#004;End of transmission
    0000010100550x05␅ (ENQ)&#005;Enquiry
    0000011000660x06␆ (ACK)&#006;Acknowledgment
    0000011100770x07␇ (BEL)&#007;Bell
    0000100001080x08␈ ( BS)&#008;Backspace
    0000100101190x09␉ ( HT)&#009;Horizontal tab
    00001010012100x0A␊ ( LF)&#010;Line feed
    00001011013110x0B␋ ( VT)&#011;Vertical tab
    00001100014120x0C␌ ( FF)&#012;Form feed
    00001101015130x0D␍ ( CR)&#013;Carriage return
    00001110016140x0E␎ ( SO)&#014;Shift out / x-on
    00001111017150x0F␏ ( SI)&#015;Shift in / x-off
    00010000020160x10␐ (DLE)&#016;Data line escape
    00010001021170x11␑ (DC1)&#017;Device control 1 (oft. xon)
    00010010022180x12␒ (DC2)&#018;Device control 2
    00010011023190x13␓ (DC3)&#019;Device control 3 (oft. xoff)
    00010100024200x14␔ (DC4)&#020;Device control 4
    00010101025210x15␕ (NAK)&#021;Negative acknowledgement
    00010110026220x16␖ (SYN)&#022;Synchronous idle
    00010111027230x17␗ (ETB)&#023;End of transmit block
    00011000030240x18␘ (CAN)&#024;Cancel
    00011001031250x19␙ ( EM)&#025;End of medium
    00011010032260x1A␚ (SUB)&#026;Substitute
    00011011033270x1B␛ (ESC)&#027;Escape
    00011100034280x1C␜ ( FS)&#028;File separator
    00011101035290x1D␝ ( GS)&#029;Group separator
    00011110036300x1E␞ ( RS)&#030;Record separator
    00011111037310x1F␟ ( US)&#031;Unit separator

    Printable Characters

    BinOctDecHexSymbolHTML EntityName
    00100000040320x20(space)&#32;Space
    00100001041330x21!&#33;Exclamation mark
    00100010042340x22"&#34; or &quot;Double quotes (or speech marks)
    00100011043350x23#&#35;Number
    00100100044360x24$&#36;Dollar
    00100101045370x25%&#37;Percent sign
    00100110046380x26&&#38; or &amp;Ampersand
    00100111047390x27'&#39;Single quote
    00101000050400x28(&#40;Open parenthesis (or open bracket)
    00101001051410x29)&#41;Close parenthesis (or close bracket)
    00101010052420x2A*&#42;Asterisk
    00101011053430x2B+&#43;Plus
    00101100054440x2C,&#44;Comma
    00101101055450x2D-&#45;Hyphen
    00101110056460x2E.&#46;Period, dot or full stop
    00101111057470x2F/&#47;Slash or divide
    00110000060480x300&#48;Zero
    00110001061490x311&#49;One
    00110010062500x322&#50;Two
    00110011063510x333&#51;Three
    00110100064520x344&#52;Four
    00110101065530x355&#53;Five
    00110110066540x366&#54;Six
    00110111067550x377&#55;Seven
    00111000070560x388&#56;Eight
    00111001071570x399&#57;Nine
    00111010072580x3A:&#58;Colon
    00111011073590x3B;&#59;Semicolon
    00111100074600x3C<&#60; or &lt;Less than (or open angled bracket)
    00111101075610x3D=&#61;Equals
    00111110076620x3E>&#62; or &gt;Greater than (or close angled bracket)
    00111111077630x3F?&#63;Question mark
    01000000100640x40@&#64;At symbol
    01000001101650x41A&#65;Uppercase a
    01000010102660x42B&#66;Uppercase b
    01000011103670x43C&#67;Uppercase c
    01000100104680x44D&#68;Uppercase d
    01000101105690x45E&#69;Uppercase e
    01000110106700x46F&#70;Uppercase f
    01000111107710x47G&#71;Uppercase g
    01001000110720x48H&#72;Uppercase h
    01001001111730x49I&#73;Uppercase i
    01001010112740x4AJ&#74;Uppercase j
    01001011113750x4BK&#75;Uppercase k
    01001100114760x4CL&#76;Uppercase l
    01001101115770x4DM&#77;Uppercase m
    01001110116780x4EN&#78;Uppercase n
    01001111117790x4FO&#79;Uppercase o
    01010000120800x50P&#80;Uppercase p
    01010001121810x51Q&#81;Uppercase q
    01010010122820x52R&#82;Uppercase r
    01010011123830x53S&#83;Uppercase s
    01010100124840x54T&#84;Uppercase t
    01010101125850x55U&#85;Uppercase u
    01010110126860x56V&#86;Uppercase v
    01010111127870x57W&#87;Uppercase w
    01011000130880x58X&#88;Uppercase x
    01011001131890x59Y&#89;Uppercase y
    01011010132900x5AZ&#90;Uppercase z
    01011011133910x5B[&#91;Opening bracket
    01011100134920x5C\&#92;Backslash
    01011101135930x5D]&#93;Closing bracket
    01011110136940x5E^&#94;Caret – circumflex
    01011111137950x5F_&#95;Underscore
    01100000140960x60`&#96;Grave accent
    01100001141970x61a&#97;Lowercase a
    01100010142980x62b&#98;Lowercase b
    01100011143990x63c&#99;Lowercase c
    011001001441000x64d&#100;Lowercase d
    011001011451010x65e&#101;Lowercase e
    011001101461020x66f&#102;Lowercase f
    011001111471030x67g&#103;Lowercase g
    011010001501040x68h&#104;Lowercase h
    011010011511050x69i&#105;Lowercase i
    011010101521060x6Aj&#106;Lowercase j
    011010111531070x6Bk&#107;Lowercase k
    011011001541080x6Cl&#108;Lowercase l
    011011011551090x6Dm&#109;Lowercase m
    011011101561100x6En&#110;Lowercase n
    011011111571110x6Fo&#111;Lowercase o
    011100001601120x70p&#112;Lowercase p
    011100011611130x71q&#113;Lowercase q
    011100101621140x72r&#114;Lowercase r
    011100111631150x73s&#115;Lowercase s
    011101001641160x74t&#116;Lowercase t
    011101011651170x75u&#117;Lowercase u
    011101101661180x76v&#118;Lowercase v
    011101111671190x77w&#119;Lowercase w
    011110001701200x78x&#120;Lowercase x
    011110011711210x79y&#121;Lowercase y
    011110101721220x7Az&#122;Lowercase z
    011110111731230x7B{&#123;Opening brace
    011111001741240x7C|&#124;Vertical bar
    011111011751250x7D}&#125;Closing brace
    011111101761260x7E~&#126;Equivalency sign – tilde
    011111111771270x7F␡ (DEL)&#127;Delete

    Extended ASCII Characters

    BinOctDecHexSymbolHTML EntityName
    100000002001280x80€&#128; or &euro;Euro sign
    100000102021300x82‚&#130; or &sbquo;Single low-9 quotation mark
    100000112031310x83ƒ&#131; or &fnof;Latin small letter f with hook
    100001002041320x84„&#132; or &bdquo;Double low-9 quotation mark
    100001012051330x85…&#133; or &hellip;Horizontal ellipsis
    100001102061340x86†&#134; or &dagger;Dagger
    100001112071350x87‡&#135; or &Dagger;Double dagger
    100010002101360x88ˆ&#136; or &circ;Circumflex accent modifier
    100010012111370x89‰&#137; or &permil;Per mil sign
    100010102121380x8AŠ&#138; or &Scaron;Latin capital letter s with caron
    100010112131390x8B‹&#139; or &lsaquo;Single left-pointing angle quotation
    100011002141400x8CŒ&#140; or &OElig;Latin capital ligature oe
    100011102161420x8EŽ&#142;Latin capital letter z with caron
    100100012211450x91‘&#145; or &lsquo;Left single quotation mark
    100100102221460x92’&#146; or &rsquo;Right single quotation mark
    100100112231470x93“&#147; or &ldquo;Left double quotation mark
    100101002241480x94”&#148; or &rdquo;Right double quotation mark
    100101012251490x95•&#149; or &bull;Bullet
    100101102261500x96–&#150; or &ndash;En dash
    100101112271510x97—&#151; or &mdash;Em dash
    100110002301520x98˜&#152; or &tilde;Small tilde
    100110012311530x99™&#153; or &trade;Trade mark sign
    100110102321540x9Aš&#154; or &scaron;Latin small letter s with caron
    100110112331550x9B›&#155; or &rsaquo;Single right-pointing angle quotation mark
    100111002341560x9Cœ&#156; or &oelig;Latin small ligature oe
    100111102361580x9Ež&#158;Latin small letter z with caron
    100111112371590x9FŸ&#159; or &yuml;Latin capital letter y with diaeresis
    101000002401600xA0&#160; or &nbsp;Non-breaking space
    101000012411610xA1¡&#161; or &iexcl;Inverted exclamation mark
    101000102421620xA2¢&#162; or &cent;Cent sign
    101000112431630xA3£&#163; or &pound;Pound sign
    101001002441640xA4¤&#164; or &curren;Currency sign
    101001012451650xA5¥&#165; or &yen;Yen sign
    101001102461660xA6¦&#166; or &brvbar;Pipe, broken vertical bar
    101001112471670xA7§&#167; or &sect;Section sign
    101010002501680xA8¨&#168; or &uml;Spacing diaeresis – umlaut
    101010012511690xA9©&#169; or &copy;Copyright sign
    101010102521700xAAª&#170; or &ordf;Feminine ordinal indicator
    101010112531710xAB«&#171; or &laquo;Left double angle quotes
    101011002541720xAC¬&#172; or &not;Not sign
    101011012551730xAD­&#173; or &shy;Soft hyphen
    101011102561740xAE®&#174; or &reg;Registered trade mark sign
    101011112571750xAF¯&#175; or &macr;Spacing macron – overline
    101100002601760xB0°&#176; or &deg;Degree sign
    101100012611770xB1±&#177; or &plusmn;Plus-or-minus sign
    101100102621780xB2²&#178; or &sup2;Superscript two – squared
    101100112631790xB3³&#179; or &sup3;Superscript three – cubed
    101101002641800xB4´&#180; or &acute;Acute accent – spacing acute
    101101012651810xB5µ&#181; or &micro;Micro sign
    101101102661820xB6&#182; or &para;Pilcrow sign – paragraph sign
    101101112671830xB7·&#183; or &middot;Middle dot – georgian comma
    101110002701840xB8¸&#184; or &cedil;Spacing cedilla
    101110012711850xB9¹&#185; or &sup1;Superscript one
    101110102721860xBAº&#186; or &ordm;Masculine ordinal indicator
    101110112731870xBB»&#187; or &raquo;Right double angle quotes
    101111002741880xBC¼&#188; or &frac14;Fraction one quarter
    101111012751890xBD½&#189; or &frac12;Fraction one half
    101111102761900xBE¾&#190; or &frac34;Fraction three quarters
    101111112771910xBF¿&#191; or &iquest;Inverted question mark
    110000003001920xC0À&#192; or &Agrave;Latin capital letter a with grave
    110000013011930xC1Á&#193; or &Aacute;Latin capital letter a with acute
    110000103021940xC2Â&#194; or &Acirc;Latin capital letter a with circumflex
    110000113031950xC3Ã&#195; or &Atilde;Latin capital letter a with tilde
    110001003041960xC4Ä&#196; or &Auml;Latin capital letter a with diaeresis
    110001013051970xC5Å&#197; or &Aring;Latin capital letter a with ring above
    110001103061980xC6Æ&#198; or &AElig;Latin capital letter ae
    110001113071990xC7Ç&#199; or &Ccedil;Latin capital letter c with cedilla
    110010003102000xC8È&#200; or &Egrave;Latin capital letter e with grave
    110010013112010xC9É&#201; or &Eacute;Latin capital letter e with acute
    110010103122020xCAÊ&#202; or &Ecirc;Latin capital letter e with circumflex
    110010113132030xCBË&#203; or &Euml;Latin capital letter e with diaeresis
    110011003142040xCCÌ&#204; or &Igrave;Latin capital letter i with grave
    110011013152050xCDÍ&#205; or &Iacute;Latin capital letter i with acute
    110011103162060xCEÎ&#206; or &Icirc;Latin capital letter i with circumflex
    110011113172070xCFÏ&#207; or &Iuml;Latin capital letter i with diaeresis
    110100003202080xD0Ð&#208; or &ETH;Latin capital letter eth
    110100013212090xD1Ñ&#209; or &Ntilde;Latin capital letter n with tilde
    110100103222100xD2Ò&#210; or &Ograve;Latin capital letter o with grave
    110100113232110xD3Ó&#211; or &Oacute;Latin capital letter o with acute
    110101003242120xD4Ô&#212; or &Ocirc;Latin capital letter o with circumflex
    110101013252130xD5Õ&#213; or &Otilde;Latin capital letter o with tilde
    110101103262140xD6Ö&#214; or &Ouml;Latin capital letter o with diaeresis
    110101113272150xD7×&#215; or &times;Multiplication sign
    110110003302160xD8Ø&#216; or &Oslash;Latin capital letter o with slash
    110110013312170xD9Ù&#217; or &Ugrave;Latin capital letter u with grave
    110110103322180xDAÚ&#218; or &Uacute;Latin capital letter u with acute
    110110113332190xDBÛ&#219; or &Ucirc;Latin capital letter u with circumflex
    110111003342200xDCÜ&#220; or &Uuml;Latin capital letter u with diaeresis
    110111013352210xDDÝ&#221; or &Yacute;Latin capital letter y with acute
    110111103362220xDEÞ&#222; or &THORN;Latin capital letter thorn
    110111113372230xDFß&#223; or &szlig;Latin small letter sharp s – ess-zed
    111000003402240xE0à&#224; or &agrave;Latin small letter a with grave
    111000013412250xE1á&#225; or &aacute;Latin small letter a with acute
    111000103422260xE2â&#226; or &acirc;Latin small letter a with circumflex
    111000113432270xE3ã&#227; or &atilde;Latin small letter a with tilde
    111001003442280xE4ä&#228; or &auml;Latin small letter a with diaeresis
    111001013452290xE5å&#229; or &aring;Latin small letter a with ring above
    111001103462300xE6æ&#230; or &aelig;Latin small letter ae
    111001113472310xE7ç&#231; or &ccedil;Latin small letter c with cedilla
    111010003502320xE8è&#232; or &egrave;Latin small letter e with grave
    111010013512330xE9é&#233; or &eacute;Latin small letter e with acute
    111010103522340xEAê&#234; or &ecirc;Latin small letter e with circumflex
    111010113532350xEBë&#235; or &euml;Latin small letter e with diaeresis
    111011003542360xECì&#236; or &igrave;Latin small letter i with grave
    111011013552370xEDí&#237; or &iacute;Latin small letter i with acute
    111011103562380xEEî&#238; or &icirc;Latin small letter i with circumflex
    111011113572390xEFï&#239; or &iuml;Latin small letter i with diaeresis
    111100003602400xF0ð&#240; or &eth;Latin small letter eth
    111100013612410xF1ñ&#241; or &ntilde;Latin small letter n with tilde
    111100103622420xF2ò&#242; or &ograve;Latin small letter o with grave
    111100113632430xF3ó&#243; or &oacute;Latin small letter o with acute
    111101003642440xF4ô&#244; or &ocirc;Latin small letter o with circumflex
    111101013652450xF5õ&#245; or &otilde;Latin small letter o with tilde
    111101103662460xF6ö&#246; or &ouml;Latin small letter o with diaeresis
    111101113672470xF7÷&#247; or &divide;Division sign
    111110003702480xF8ø&#248; or &oslash;Latin small letter o with slash
    111110013712490xF9ù&#249; or &ugrave;Latin small letter u with grave
    111110103722500xFAú&#250; or &uacute;Latin small letter u with acute
    111110113732510xFBû&#251; or &ucirc;Latin small letter u with circumflex
    111111003742520xFCü&#252; or &uuml;Latin small letter u with diaeresis
    111111013752530xFDý&#253; or &yacute;Latin small letter y with acute
    111111103762540xFEþ&#254; or &thorn;Latin small letter thorn
    111111113772550xFFÿ&#255; or &yuml;Latin small letter y with diaeresis
  • Conda cheatsheet

    Conda

    Managing Conda and Anaconda, Environments, Python, Configuration, Packages. Removing Packages or Environments

    (більше…)
  • Find the sum of the digits in the number 100! (Python)

    Find the sum of the digits in the number 100! (Python)

    Python code to demonstrate a method to compute the factorial digists sum, i.e. 100 factorial (100!).

    This test exercise I’ve recieved when I was looking for a Trainee Python Developer position.

    n = 100
    fact = 1
      
    for i in range(1, n+1): 
        fact = fact * i
    
    # Convert number to string
    text_fact = str(fact)
    
    # Initialize empty list for every letter of factorial string 
    summ = []
    
    for letter in text_fact:
        summ.append(int(letter))
    print(sum(summ))
    648
  • Django ORM and SQL: Making QuerySet Expressions

    Django ORM and SQL: Making QuerySet Expressions

    Making QuerySet & Query Expressions with Django ORM like SQL, or Django ORM == SQL.

    If you are migrating to Django from another MVC framework, chances are you already know SQL.

    In this post, we will be illustrating how to use Django ORM by drawing analogies to equivalent SQL statements. Connecting a new topic to your existing knowledge will help you learn to use the ORM faster.

    Let us consider a simple base model for a person with attributes name, age, and gender.

    (більше…)
  • Create an E-commerce Shop with Django (Part 4)

    Create an E-commerce Shop with Django (Part 4)

    How to create a checkout form in an E-commerce Shop with Django? Part 4.

    In the previous Part 3 we create models for Order and in this Part 4 of Create an E-commerce Shop with Django we will create checkout form an order.

    Prerequisites

    • Django Latest Version
    • Virtual Environment
    • IDE PyCharm or Visual Studio Code

    1. Form

    In this part of the tutorial we will create a checkout form.

    Checkout.html file has been adjusted to the needs of the checkout display. then we only need to create a form from the core directory.

    Then in the core directory create a new file called forms.py where this file will store everything related to the form.

    Import :

    from django import forms
    from django_countries.fields import CountryField
    from django_countries.widgets import CountrySelectWidget

    You can see we are using the country field library and this is a third party library so we have to install it to use it. to install country library jus run command below :

    $ pip install django-countries

    and in project’s settings.py add this code :

    INSTALLED_APPS = [
       ...
       'django_countries',
    ]

    Then we create a class form calledCheckoutFormas a form from the checkout page.

    PAYMENT = (
        ('S', 'Stripe'),
        ('P', 'Paypal')
    )
    
    class CheckoutForm(forms.Form):
        street_address = forms.CharField(widget=forms.TextInput(attrs={
            'class': 'form-control',
            'placeholder': '1234 Main St.'
        }))
        apartment_address = forms.CharField(required=False, widget=forms.TextInput(attrs={
            'class': 'form-control',
            'placeholder': 'Apartment or suite'
        }))
        country = CountryField(blank_label='(select country)').formfield(widget=CountrySelectWidget(attrs={
            'class': 'custom-select d-block w-100'
        }))
        zip = forms.CharField(widget=forms.TextInput(attrs={
            'class': 'form-control'
        }))
        same_billing_address = forms.BooleanField(required=False)
        save_info = forms.BooleanField(required=False)
        payment_option = forms.ChoiceField(
            widget=forms.RadioSelect, choices=PAYMENT
        )

    And with this you will have checkout form.

    2. Models

    To create a checkout form we will create a new model class that functions to save shipping address an order.

    the class we will create isCheckoutAddresswhich will store the shipping address of the order from the form we made before.

    class CheckoutAddress(models.Model):
        user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
        street_address = models.CharField(max_length=100)
        apartment_address = models.CharField(max_length=100)
        country = CountryField(multiple=False)
        zip = models.CharField(max_length=100)
    
        def __str__(self):
            return self.user.username

    dont forget as well to impor becouse we would use Country Field:

    from django_countries.fields import CountryField

    Do not forget migrate your model database with the command below :

    $ python manage.py migrate
    $ python manage.py makemigrations

    3. Views

    In the view don’t forget to add the country field library and don’t forget to add the model and form that we just created

    from .forms import CheckoutForm
    from .models import (
        ...
        CheckoutAddress
    )

    Create CheckoutView class

    class CheckoutView(View):
        def get(self, *args, **kwargs):
            form = CheckoutForm()
            context = {
                'form': form
            }
            return render(self.request, 'core/checkout.html', context=context)
    
        def post(self, *args, **kwargs):
            form = CheckoutForm(self.request.POST or None)
    
            try:
                order = Order.objects.get(user=self.request.user, ordered=False)
                if form.is_valid():
                    street_address = form.cleaned_data.get('street_address')
                    apartment_address = form.cleaned_data.get('apartment_address')
                    country = form.cleaned_data.get('country')
                    zip = form.cleaned_data.get('zip')
                    same_billing_address = form.cleaned_data.get('same_billing_address')
                    save_info = form.cleaned_data.get('save_info')
                    payment_option = form.cleaned_data.get('payment_option')
    
                    checkout_address = CheckoutAddress(
                        user=self.request.user,
                        street_address=street_address,
                        apartment_address=apartment_address,
                        country=country,
                        zip=zip
                    )
    
                    checkout_address.save()
                    order.checkout_address = checkout_address
                    order.save()
                    return redirect('core:checkout')
                messages.warning(self.request, 'Fail checkout')
                return redirect('core:checkout')
    
            except ObjectDoesNotExist:
                messages.error(self.request, 'You do not have an order')
                return redirect('core:order-summary')

    In the forms.py file that we made earlier. we send the form into templates via view. Thepostfunction that captures the value sent via the form in the templates.

    4. Urls

    As usual after we make the view don’t forget to register it in the core/urls.py file.

    Import

    from django.urls import path
    from .views import (
        ...
        CheckoutView
    )

    Register all your class and fuctions in views to urls.py file. after that we will add the address in

    Create path url to checkout page with code below:

    urlpatterns = [
       ...
       path('checkout', CheckoutView.as_view(), name='checkout'),
    ]

    And finally the checkout form can be accessed and save the order data into the database

    Proceed to the next part!

    I hope you’ve found the fourth part of this tutorial helpful. In the next session, we’re going to handling payment with stripe to this E-Commerce Website.

    You can visit github where find other scripts.

  • Create a E-commerce Shop with Django (Part 3)

    Create a E-commerce Shop with Django (Part 3)

    In the previous Part 2 we create models for Order and in this Part 3 of Create a E-commerce Shop with Django we will make a summary of the order in the shopping cart of your Django shop.

    Prerequisites

    • Django Latest Version
    • Virtual Environment
    • IDE PyCharm or Visual Studio Code

    Before starting the tutorial don’t forget to activate your Virtual Environment, and the project we created in the previous tutorial.

    1. Models

    Open core / models.py using the edit code and add some functions in class model as follows :

    1. Class Item

    Nothing is changed in the Item class because the order summary is not directly related to the Item class

    2. Class OrderItem

    InOrderItemclass we will add some additional functions as follows

    class OrderItem(models.Model):
        user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
        ordered = models.BooleanField(default=False)
        item = models.ForeignKey(Item, on_delete=models.CASCADE)
        quantity = models.IntegerField(default=1)
    
        def __str__(self):
            return f'{self.quantity} of {self.item.item_name}'
    
        def get_total_item_price(self):
            return self.quantity * self.item.price
    
        def get_discount_item_price(self):
            return self.quantity * self.item.discount_price
    
        def get_amount_saved(self):
            saved = self.get_total_item_price() - self.get_discount_item_price()
            return f'{saved:.2f}'
    
        def get_final_price(self):
            if self.item.discount_price:
                return self.get_discount_item_price()
            return self.get_total_item_price()
    • get_total_item_price, returns the total price value of each product item
    • get_discount_item_price, returns the total price value of each product item based on discounted prices
    • get_amount_saved, returns the value of the price saved from existing discounts
    • get_final_price, returns which function is used as a price determinant (whether using the original price or discounted price)

    3. Class Order

    In the Order class add a function that will calculate the total price of the order

    class Order(models.Model):
        user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
        items = models.ManyToManyField(OrderItem)
        start_date = models.DateTimeField(auto_now_add=True)
        ordered_date = models.DateTimeField()
        ordered = models.BooleanField(default=False)
    
        def __str__(self):
            return self.user.username
    
        def get_total_price(self):
            total = 0
            for order_item in self.items.all():
                total += order_item.get_final_price()
            return total
    • get_total_price, returns the value of the total price of all ordered product items

    4. Migrate model database

    Do not forget migrate your model database with the command below :

    $ python manage.py migrate
    $ python manage.py makemigrations

    2. Views

    After manage our model, now switches to the core/views.py file.

    You can just just takeorder_summary.htmland place it in the templates directory.

    1. Import
    from django.core.exceptions import ObjectDoesNotExist
    from django.shortcuts import render, get_object_or_404, redirect
    from django.contrib import messages
    from django.contrib.auth.decorators import login_required
    from django.contrib.auth.mixins import LoginRequiredMixin
    from django.views.generic import ListView, DetailView, View
    from django.utils import timezone
    from core.models import (
        Item,
        Order,
        OrderItem
    )

    Import all requiment library in your views.py, in django.views.generic you can see we import the View class. for the order summary views we will use this View class

    2. CreateOrderSummaryView

    class OrderSummaryView(LoginRequiredMixin, View):
        def get(self, *args, **kwargs):
    
            try:
                order = Order.objects.get(user=self.request.user, ordered=False)
                context = {
                    'object' : order
                }
                return render(self.request, 'core/order_summary.html', context)
            except ObjectDoesNotExist:
                messages.error(self.request, "You do not have an order")
                return redirect("/")

    In the OrderSummaryView class we use the Order model as the model and order_summary.html as tempalate.

    3. Create reduce quantity product

    In the previous tutorial we made 2 function:add_to_cart()andremove_from_cart().

    add_to_cart() make the quantiy of product adding but remove_from_cart() function will make all order removed. So we will make function that will reduce a quantity of product item and remove it if quantity equal to 0

    def reduce_quantity_item(request, pk):
        item = get_object_or_404(Item, pk=pk)
        order_qs = Order.objects.filter(
            user = request.user,
            ordered=False
        )
        if order_qs.exists():
            order = order_qs[0]
            if order.items.filter(item__pk=item.pk).exists():
                order_item = OrderItem.objects.filter(
                    item = item,
                    user = request.user,
                    ordered = False
                )[0]
                if order_item.quantity > 1:
                    order_item.quantity -= 1
                    order_item.save()
                else:
                    order_item.delete()
                messages.info(request, "Item quantity is updated")
                return redirect("core:order-summary")
            else:
                messages.info(request, "This item not in your cart")
                return redirect("core:product")
        else:
            messages.info(request, "You do not have an order")
            return redirect("core:product")

    4. Make an user must log in to make an order

    For each function add an @login_required annotation, where this will throw the user into the login page when running the function if the user has not logged in

    @login_required
    def add_to_cart(request, pk):
       ...
    @login_required
    def remove_from_cart(request, pk):
       ...
    @login_required
    def reduce_quantity_item(request, pk):
       ...

    3. Urls

    After completing the view, we will now add the OrderSummaryView url and the reduce_quantity item function in the core/url.py file

    1. Import
    from django.urls import path
    from .views import (
        remove_from_cart,
        reduce_quantity_item,
        add_to_cart,
        ProductView,
        HomeView,
        OrderSummaryView
    )

    add all the views and functions that we made in the views.py file on import, so we just add OrderSummaryView and reduce_quantity_item from the previous file.

    2. Create Path Url

    Create path url to OrderSummaryView and reduce_quantity_item() function like this :

    urlpatterns = [
        ...
        path('order-summary/', OrderSummaryView.as_view(), name="order-summary"),
        path('reduce-quantity-item/<int:pk>', reduce_quantity_item, name='reduce-quantity-item'),
    ]

    And now you can access the view and another functions.

    Proceed to the next part!

    I hope you’ve found the third part of this tutorial helpful. In the next session, we’re going to make Checkout form to this E-Commerce Website.

    You can visit github where find other scripts.

KUPRIENKO