├── .gitignore ├── LICENSE ├── README.md ├── djuser.sublime-project ├── djuser.sublime-workspace └── src ├── accounts ├── __init__.py ├── admin.py ├── apps.py ├── forms.py ├── migrations │ ├── 0001_initial.py │ ├── 0002_myuser_zipcode.py │ ├── 0003_profile.py │ ├── 0004_auto_20161029_2115.py │ ├── 0005_activationprofile.py │ └── __init__.py ├── models.py ├── templates │ ├── accounts │ │ ├── form.html │ │ ├── login.html │ │ └── register.html │ └── base.html ├── tests.py ├── utils.py └── views.py ├── db.sqlite3 ├── djuser ├── __init__.py ├── settings.py ├── urls.py └── wsgi.py └── manage.py /.gitignore: -------------------------------------------------------------------------------- 1 | *.py[cod] 2 | .DS_Store 3 | 4 | bin/ 5 | include/ 6 | lib/ 7 | pip-selfcheck.json 8 | 9 | # Byte-compiled / optimized / DLL files 10 | __pycache__/ 11 | *.py[cod] 12 | *$py.class 13 | 14 | # C extensions 15 | *.so 16 | 17 | # Distribution / packaging 18 | .Python 19 | env/ 20 | build/ 21 | develop-eggs/ 22 | dist/ 23 | downloads/ 24 | eggs/ 25 | .eggs/ 26 | lib/ 27 | lib64/ 28 | parts/ 29 | sdist/ 30 | var/ 31 | *.egg-info/ 32 | .installed.cfg 33 | *.egg 34 | 35 | # PyInstaller 36 | # Usually these files are written by a python script from a template 37 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 38 | *.manifest 39 | *.spec 40 | 41 | # Installer logs 42 | pip-log.txt 43 | pip-delete-this-directory.txt 44 | 45 | # Unit test / coverage reports 46 | htmlcov/ 47 | .tox/ 48 | .coverage 49 | .coverage.* 50 | .cache 51 | nosetests.xml 52 | coverage.xml 53 | *,cover 54 | .hypothesis/ 55 | 56 | # Translations 57 | *.mo 58 | *.pot 59 | 60 | # Django stuff: 61 | *.log 62 | local_settings.py 63 | 64 | # Flask stuff: 65 | instance/ 66 | .webassets-cache 67 | 68 | # Scrapy stuff: 69 | .scrapy 70 | 71 | # Sphinx documentation 72 | docs/_build/ 73 | 74 | # PyBuilder 75 | target/ 76 | 77 | # IPython Notebook 78 | .ipynb_checkpoints 79 | 80 | # pyenv 81 | .python-version 82 | 83 | # celery beat schedule file 84 | celerybeat-schedule 85 | 86 | # dotenv 87 | .env 88 | 89 | # virtualenv 90 | .venv/ 91 | venv/ 92 | ENV/ 93 | 94 | # Spyder project settings 95 | .spyderproject 96 | 97 | # Rope project settings 98 | .ropeproject -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Coding For Entrepreneurs 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Django User Model Unleashed 2 | 3 | Django User Model Unleashed is reference series to teach you about Django user model including customizing, extending, authentication, registration and basic activation keys. Created using Django 1.10. Created by Team CFE @ http://joincfe.com. 4 | 5 | Subscribe to our [YouTube Channel](http://joincfe.com/youtube) 6 | 7 | Thanks for watching! 8 | 9 | Team CFE 10 | 11 | 12 | ## Lecture Code 13 | 14 | 15 | [3 - Extend User Model](../../tree/bdd42118e0f39d40f7399f7f93ab742afdd18086) 16 | 17 | [4 - Custom User Model](../../tree/8d2b5808df6f4171396be5fe79204cce475acf8e) 18 | 19 | [5 - Extending the Custom User Model](../../tree/9700d82304e1a6ea6c7e18e84a084b8c1d02c37a) 20 | 21 | [6 - Register User](../../tree/ba033bfc9a727c9a3abf04871e51affe5a380103) 22 | 23 | [7 - User Login & Authentication](../../tree/410d6069f9a1a72d9f9ee744663bf0b994da9984) 24 | 25 | [8 - User Logout](../../tree/084bef4879286aad34e761c2ac059ec52ad2b351) 26 | 27 | [9 - Login with Username or Email](../../tree/c89250735f9b088f507ea553ac260f62bc404217) 28 | 29 | [10 - Inactive User](../../tree/76391309c7ffcb98a41ac9a79359bf1ff4904375) 30 | 31 | [11 - Activation Keys](../../tree/4980628a74c6d8cd6f1ee8ee3e168b06a1c5b7dd) 32 | 33 | 34 | -------------------------------------------------------------------------------- /djuser.sublime-project: -------------------------------------------------------------------------------- 1 | { 2 | "folders": 3 | [ 4 | { 5 | "path": "/Users/cfe/Desktop/djuser" 6 | } 7 | ] 8 | } 9 | -------------------------------------------------------------------------------- /djuser.sublime-workspace: -------------------------------------------------------------------------------- 1 | { 2 | "auto_complete": 3 | { 4 | "selected_items": 5 | [ 6 | [ 7 | "pub", 8 | "publish_date" 9 | ], 10 | [ 11 | "time", 12 | "timezone" 13 | ], 14 | [ 15 | "auto", 16 | "auto_now" 17 | ], 18 | [ 19 | "Post", 20 | "PostModel" 21 | ], 22 | [ 23 | "blog", 24 | "blog_post_model_pre_save_receiver" 25 | ], 26 | [ 27 | "pos", 28 | "post_model_post_save_receiver" 29 | ], 30 | [ 31 | "Po", 32 | "PostModel" 33 | ], 34 | [ 35 | "val", 36 | "validate_justin" 37 | ], 38 | [ 39 | "va", 40 | "validate_author_email" 41 | ], 42 | [ 43 | "pat", 44 | "patterns" 45 | ], 46 | [ 47 | "Ht", 48 | "HttpResponse" 49 | ], 50 | [ 51 | "r", 52 | "return" 53 | ], 54 | [ 55 | "obj", 56 | "obj_url" 57 | ], 58 | [ 59 | "k", 60 | "kwargs" 61 | ], 62 | [ 63 | "se", 64 | "settings" 65 | ], 66 | [ 67 | "kirr", 68 | "kirr_redirect_view" 69 | ], 70 | [ 71 | "Kir", 72 | "KirrURL" 73 | ], 74 | [ 75 | "in", 76 | "instance" 77 | ], 78 | [ 79 | "s", 80 | "shortcode" 81 | ], 82 | [ 83 | "ran", 84 | "random" 85 | ], 86 | [ 87 | "aut", 88 | "auto_now_add" 89 | ], 90 | [ 91 | "ch", 92 | "chars" 93 | ], 94 | [ 95 | "file", 96 | "filename" 97 | ], 98 | [ 99 | "save", 100 | "save_path" 101 | ], 102 | [ 103 | "get", 104 | "get_payload" 105 | ], 106 | [ 107 | "email", 108 | "email_message" 109 | ], 110 | [ 111 | "inb", 112 | "inbox_item_list" 113 | ], 114 | [ 115 | "ea", 116 | "email_message" 117 | ], 118 | [ 119 | "html", 120 | "html_text" 121 | ], 122 | [ 123 | "ema", 124 | "email_message" 125 | ], 126 | [ 127 | "acc", 128 | "access_secret" 129 | ], 130 | [ 131 | "con", 132 | "consumer_secret" 133 | ], 134 | [ 135 | "cons", 136 | "consumer_key" 137 | ], 138 | [ 139 | "BlogList", 140 | "blogListController" 141 | ], 142 | [ 143 | "font", 144 | "font-size" 145 | ], 146 | [ 147 | "img", 148 | "img_r" 149 | ], 150 | [ 151 | "sel", 152 | "sel_soup" 153 | ], 154 | [ 155 | "web", 156 | "webdriver" 157 | ], 158 | [ 159 | "my", 160 | "my_num_list" 161 | ], 162 | [ 163 | "nu", 164 | "num_of_items" 165 | ], 166 | [ 167 | "my_", 168 | "my_num_list" 169 | ], 170 | [ 171 | "str", 172 | "str" 173 | ], 174 | [ 175 | "query", 176 | "queryset" 177 | ], 178 | [ 179 | "read", 180 | "read_time_min" 181 | ], 182 | [ 183 | "rea", 184 | "read_time_minutes" 185 | ], 186 | [ 187 | "count", 188 | "count_words" 189 | ], 190 | [ 191 | "cont", 192 | "content_type" 193 | ], 194 | [ 195 | "Co", 196 | "CommentForm" 197 | ], 198 | [ 199 | "Commen", 200 | "CommentForm" 201 | ], 202 | [ 203 | "H", 204 | "HttpResponseRedirect" 205 | ], 206 | [ 207 | "Comm", 208 | "CommentManager" 209 | ], 210 | [ 211 | "parent", 212 | "parent_qs" 213 | ], 214 | [ 215 | "parent_", 216 | "parent_id" 217 | ], 218 | [ 219 | "obje", 220 | "objects" 221 | ], 222 | [ 223 | "pare", 224 | "parent_id" 225 | ], 226 | [ 227 | "comm", 228 | "CommentManager" 229 | ], 230 | [ 231 | "Com", 232 | "Comment" 233 | ], 234 | [ 235 | "cle", 236 | "clean_parent_id" 237 | ], 238 | [ 239 | "COmm", 240 | "CommentManager" 241 | ], 242 | [ 243 | "content", 244 | "content_type" 245 | ], 246 | [ 247 | "co", 248 | "comments" 249 | ], 250 | [ 251 | "conten", 252 | "content_type" 253 | ], 254 | [ 255 | "mar", 256 | "margin-left" 257 | ], 258 | [ 259 | "conte", 260 | "contentItem" 261 | ], 262 | [ 263 | "mark", 264 | "markedContent" 265 | ], 266 | [ 267 | "titl", 268 | "titleItem" 269 | ], 270 | [ 271 | "tit", 272 | "titleValue" 273 | ], 274 | [ 275 | "use", 276 | "username" 277 | ], 278 | [ 279 | "get_o", 280 | "get_object" 281 | ], 282 | [ 283 | "usr", 284 | "username" 285 | ], 286 | [ 287 | "get_obj", 288 | "get_object_or_404" 289 | ], 290 | [ 291 | "sale", 292 | "sale_price" 293 | ], 294 | [ 295 | "ratin", 296 | "rating_obj" 297 | ], 298 | [ 299 | "prod", 300 | "product" 301 | ], 302 | [ 303 | "product", 304 | "productrating_set" 305 | ], 306 | [ 307 | "rai", 308 | "ratings" 309 | ], 310 | [ 311 | "rat", 312 | "ratings" 313 | ], 314 | [ 315 | "pro", 316 | "product_obj" 317 | ], 318 | [ 319 | "ra", 320 | "rating_obj" 321 | ], 322 | [ 323 | "ob", 324 | "objects" 325 | ], 326 | [ 327 | "Pr", 328 | "ProductRating" 329 | ], 330 | [ 331 | "Mu", 332 | "MultipleObjectsReturned" 333 | ], 334 | [ 335 | "Pro", 336 | "ProductRating" 337 | ], 338 | [ 339 | "inpu", 340 | "inputValue" 341 | ], 342 | [ 343 | "tra", 344 | "transactions_today" 345 | ], 346 | [ 347 | "today", 348 | "today_max" 349 | ], 350 | [ 351 | "date", 352 | "datetime" 353 | ], 354 | [ 355 | "get_", 356 | "get_transactions" 357 | ], 358 | [ 359 | "mode", 360 | "models" 361 | ], 362 | [ 363 | "is", 364 | "is_active" 365 | ], 366 | [ 367 | "Sell", 368 | "SellerAccount" 369 | ], 370 | [ 371 | "dow", 372 | "download_link" 373 | ], 374 | [ 375 | "w", 376 | "wrap" 377 | ], 378 | [ 379 | "http", 380 | "Http404" 381 | ], 382 | [ 383 | "produ", 384 | "product_obj" 385 | ], 386 | [ 387 | "fun", 388 | "function" 389 | ], 390 | [ 391 | "wid", 392 | "width" 393 | ], 394 | [ 395 | "po", 396 | "products" 397 | ], 398 | [ 399 | "to", 400 | "top_tags_idless" 401 | ], 402 | [ 403 | "Tag", 404 | "TagView" 405 | ], 406 | [ 407 | "new", 408 | "new_view" 409 | ], 410 | [ 411 | "Prod", 412 | "ProductDetailView" 413 | ], 414 | [ 415 | "ana", 416 | "analytic_obj" 417 | ], 418 | [ 419 | "an", 420 | "analytic_obj" 421 | ], 422 | [ 423 | "model", 424 | "models" 425 | ], 426 | [ 427 | "tag", 428 | "tag_set" 429 | ], 430 | [ 431 | "tags", 432 | "tags_list" 433 | ], 434 | [ 435 | "hd_", 436 | "hd_max" 437 | ], 438 | [ 439 | "hd", 440 | "hd_created" 441 | ], 442 | [ 443 | "temp", 444 | "temp_loc" 445 | ], 446 | [ 447 | "thu", 448 | "thumb_file" 449 | ], 450 | [ 451 | "Tu", 452 | "Thumbnail" 453 | ], 454 | [ 455 | "qu", 456 | "query" 457 | ], 458 | [ 459 | "mim", 460 | "mimetype" 461 | ], 462 | [ 463 | "Htt", 464 | "HttpResponse" 465 | ], 466 | [ 467 | "url", 468 | "urlpatterns" 469 | ], 470 | [ 471 | "des", 472 | "decorators" 473 | ], 474 | [ 475 | "form", 476 | "form_valid" 477 | ], 478 | [ 479 | "slug", 480 | "slugify" 481 | ], 482 | [ 483 | "sug", 484 | "slugify" 485 | ], 486 | [ 487 | "Upda", 488 | "UpdateView" 489 | ], 490 | [ 491 | "Crea", 492 | "CreateView" 493 | ], 494 | [ 495 | "mu", 496 | "MultiSlugMixin" 497 | ], 498 | [ 499 | "Product", 500 | "ProductDetailView" 501 | ], 502 | [ 503 | "ht", 504 | "Http404" 505 | ], 506 | [ 507 | "de", 508 | "description" 509 | ], 510 | [ 511 | "object", 512 | "object_id" 513 | ], 514 | [ 515 | "option", 516 | "option1" 517 | ] 518 | ] 519 | }, 520 | "buffers": 521 | [ 522 | { 523 | "settings": 524 | { 525 | "buffer_size": 0, 526 | "line_ending": "Unix" 527 | } 528 | } 529 | ], 530 | "build_system": "", 531 | "command_palette": 532 | { 533 | "height": 287.0, 534 | "selected_items": 535 | [ 536 | [ 537 | "mark", 538 | "Markdown Preview: Preview in Browser" 539 | ], 540 | [ 541 | "mar", 542 | "Markdown Preview: Preview in Browser" 543 | ], 544 | [ 545 | "markd", 546 | "Markdown Preview: Preview in Browser" 547 | ], 548 | [ 549 | "markdown", 550 | "Markdown Preview: Preview in Browser" 551 | ], 552 | [ 553 | "", 554 | "Convert Case: Lower Case" 555 | ], 556 | [ 557 | "package", 558 | "Package Control: List Packages" 559 | ], 560 | [ 561 | "install", 562 | "Package Control: Install Package" 563 | ] 564 | ], 565 | "width": 575.0 566 | }, 567 | "console": 568 | { 569 | "height": 125.0 570 | }, 571 | "distraction_free": 572 | { 573 | "menu_visible": true, 574 | "show_minimap": false, 575 | "show_open_files": false, 576 | "show_tabs": false, 577 | "side_bar_visible": false, 578 | "status_bar_visible": false 579 | }, 580 | "file_history": 581 | [ 582 | "/Users/cfe/Desktop/djtem/src/templates/admin/base_site.html", 583 | "/Users/cfe/Desktop/djtem/src/djtem/settings.py", 584 | "/Users/cfe/Desktop/djtem/src/djtem/urls.py", 585 | "/Users/cfe/Desktop/djtem/src/blog/urls.py", 586 | "/Users/cfe/Desktop/djtem/src/blog/views.py", 587 | "/Users/cfe/Desktop/djtem/src/blog/templates/blog/base-messages.html", 588 | "/Users/cfe/Desktop/djtem/src/blog/templates/blog/search-blog.html", 589 | "/Users/cfe/Desktop/djtem/src/blog/templates/blog/components/message.html", 590 | "/Users/cfe/Desktop/djtem/src/blog/templates/blog/create-view.html", 591 | "/Users/cfe/Desktop/djtem/src/blog/templates/blog/list-view-public.html", 592 | "/Users/cfe/Desktop/djtem/src/blog/templates/blog/list-view.html", 593 | "/Users/cfe/Desktop/djtem/src/blog/templates/blog/test-view.html", 594 | "/Users/cfe/Desktop/djtem/src/blog/templates/blog/update-view.html", 595 | "/Users/cfe/Desktop/djtem/src/blog/templates/blog/base.html", 596 | "/Users/cfe/Desktop/djtem/src/blog/templates/blog/delete-view.html", 597 | "/Users/cfe/Desktop/djtem/src/blog/templates/blog/detail-view.html", 598 | "/Users/cfe/Desktop/djtem/src/blog/templates/blog/components/search.html", 599 | "/Users/cfe/Desktop/djmod/README.md", 600 | "/Users/cfe/Desktop/djmod/src/blog/migrations/validators.py", 601 | "/Users/cfe/Desktop/djmod/src/djmod/settings.py", 602 | "/Users/cfe/Desktop/djmod/.gitignore", 603 | "/Users/cfe/Desktop/kirr/src/shortener/models.py", 604 | "/Users/cfe/Desktop/kirr/src/requirements.txt", 605 | "/Users/cfe/Desktop/kirr/src/kirr/settings/__init__.py", 606 | "/Users/cfe/Desktop/kirr/src/kirr/settings/justin_settings.py", 607 | "/Users/cfe/Desktop/kirr/src/.gitignore", 608 | "/Users/cfe/Desktop/kirr/src/kirr/settings/production.py", 609 | "/Users/cfe/Desktop/kirr/src/kirr/settings/local.py", 610 | "/Users/cfe/Desktop/kirr/src/kirr/old_settings.py", 611 | "/Users/cfe/Desktop/kirr/src/Procfile", 612 | "/Users/cfe/Desktop/kirr/Procfile", 613 | "/Users/cfe/Library/Application Support/Sublime Text 2/Packages/User/Preferences.sublime-settings", 614 | "/Users/cfe/Desktop/trydjango110/src/kirr/hostscf/views.py", 615 | "/Users/cfe/Desktop/trydjango110/src/kirr/hostscf/urls.py", 616 | "/Users/cfe/Desktop/trydjango110/src/kirr/hostsconf/urls.py", 617 | "/Users/cfe/Desktop/trydjango110/src/kirr/hostsconf/views.py", 618 | "/Users/cfe/Desktop/trydjango110/src/kirr/hostsconf/__init__.py", 619 | "/Users/cfe/Desktop/trydjango110/src/shortener/management/commands/__init__.py", 620 | "/Users/cfe/Desktop/trydjango110/src/shortener/management/__init__.py", 621 | "/Users/cfe/Desktop/trydjango110/src/shortener/utils.py", 622 | "/Users/cfe/Desktop/trydjango110/.gitignore", 623 | "/Users/cfe/Desktop/trydjango110/readme.md", 624 | "/Users/cfe/Desktop/trydjango110/src/db.sqlite3", 625 | "/Users/cfe/Desktop/tweetup/src/tweet_it_up.py", 626 | "/Users/cfe/Desktop/tryangular/src/js/app/app.module.js", 627 | "/Users/cfe/Desktop/tryangular/src/js/app/app.config.js", 628 | "/Users/cfe/Desktop/tryangular/config.ru", 629 | "/Users/cfe/Desktop/tryangular/src/config.ru", 630 | "/Users/cfe/Desktop/tryangular/quicktips.md", 631 | "/Users/cfe/Desktop/tryangular/src/js/angular.min.js", 632 | "/Users/cfe/Desktop/tryangular/README.md", 633 | "/Users/cfe/Desktop/tryangular/new_log.md", 634 | "/Users/cfe/Desktop/tryangular/src/js/app/blogList/blog-list.component.js", 635 | "/Users/cfe/Desktop/tryangular/src/js/app/blogList/blog-list.module.js", 636 | "/Users/cfe/Desktop/tryangular/src/quicktips.md", 637 | "/Users/cfe/Desktop/tryangular/js/angular.min.js", 638 | "/Users/cfe/Desktop/tryangular/index.html", 639 | "/Users/cfe/Downloads/angular.min.js", 640 | "/Users/cfe/Desktop/scrape/notes/yelpapi.py", 641 | "/Users/cfe/Desktop/scrape/25/js_scrape.py", 642 | "/Users/cfe/Desktop/30DaysofPython/day5_functions_start.py", 643 | "/Users/cfe/Dropbox/CFE Projects/30 Days of Python/Notes/conditionals.py", 644 | "/Users/cfe/Desktop/blog-api/src/posts/forms.py", 645 | "/Users/cfe/Desktop/blog-api/src/blog/settings.py", 646 | "/Users/cfe/Desktop/blog-api/src/posts/serializers.py", 647 | "/Users/cfe/Desktop/blog-api/requirements.txt", 648 | "/Users/cfe/Desktop/blog-api/src/comments/migrations/0002_auto_20160325_2151.py", 649 | "/Users/cfe/Desktop/blog/src/posts/models.py", 650 | "/Users/cfe/Desktop/blog/src/posts/utils.py", 651 | "/Users/cfe/Desktop/blog/src/posts/views.py", 652 | "/Users/cfe/Desktop/blog/src/comments/forms.py", 653 | "/Users/cfe/Desktop/blog/src/blog/urls.py", 654 | "/Users/cfe/Desktop/blog/src/templates/comment_thread.html", 655 | "/Users/cfe/Desktop/blog/src/templates/post_detail.html", 656 | "/Users/cfe/Desktop/blog/src/comments/views.py", 657 | "/Users/cfe/Desktop/blog/src/comments/urls.py", 658 | "/Users/cfe/Desktop/blog/src/comments/models.py", 659 | "/Users/cfe/Desktop/blog/README.md", 660 | "/Users/cfe/Desktop/blog/src/posts/migrations/0004_post_read_time.py", 661 | "/Users/cfe/Desktop/blog/src/templates/base.html", 662 | "/Users/cfe/Desktop/blog/src/templates/comments/comment_thread.html", 663 | "/Users/cfe/Desktop/blog/src/static/css/base.css", 664 | "/Users/cfe/Desktop/blog/src/posts/urls.py", 665 | "/Users/cfe/Desktop/blog/src/comments/migrations/0002_comment_parent.py", 666 | "/Users/cfe/Desktop/blog/src/posts/forms.py", 667 | "/Users/cfe/Desktop/blog/src/templates/post_list.html", 668 | "/Users/cfe/Desktop/blog/src/blog/settings.py", 669 | "/Users/cfe/Desktop/blog/src/comments/admin.py", 670 | "/Users/cfe/Desktop/blog/static_cdn/css/base.css", 671 | "/Users/cfe/Desktop/blog/src/templates/post_form.html", 672 | "/Users/jmitch/Desktop/blog/src/blog/urls.py", 673 | "/Users/jmitch/Desktop/blog/src/blog/settings.py", 674 | "/Users/jmitch/Desktop/blog/src/db.sqlite3", 675 | "/Users/jmitch/Desktop/blog/src/blog/wsgi.py", 676 | "/Users/jmitch/Desktop/blog/README.md", 677 | "/Users/jmitch/Desktop/dm/src/products/views.py", 678 | "/Users/jmitch/Desktop/dm/src/templates/form.html", 679 | "/Users/jmitch/Desktop/dm/src/templates/form_include.html", 680 | "/Users/jmitch/Desktop/dm/src/sellers/forms.py", 681 | "/Users/jmitch/Desktop/dm/src/templates/base.html", 682 | "/Users/jmitch/Desktop/dm/src/digitalmarket/mixins.py", 683 | "/Users/jmitch/Desktop/dm/src/templates/products/product_list_snippet.html", 684 | "/Users/jmitch/Desktop/dm/src/templates/products/library_list.html", 685 | "/Users/jmitch/Desktop/dm/src/products/urls.py", 686 | "/Users/jmitch/Desktop/dm/src/templates/products/product_detail.html", 687 | "/Users/jmitch/Desktop/dm/src/templates/products/product_list.html", 688 | "/Users/jmitch/Desktop/dm/src/products/tests.py", 689 | "/Users/jmitch/Desktop/dm/src/products/admin.py", 690 | "/Users/jmitch/Desktop/dm/src/sellers/models.py", 691 | "/Users/jmitch/Desktop/dm/src/products/models.py", 692 | "/Users/jmitch/Desktop/dm/src/templates/dashboard/view.html", 693 | "/Users/jmitch/Desktop/dm/src/dashboard/views.py", 694 | "/Users/jmitch/Desktop/dm/README.md", 695 | "/Users/jmitch/Desktop/dm/src/digitalmarket/urls.py", 696 | "/Users/jmitch/Desktop/dm/src/sellers/views.py", 697 | "/Users/jmitch/Desktop/dm/src/checkout/views.py", 698 | "/Users/jmitch/Desktop/dm.md", 699 | "/Users/jmitch/Desktop/dm/src/digitalmarket/settings.py", 700 | "/Users/jmitch/Desktop/dm/LICENSE", 701 | "/Users/jmitch/Desktop/dm/src/templates/sellers/dashboard.html", 702 | "/Users/jmitch/Desktop/dm/src/sellers/mixins.py", 703 | "/Users/jmitch/Desktop/dm/src/analytics/models.py", 704 | "/Users/jmitch/Desktop/dm/src/products/mixins.py", 705 | "/Users/jmitch/Desktop/dm/src/templates/sellers/product_list_view.html", 706 | "/Users/jmitch/Desktop/dm/src/billing/models.py", 707 | "/Users/jmitch/Desktop/dm/src/sellers/urls.py", 708 | "/Users/jmitch/Desktop/dm/src/templates/sellers/transaction_list.html", 709 | "/Users/jmitch/Desktop/dm/src/templates/sellers/transaction_list_view.html" 710 | ], 711 | "find": 712 | { 713 | "height": 35.0 714 | }, 715 | "find_in_files": 716 | { 717 | "height": 0.0, 718 | "where_history": 719 | [ 720 | "/Users/jmitch/Desktop/ecommerce-2/src", 721 | "/Users/jmitch/Dropbox/projects/kpj", 722 | "/Users/jmitch/Dropbox/projects/kpj/kpj", 723 | "/Users/jmitch/Dropbox/projects/", 724 | "/Users/jmitch/Dropbox/projects/kpj/kpj", 725 | "", 726 | "/Users/jmitch/Dropbox/projects/kpj/kpj", 727 | "/Users/jmitch/Dropbox/projects/kpj", 728 | "/Users/jmitch/Dropbox/cfe/src" 729 | ] 730 | }, 731 | "find_state": 732 | { 733 | "case_sensitive": false, 734 | "find_history": 735 | [ 736 | "post_model_list_view", 737 | "$http", 738 | "get_transactions", 739 | "ProductUpdateView", 740 | "delete all", 741 | "jmitch-#", 742 | "AddressSelectFormView", 743 | "order_address", 744 | "\"", 745 | "item_it", 746 | "trydjango18", 747 | "questions_notification", 748 | "app.task", 749 | "needs_rep", 750 | "sendgrid", 751 | "celerybeat-schedule.db", 752 | "get_next_lecture", 753 | "lecture_quiz_result", 754 | "quiz", 755 | "url", 756 | "reverse", 757 | "module-box", 758 | "slug", 759 | "lang", 760 | "send_mail", 761 | "get_user", 762 | "ppe_4", 763 | "as_view", 764 | "\"join\"", 765 | "saftey", 766 | "Saftey Trianing i", 767 | "Training on new pesticides prior to first use", 768 | "transaction", 769 | "render_to", 770 | "render_to_pdf", 771 | "render_to", 772 | "DeleteView", 773 | "welcome_", 774 | "welcome", 775 | "all.html", 776 | "$.ajax", 777 | "ajax", 778 | "wistia", 779 | "upload", 780 | "review", 781 | "review now", 782 | "review_chemicals", 783 | "lectures_admin", 784 | "upload_bulk", 785 | "ChemicalsViewAdmin", 786 | "filter(active=F", 787 | "active", 788 | "LectureQuizAdminView", 789 | "formview", 790 | "$.ajax", 791 | "ajax", 792 | "clean", 793 | "keep", 794 | "questionanswer", 795 | "initial", 796 | "get_lecture", 797 | "slug", 798 | "LectureDetailView", 799 | "get_lecture", 800 | "get_next_lecture", 801 | "lecture_quiz", 802 | "edit_lecture", 803 | "single_lecture", 804 | "single", 805 | "form.as", 806 | "question.as", 807 | "question", 808 | "method", 809 | "csv", 810 | "ceu", 811 | "login", 812 | "easy", 813 | "grand", 814 | "pricing", 815 | "cost", 816 | "paginator", 817 | "question", 818 | "lecturequestion", 819 | "question", 820 | "next", 821 | "take_quiz", 822 | "after ", 823 | "href", 824 | "take_quiz", 825 | "start", 826 | "Coding", 827 | "Coding For Entrepreneurs", 828 | "Coding for Entrepreneurs", 829 | "results", 830 | "cleaned_email", 831 | "class=\"fa fa-check\"", 832 | "You are already logged in", 833 | "pricing", 834 | "login", 835 | "PasswordResetForm", 836 | "team", 837 | "team_id", 838 | "user_logged_in", 839 | "transcript", 840 | "template", 841 | "modal", 842 | "def __unicode__(self)", 843 | "def__unicode__(self)", 844 | "check", 845 | "chain", 846 | "action", 847 | "get_model", 848 | "team", 849 | "DEFAULT_FROM_EMAIL", 850 | "PasswordResetForm", 851 | "activate", 852 | "settings", 853 | "request", 854 | "reset", 855 | "checmicals", 856 | "activity", 857 | "Pag", 858 | "quiz", 859 | "middle", 860 | "user_logged_in", 861 | "create", 862 | "create_user", 863 | "MemberCreateForm" 864 | ], 865 | "highlight": false, 866 | "in_selection": false, 867 | "preserve_case": false, 868 | "regex": false, 869 | "replace_history": 870 | [ 871 | "jmitch=#", 872 | "'", 873 | "ecommerce2", 874 | "Control Guidance Solutions, LLC", 875 | "class=\"fa fa-check fa-2x\"", 876 | "img/apple-touch-icon-152.png", 877 | "{})", 878 | "render(request,", 879 | "render(", 880 | ")", 881 | "render(request,", 882 | "Coding For Entrepreneurs", 883 | "CodingForEntrepreneurs.com", 884 | "Coding For Entrepreneurs", 885 | "CodingForEntrepreneurs.com" 886 | ], 887 | "reverse": false, 888 | "show_context": false, 889 | "use_buffer2": false, 890 | "whole_word": false, 891 | "wrap": true 892 | }, 893 | "groups": 894 | [ 895 | { 896 | "selected": 0, 897 | "sheets": 898 | [ 899 | { 900 | "buffer": 0, 901 | "settings": 902 | { 903 | "buffer_size": 0, 904 | "regions": 905 | { 906 | }, 907 | "selection": 908 | [ 909 | [ 910 | 0, 911 | 0 912 | ] 913 | ], 914 | "settings": 915 | { 916 | "syntax": "Packages/Text/Plain text.tmLanguage" 917 | }, 918 | "translation.x": 0.0, 919 | "translation.y": 0.0, 920 | "zoom_level": 1.0 921 | }, 922 | "type": "text" 923 | } 924 | ] 925 | } 926 | ], 927 | "incremental_find": 928 | { 929 | "height": 25.0 930 | }, 931 | "input": 932 | { 933 | "height": 31.0 934 | }, 935 | "layout": 936 | { 937 | "cells": 938 | [ 939 | [ 940 | 0, 941 | 0, 942 | 1, 943 | 1 944 | ] 945 | ], 946 | "cols": 947 | [ 948 | 0.0, 949 | 1.0 950 | ], 951 | "rows": 952 | [ 953 | 0.0, 954 | 1.0 955 | ] 956 | }, 957 | "menu_visible": true, 958 | "output.find_results": 959 | { 960 | "height": 136.0 961 | }, 962 | "replace": 963 | { 964 | "height": 64.0 965 | }, 966 | "save_all_on_build": true, 967 | "select_file": 968 | { 969 | "height": 0.0, 970 | "selected_items": 971 | [ 972 | [ 973 | "email", 974 | "templates/team/email_instructions.html" 975 | ] 976 | ], 977 | "width": 0.0 978 | }, 979 | "select_project": 980 | { 981 | "height": 0.0, 982 | "selected_items": 983 | [ 984 | ], 985 | "width": 0.0 986 | }, 987 | "show_minimap": false, 988 | "show_open_files": true, 989 | "show_tabs": true, 990 | "side_bar_visible": true, 991 | "side_bar_width": 383.0, 992 | "status_bar_visible": true 993 | } 994 | -------------------------------------------------------------------------------- /src/accounts/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codingforentrepreneurs/Django-User-Model-Unleashed/11e57778d67d4c3356fc6dfda52c8210f29af296/src/accounts/__init__.py -------------------------------------------------------------------------------- /src/accounts/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | 3 | 4 | from django import forms 5 | from django.contrib import admin 6 | from django.contrib.auth.models import Group 7 | from django.contrib.auth.admin import UserAdmin as BaseUserAdmin 8 | from django.contrib.auth.forms import ReadOnlyPasswordHashField 9 | 10 | from .forms import UserChangeForm, UserCreationForm 11 | from .models import MyUser, Profile, ActivationProfile 12 | 13 | 14 | class UserAdmin(BaseUserAdmin): 15 | # The forms to add and change user instances 16 | form = UserChangeForm 17 | add_form = UserCreationForm 18 | 19 | # The fields to be used in displaying the User model. 20 | # These override the definitions on the base UserAdmin 21 | # that reference specific fields on auth.User. 22 | list_display = ('username', 'email', 'is_admin') 23 | list_filter = ('is_admin',) 24 | fieldsets = ( 25 | (None, {'fields': ('username', 'email', 'password')}), 26 | ('Personal info', {'fields': ('zipcode',)}), 27 | ('Permissions', {'fields': ('is_admin', 'is_staff',)}), 28 | ('Access', {'fields': ('is_active',)}), 29 | ) 30 | # add_fieldsets is not a standard ModelAdmin attribute. UserAdmin 31 | # overrides get_fieldsets to use this attribute when creating a user. 32 | add_fieldsets = ( 33 | (None, { 34 | 'classes': ('wide',), 35 | 'fields': ('username', 'email', 'password1', 'password2')} 36 | ), 37 | ) 38 | search_fields = ('username', 'email',) 39 | ordering = ('username', 'email',) 40 | filter_horizontal = () 41 | 42 | 43 | admin.site.register(MyUser, UserAdmin) 44 | 45 | admin.site.register(Profile) 46 | 47 | admin.site.register(ActivationProfile) 48 | 49 | 50 | # ... and, since we're not using Django's built-in permissions, 51 | # unregister the Group model from admin. 52 | admin.site.unregister(Group) 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /src/accounts/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class AccountsConfig(AppConfig): 5 | name = 'accounts' 6 | -------------------------------------------------------------------------------- /src/accounts/forms.py: -------------------------------------------------------------------------------- 1 | from django import forms 2 | 3 | from django.contrib.auth.forms import ReadOnlyPasswordHashField 4 | from django.contrib.auth import authenticate, get_user_model 5 | from django.core.validators import RegexValidator 6 | from django.db.models import Q 7 | 8 | from .models import USERNAME_REGEX 9 | 10 | 11 | 12 | User = get_user_model() 13 | 14 | 15 | class UserLoginForm(forms.Form): 16 | query = forms.CharField(label='Username / Email') 17 | password = forms.CharField(label='Password', widget=forms.PasswordInput) 18 | 19 | def clean(self, *args, **kwargs): 20 | query = self.cleaned_data.get("query") 21 | password = self.cleaned_data.get("password") 22 | user_qs_final = User.objects.filter( 23 | Q(username__iexact=query)| 24 | Q(email__iexact=query) 25 | ).distinct() 26 | if not user_qs_final.exists() and user_qs_final.count() != 1: 27 | raise forms.ValidationError("Invalid credentials -- user not exist") 28 | user_obj = user_qs_final.first() 29 | if not user_obj.check_password(password): 30 | # log auth tries 31 | raise forms.ValidationError("Invalid credentials -- passowrd invalid") 32 | if not user_obj.is_active: 33 | raise forms.ValidationError("Inactive user. Please verify your email address.") 34 | self.cleaned_data["user_obj"] = user_obj 35 | return super(UserLoginForm, self).clean(*args, **kwargs) 36 | 37 | 38 | class UserCreationForm(forms.ModelForm): 39 | """A form for creating new users. Includes all the required 40 | fields, plus a repeated password.""" 41 | password1 = forms.CharField(label='Password', widget=forms.PasswordInput) 42 | password2 = forms.CharField(label='Password confirmation', widget=forms.PasswordInput) 43 | 44 | class Meta: 45 | model = User 46 | fields = ('username', 'email',) 47 | 48 | def clean_password2(self): 49 | # Check that the two password entries match 50 | password1 = self.cleaned_data.get("password1") 51 | password2 = self.cleaned_data.get("password2") 52 | if password1 and password2 and password1 != password2: 53 | raise forms.ValidationError("Passwords don't match") 54 | return password2 55 | 56 | def save(self, commit=True): 57 | # Save the provided password in hashed format 58 | user = super(UserCreationForm, self).save(commit=False) 59 | user.set_password(self.cleaned_data["password1"]) 60 | user.is_active = False 61 | # create a new user hash for activating email. 62 | 63 | if commit: 64 | user.save() 65 | return user 66 | 67 | 68 | 69 | class UserChangeForm(forms.ModelForm): 70 | """A form for updating users. Includes all the fields on 71 | the user, but replaces the password field with admin's 72 | password hash display field. 73 | """ 74 | password = ReadOnlyPasswordHashField() 75 | 76 | class Meta: 77 | model = User 78 | fields = ('username', 'email', 'password', 'is_staff', 'is_active', 'is_admin') 79 | 80 | def clean_password(self): 81 | # Regardless of what the user provides, return the initial value. 82 | # This is done here, rather than on the field, because the 83 | # field does not have access to the initial value 84 | return self.initial["password"] 85 | 86 | 87 | -------------------------------------------------------------------------------- /src/accounts/migrations/0001_initial.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.10.2 on 2016-10-29 20:23 3 | from __future__ import unicode_literals 4 | 5 | import django.core.validators 6 | from django.db import migrations, models 7 | 8 | 9 | class Migration(migrations.Migration): 10 | 11 | initial = True 12 | 13 | dependencies = [ 14 | ] 15 | 16 | operations = [ 17 | migrations.CreateModel( 18 | name='MyUser', 19 | fields=[ 20 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 21 | ('password', models.CharField(max_length=128, verbose_name='password')), 22 | ('last_login', models.DateTimeField(blank=True, null=True, verbose_name='last login')), 23 | ('username', models.CharField(max_length=255, unique=True, validators=[django.core.validators.RegexValidator(code='invalid_username', message='Username must be Alpahnumeric or contain any of the following: ". @ + -" ', regex='^[a-zA-Z0-9.@+-]*$')])), 24 | ('email', models.EmailField(max_length=255, unique=True, verbose_name='email address')), 25 | ('is_active', models.BooleanField(default=True)), 26 | ('is_staff', models.BooleanField(default=False)), 27 | ('is_admin', models.BooleanField(default=False)), 28 | ], 29 | options={ 30 | 'abstract': False, 31 | }, 32 | ), 33 | ] 34 | -------------------------------------------------------------------------------- /src/accounts/migrations/0002_myuser_zipcode.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.10.2 on 2016-10-29 20:28 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations, models 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('accounts', '0001_initial'), 12 | ] 13 | 14 | operations = [ 15 | migrations.AddField( 16 | model_name='myuser', 17 | name='zipcode', 18 | field=models.CharField(default='92660', max_length=120), 19 | ), 20 | ] 21 | -------------------------------------------------------------------------------- /src/accounts/migrations/0003_profile.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.10.2 on 2016-10-29 20:30 3 | from __future__ import unicode_literals 4 | 5 | from django.conf import settings 6 | from django.db import migrations, models 7 | import django.db.models.deletion 8 | 9 | 10 | class Migration(migrations.Migration): 11 | 12 | dependencies = [ 13 | ('accounts', '0002_myuser_zipcode'), 14 | ] 15 | 16 | operations = [ 17 | migrations.CreateModel( 18 | name='Profile', 19 | fields=[ 20 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 21 | ('city', models.CharField(blank=True, max_length=120, null=True)), 22 | ('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), 23 | ], 24 | ), 25 | ] 26 | -------------------------------------------------------------------------------- /src/accounts/migrations/0004_auto_20161029_2115.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.10.2 on 2016-10-29 21:15 3 | from __future__ import unicode_literals 4 | 5 | import django.core.validators 6 | from django.db import migrations, models 7 | 8 | 9 | class Migration(migrations.Migration): 10 | 11 | dependencies = [ 12 | ('accounts', '0003_profile'), 13 | ] 14 | 15 | operations = [ 16 | migrations.AlterField( 17 | model_name='myuser', 18 | name='username', 19 | field=models.CharField(max_length=255, unique=True, validators=[django.core.validators.RegexValidator(code='invalid_username', message='Username must be Alpahnumeric or contain any of the following: ". @ + -" ', regex='^[a-zA-Z0-9.+-]*$')]), 20 | ), 21 | ] 22 | -------------------------------------------------------------------------------- /src/accounts/migrations/0005_activationprofile.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.10.2 on 2016-10-29 21:37 3 | from __future__ import unicode_literals 4 | 5 | from django.conf import settings 6 | from django.db import migrations, models 7 | import django.db.models.deletion 8 | 9 | 10 | class Migration(migrations.Migration): 11 | 12 | dependencies = [ 13 | ('accounts', '0004_auto_20161029_2115'), 14 | ] 15 | 16 | operations = [ 17 | migrations.CreateModel( 18 | name='ActivationProfile', 19 | fields=[ 20 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 21 | ('key', models.CharField(max_length=120)), 22 | ('expired', models.BooleanField(default=False)), 23 | ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), 24 | ], 25 | ), 26 | ] 27 | -------------------------------------------------------------------------------- /src/accounts/migrations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codingforentrepreneurs/Django-User-Model-Unleashed/11e57778d67d4c3356fc6dfda52c8210f29af296/src/accounts/migrations/__init__.py -------------------------------------------------------------------------------- /src/accounts/models.py: -------------------------------------------------------------------------------- 1 | from django.conf import settings 2 | from django.contrib.auth.models import ( 3 | BaseUserManager, AbstractBaseUser 4 | ) 5 | from django.core.validators import RegexValidator 6 | from django.db import models 7 | from django.db.models.signals import post_save 8 | # Create your models here. 9 | from .utils import code_generator 10 | 11 | USERNAME_REGEX = '^[a-zA-Z0-9.+-]*$' 12 | 13 | class MyUserManager(BaseUserManager): 14 | def create_user(self, username, email, password=None): 15 | """ 16 | Creates and saves a User with the given email, date of 17 | birth and password. 18 | """ 19 | if not email: 20 | raise ValueError('Users must have an email address') 21 | 22 | user = self.model( 23 | username = username, 24 | email=self.normalize_email(email), 25 | ) 26 | 27 | user.set_password(password) 28 | user.save(using=self._db) 29 | return user 30 | 31 | def create_superuser(self, username, email, password): 32 | """ 33 | Creates and saves a superuser with the given email, date of 34 | birth and password. 35 | """ 36 | user = self.create_user( 37 | username, 38 | email, 39 | password=password, 40 | ) 41 | user.is_admin = True 42 | user.is_staff = True 43 | user.save(using=self._db) 44 | return user 45 | 46 | 47 | 48 | 49 | 50 | 51 | class MyUser(AbstractBaseUser): 52 | username = models.CharField( 53 | max_length=255, 54 | validators=[ 55 | RegexValidator( 56 | regex = USERNAME_REGEX, 57 | message = 'Username must be Alpahnumeric or contain any of the following: ". @ + -" ', 58 | code='invalid_username' 59 | )], 60 | unique=True, 61 | ) 62 | email = models.EmailField( 63 | verbose_name='email address', 64 | max_length=255, 65 | unique=True, 66 | ) 67 | zipcode = models.CharField(max_length=120, default="92660") 68 | is_active = models.BooleanField(default=True) 69 | is_staff = models.BooleanField(default=False) 70 | is_admin = models.BooleanField(default=False) 71 | 72 | objects = MyUserManager() 73 | 74 | USERNAME_FIELD = 'username' 75 | REQUIRED_FIELDS = ['email'] 76 | 77 | def get_full_name(self): 78 | # The user is identified by their email address 79 | return self.email 80 | 81 | def get_short_name(self): 82 | # The user is identified by their email address 83 | return self.email 84 | 85 | def __str__(self): # __unicode__ on Python 2 86 | return self.email 87 | 88 | def has_perm(self, perm, obj=None): 89 | "Does the user have a specific permission?" 90 | # Simplest possible answer: Yes, always 91 | return True 92 | 93 | def has_module_perms(self, app_label): 94 | "Does the user have permissions to view the app `app_label`?" 95 | # Simplest possible answer: Yes, always 96 | return True 97 | 98 | # @property 99 | # def is_staff(self): 100 | # "Is the user a member of staff?" 101 | # # Simplest possible answer: All admins are staff 102 | # return self.is_admin 103 | 104 | 105 | 106 | class ActivationProfile(models.Model): 107 | user = models.ForeignKey(settings.AUTH_USER_MODEL) 108 | key = models.CharField(max_length=120) 109 | expired = models.BooleanField(default=False) 110 | 111 | def save(self, *args, **kwargs): 112 | self.key = code_generator() 113 | super(ActivationProfile, self).save(*args, **kwargs) 114 | 115 | 116 | def post_save_activation_receiver(sender, instance, created, *args, **kwargs): 117 | if created: 118 | #send email 119 | print('activation created') 120 | 121 | post_save.connect(post_save_activation_receiver, sender=ActivationProfile) 122 | 123 | 124 | 125 | 126 | class Profile(models.Model): 127 | user = models.OneToOneField(settings.AUTH_USER_MODEL) 128 | city = models.CharField(max_length=120, null=True, blank=True) 129 | 130 | def __str__(self): 131 | return str(self.user.username) 132 | 133 | def __unicode__(self): 134 | return str(self.user.username) 135 | 136 | 137 | def post_save_user_model_receiver(sender, instance, created, *args, **kwargs): 138 | if created: 139 | try: 140 | Profile.objects.create(user=instance) 141 | ActivationProfile.objects.create(user=instance) 142 | except: 143 | pass 144 | 145 | post_save.connect(post_save_user_model_receiver, sender=settings.AUTH_USER_MODEL) 146 | -------------------------------------------------------------------------------- /src/accounts/templates/accounts/form.html: -------------------------------------------------------------------------------- 1 |
{% csrf_token %} 2 | {{ form.as_p }} 3 | 4 |
-------------------------------------------------------------------------------- /src/accounts/templates/accounts/login.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | 3 | 4 | {% block content %} 5 |

Login

6 | {% include "accounts/form.html" with form=form %} 7 | 8 | {% endblock %} -------------------------------------------------------------------------------- /src/accounts/templates/accounts/register.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | 3 | 4 | {% block content %} 5 |

Register

6 | {% include "accounts/form.html" with form=form %} 7 | 8 | {% endblock %} -------------------------------------------------------------------------------- /src/accounts/templates/base.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | {% block content %} 9 | 10 | {% endblock %} 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /src/accounts/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | # Create your tests here. 4 | -------------------------------------------------------------------------------- /src/accounts/utils.py: -------------------------------------------------------------------------------- 1 | import random 2 | import string 3 | 4 | from django.conf import settings 5 | 6 | 7 | SHORTCODE_MIN = getattr(settings, "SHORTCODE_MIN", 15) 8 | 9 | #from shortener.models import KirrURL 10 | 11 | def code_generator(size=SHORTCODE_MIN, chars=string.ascii_lowercase + string.digits): 12 | # new_code = '' 13 | # for _ in range(size): 14 | # new_code += random.choice(chars) 15 | # return new_code 16 | return ''.join(random.choice(chars) for _ in range(size)) 17 | -------------------------------------------------------------------------------- /src/accounts/views.py: -------------------------------------------------------------------------------- 1 | from django.contrib.auth import login, get_user_model, logout 2 | from django.http import HttpResponseRedirect, Http404 3 | from django.shortcuts import render 4 | 5 | # Create your views here. 6 | 7 | User = get_user_model() 8 | 9 | from .forms import UserCreationForm, UserLoginForm 10 | from .models import ActivationProfile 11 | 12 | 13 | def home(request): 14 | if request.user.is_authenticated(): 15 | print(request.user.profile.city) 16 | return render(request, "base.html", {}) 17 | 18 | 19 | 20 | def register(request, *args, **kwargs): 21 | form = UserCreationForm(request.POST or None) 22 | if form.is_valid(): 23 | form.save() 24 | return HttpResponseRedirect("/login") 25 | return render(request, "accounts/register.html", {"form": form}) 26 | 27 | 28 | def login_view(request, *args, **kwargs): 29 | form = UserLoginForm(request.POST or None) 30 | if form.is_valid(): 31 | user_obj = form.cleaned_data.get('user_obj') 32 | login(request, user_obj) 33 | return HttpResponseRedirect("/") 34 | return render(request, "accounts/login.html", {"form": form}) 35 | 36 | 37 | def logout_view(request): 38 | logout(request) 39 | return HttpResponseRedirect("/login") 40 | 41 | 42 | def activate_user_view(request, code=None, *args, **kwargs): 43 | if code: 44 | act_profile_qs = ActivationProfile.objects.filter(key=code) 45 | if act_profile_qs.exists() and act_profile_qs.count() == 1: 46 | act_obj = act_profile_qs.first() 47 | if not act_obj.expired: 48 | user_obj = act_obj.user 49 | user_obj.is_active = True 50 | user_obj.save() 51 | act_obj.expired = True 52 | act_obj.save() 53 | return HttpResponseRedirect("/login") 54 | # invalid code 55 | return HttpResponseRedirect("/login") 56 | 57 | 58 | 59 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /src/db.sqlite3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codingforentrepreneurs/Django-User-Model-Unleashed/11e57778d67d4c3356fc6dfda52c8210f29af296/src/db.sqlite3 -------------------------------------------------------------------------------- /src/djuser/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codingforentrepreneurs/Django-User-Model-Unleashed/11e57778d67d4c3356fc6dfda52c8210f29af296/src/djuser/__init__.py -------------------------------------------------------------------------------- /src/djuser/settings.py: -------------------------------------------------------------------------------- 1 | """ 2 | Django settings for djuser project. 3 | 4 | Generated by 'django-admin startproject' using Django 1.10.2. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/1.10/topics/settings/ 8 | 9 | For the full list of settings and their values, see 10 | https://docs.djangoproject.com/en/1.10/ref/settings/ 11 | """ 12 | 13 | import os 14 | 15 | # Build paths inside the project like this: os.path.join(BASE_DIR, ...) 16 | BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) 17 | 18 | 19 | # Quick-start development settings - unsuitable for production 20 | # See https://docs.djangoproject.com/en/1.10/howto/deployment/checklist/ 21 | 22 | # SECURITY WARNING: keep the secret key used in production secret! 23 | SECRET_KEY = '493cj9hpc$n6$$jyo!w_47-!o+^yu--7uq7g4*#xo+bhdgu&i1' 24 | 25 | # SECURITY WARNING: don't run with debug turned on in production! 26 | DEBUG = True 27 | 28 | ALLOWED_HOSTS = [] 29 | 30 | 31 | # Application definition 32 | 33 | INSTALLED_APPS = [ 34 | 'django.contrib.admin', 35 | 'django.contrib.auth', 36 | 'django.contrib.contenttypes', 37 | 'django.contrib.sessions', 38 | 'django.contrib.messages', 39 | 'django.contrib.staticfiles', 40 | 41 | 'accounts', 42 | ] 43 | 44 | 45 | AUTH_USER_MODEL = 'accounts.MyUser' 46 | 47 | MIDDLEWARE = [ 48 | 'django.middleware.security.SecurityMiddleware', 49 | 'django.contrib.sessions.middleware.SessionMiddleware', 50 | 'django.middleware.common.CommonMiddleware', 51 | 'django.middleware.csrf.CsrfViewMiddleware', 52 | 'django.contrib.auth.middleware.AuthenticationMiddleware', 53 | 'django.contrib.messages.middleware.MessageMiddleware', 54 | 'django.middleware.clickjacking.XFrameOptionsMiddleware', 55 | ] 56 | 57 | ROOT_URLCONF = 'djuser.urls' 58 | 59 | TEMPLATES = [ 60 | { 61 | 'BACKEND': 'django.template.backends.django.DjangoTemplates', 62 | 'DIRS': [], 63 | 'APP_DIRS': True, 64 | 'OPTIONS': { 65 | 'context_processors': [ 66 | 'django.template.context_processors.debug', 67 | 'django.template.context_processors.request', 68 | 'django.contrib.auth.context_processors.auth', 69 | 'django.contrib.messages.context_processors.messages', 70 | ], 71 | }, 72 | }, 73 | ] 74 | 75 | WSGI_APPLICATION = 'djuser.wsgi.application' 76 | 77 | 78 | # Database 79 | # https://docs.djangoproject.com/en/1.10/ref/settings/#databases 80 | 81 | DATABASES = { 82 | 'default': { 83 | 'ENGINE': 'django.db.backends.sqlite3', 84 | 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), 85 | } 86 | } 87 | 88 | 89 | # Password validation 90 | # https://docs.djangoproject.com/en/1.10/ref/settings/#auth-password-validators 91 | 92 | AUTH_PASSWORD_VALIDATORS = [ 93 | { 94 | 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', 95 | }, 96 | { 97 | 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', 98 | }, 99 | { 100 | 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', 101 | }, 102 | { 103 | 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', 104 | }, 105 | ] 106 | 107 | 108 | # Internationalization 109 | # https://docs.djangoproject.com/en/1.10/topics/i18n/ 110 | 111 | LANGUAGE_CODE = 'en-us' 112 | 113 | TIME_ZONE = 'UTC' 114 | 115 | USE_I18N = True 116 | 117 | USE_L10N = True 118 | 119 | USE_TZ = True 120 | 121 | 122 | # Static files (CSS, JavaScript, Images) 123 | # https://docs.djangoproject.com/en/1.10/howto/static-files/ 124 | 125 | STATIC_URL = '/static/' 126 | -------------------------------------------------------------------------------- /src/djuser/urls.py: -------------------------------------------------------------------------------- 1 | """djuser URL Configuration 2 | 3 | The `urlpatterns` list routes URLs to views. For more information please see: 4 | https://docs.djangoproject.com/en/1.10/topics/http/urls/ 5 | Examples: 6 | Function views 7 | 1. Add an import: from my_app import views 8 | 2. Add a URL to urlpatterns: url(r'^$', views.home, name='home') 9 | Class-based views 10 | 1. Add an import: from other_app.views import Home 11 | 2. Add a URL to urlpatterns: url(r'^$', Home.as_view(), name='home') 12 | Including another URLconf 13 | 1. Import the include() function: from django.conf.urls import url, include 14 | 2. Add a URL to urlpatterns: url(r'^blog/', include('blog.urls')) 15 | """ 16 | from django.conf.urls import url 17 | from django.contrib import admin 18 | 19 | 20 | from accounts.views import activate_user_view, home, register, login_view, logout_view 21 | 22 | urlpatterns = [ 23 | url(r'^$', home), 24 | url(r'^admin/', admin.site.urls), 25 | url(r'^register/$', register), 26 | url(r'^login/$', login_view), 27 | url(r'^logout/$', logout_view), 28 | url(r'^activate/(?P[a-z0-9].*)/$', activate_user_view), 29 | ] 30 | -------------------------------------------------------------------------------- /src/djuser/wsgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | WSGI config for djuser project. 3 | 4 | It exposes the WSGI callable as a module-level variable named ``application``. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/1.10/howto/deployment/wsgi/ 8 | """ 9 | 10 | import os 11 | 12 | from django.core.wsgi import get_wsgi_application 13 | 14 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "djuser.settings") 15 | 16 | application = get_wsgi_application() 17 | -------------------------------------------------------------------------------- /src/manage.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import os 3 | import sys 4 | 5 | if __name__ == "__main__": 6 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "djuser.settings") 7 | try: 8 | from django.core.management import execute_from_command_line 9 | except ImportError: 10 | # The above import may fail for some other reason. Ensure that the 11 | # issue is really that Django is missing to avoid masking other 12 | # exceptions on Python 2. 13 | try: 14 | import django 15 | except ImportError: 16 | raise ImportError( 17 | "Couldn't import Django. Are you sure it's installed and " 18 | "available on your PYTHONPATH environment variable? Did you " 19 | "forget to activate a virtual environment?" 20 | ) 21 | raise 22 | execute_from_command_line(sys.argv) 23 | --------------------------------------------------------------------------------