项目作者: mramshaw

项目描述 :
Django Hello World (Django 2 version)
高级语言: Python
项目地址: git://github.com/mramshaw/Writing_Django_2.git
创建时间: 2019-11-26T13:45:27Z
项目社区:https://github.com/mramshaw/Writing_Django_2

开源协议:

下载


Writing Django 2

Known Vulnerabilities

Having investigated Django 1 with Python 2 it seemed
time to investigate Django 2 with Python 3, mainly because Python 2 support ends in 2020.

[As my initial exercise was pretty straightforward, rather than try to update that repo, I will
simply recreate the whole exercise with Django 2 and Python 3. For more details, please refer to
the original repo.]

Django LTS

Note that we will use the LTS version of Django 2, which at the time of writing (November 2019)
is 2.2.7.

This release requires Python 3.5 or more recent.

Python 3

Verify the version of Python as follows:

  1. $ python3 --version
  2. Python 3.5.2
  3. $

[I have both Python 2 and Python 3 installed. On my system, Python 2 is python
while Python 3 is python3. Likewise Python 2 uses pip while Python 3
uses pip3. In the instructions that follows I will use python3 and
pip3 but these may be replaced with python and pip for
systems where only Python 3 is installed.]

Prerequisites

Install the latest version of Django (plus dependencies) as follows:

  1. $ pip3 install --user -r requirements.txt

Verify the installed version of Django as follows:

  1. $ python3 -m django --version
  2. 2.2.7
  3. $

Create a Project

Use the django-admin command to do this:

  1. $ django-admin startproject polls

And time to see if everything works so far:

  1. $ cd polls
  2. $ python3 manage.py runserver

The results should be something like:

  1. $ python3 manage.py runserver
  2. Watching for file changes with StatReloader
  3. Performing system checks...
  4. System check identified no issues (0 silenced).
  5. You have 17 unapplied migration(s). Your project may not work properly until you apply the migrations for app(s): admin, auth, contenttypes, sessions.
  6. Run 'python manage.py migrate' to apply them.
  7. November 26, 2019 - 16:48:54
  8. Django version 2.2.7, using settings 'polls.settings'
  9. Starting development server at http://127.0.0.1:8000/
  10. Quit the server with CONTROL-C.
  11. [26/Nov/2019 16:49:27] "GET / HTTP/1.1" 200 16348
  12. [26/Nov/2019 16:49:28] "GET /static/admin/css/fonts.css HTTP/1.1" 200 423
  13. [26/Nov/2019 16:49:28] "GET /static/admin/fonts/Roboto-Bold-webfont.woff HTTP/1.1" 200 86184
  14. [26/Nov/2019 16:49:28] "GET /static/admin/fonts/Roboto-Regular-webfont.woff HTTP/1.1" 200 85876
  15. [26/Nov/2019 16:49:28] "GET /static/admin/fonts/Roboto-Light-webfont.woff HTTP/1.1" 200 85692
  16. Not Found: /favicon.ico
  17. [26/Nov/2019 16:49:28] "GET /favicon.ico HTTP/1.1" 404 1971
  18. ^C$

The development server at http://127.0.0.1:8000/ should look something like:

Development_Server

Create an App

This needs to be done in the folder where manage.py lives:

  1. $ python3 manage.py startapp polls_app

Create a View

Open polls_app/views.py and change it as follows:

  1. $ git diff polls_app/views.py
  2. diff --git a/polls/polls_app/views.py b/polls/polls_app/views.py
  3. index 91ea44a..d2dfb9f 100644
  4. --- a/polls/polls_app/views.py
  5. +++ b/polls/polls_app/views.py
  6. @@ -1,3 +1,7 @@
  7. from django.shortcuts import render
  8. -# Create your views here.
  9. +from django.http import HttpResponse
  10. +
  11. +
  12. +def index(request):
  13. + return HttpResponse("Hello, world. You're at the polls index.")
  14. $

[Note that render may not be required yet, but we will leave it.]

Create a polls_app/urls.py file as follows:

  1. from django.urls import path
  2. from . import views
  3. urlpatterns = [
  4. path('', views.index, name='index'),
  5. ]

Next update the polls/urls.py file as follows:

  1. $ git diff polls/urls.py
  2. diff --git a/polls/polls/urls.py b/polls/polls/urls.py
  3. index c8c9627..9be9eec 100644
  4. --- a/polls/polls/urls.py
  5. +++ b/polls/polls/urls.py
  6. @@ -14,8 +14,9 @@ Including another URLconf
  7. 2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
  8. """
  9. from django.contrib import admin
  10. -from django.urls import path
  11. +from django.urls import include, path
  12. urlpatterns = [
  13. + path('polls/', include('polls_app.urls')),
  14. path('admin/', admin.site.urls),
  15. ]
  16. $

Again, lets check to see if everything works:

  1. $ python3 manage.py runserver
  2. Watching for file changes with StatReloader
  3. Performing system checks...
  4. System check identified no issues (0 silenced).
  5. You have 17 unapplied migration(s). Your project may not work properly until you apply the migrations for app(s): admin, auth, contenttypes, sessions.
  6. Run 'python manage.py migrate' to apply them.
  7. November 26, 2019 - 18:06:31
  8. Django version 2.2.7, using settings 'polls.settings'
  9. Starting development server at http://127.0.0.1:8000/
  10. Quit the server with CONTROL-C.
  11. [26/Nov/2019 18:06:53] "GET /polls/ HTTP/1.1" 200 40
  12. [26/Nov/2019 18:07:03] "GET /admin/ HTTP/1.1" 302 0
  13. [26/Nov/2019 18:07:03] "GET /admin/login/?next=/admin/ HTTP/1.1" 200 1819
  14. [26/Nov/2019 18:07:03] "GET /static/admin/css/base.css HTTP/1.1" 200 16378
  15. [26/Nov/2019 18:07:03] "GET /static/admin/css/login.css HTTP/1.1" 200 1233
  16. [26/Nov/2019 18:07:03] "GET /static/admin/css/responsive.css HTTP/1.1" 200 17944
  17. Not Found: /
  18. [26/Nov/2019 18:07:16] "GET / HTTP/1.1" 404 2026
  19. ^C$

The polls app at http://127.0.0.1:8000/polls/ should look as follows:

polls

The admin interface at http://127.0.0.1:8000/admin/ should look as follows:

admin

And our development server at http://127.0.0.1:8000/ should now look like:

404

[END OF PART 1]

[START OF PART 2]

Database setup

We will stick with the default sqlite3 database. We will also leave our timezone as UTC.

So lets run our database migrations:

  1. $ python3 manage.py migrate
  2. Operations to perform:
  3. Apply all migrations: admin, auth, contenttypes, sessions
  4. Running migrations:
  5. Applying contenttypes.0001_initial... OK
  6. Applying auth.0001_initial... OK
  7. Applying admin.0001_initial... OK
  8. Applying admin.0002_logentry_remove_auto_add... OK
  9. Applying admin.0003_logentry_add_action_flag_choices... OK
  10. Applying contenttypes.0002_remove_content_type_name... OK
  11. Applying auth.0002_alter_permission_name_max_length... OK
  12. Applying auth.0003_alter_user_email_max_length... OK
  13. Applying auth.0004_alter_user_username_opts... OK
  14. Applying auth.0005_alter_user_last_login_null... OK
  15. Applying auth.0006_require_contenttypes_0002... OK
  16. Applying auth.0007_alter_validators_add_error_messages... OK
  17. Applying auth.0008_alter_user_username_max_length... OK
  18. Applying auth.0009_alter_user_last_name_max_length... OK
  19. Applying auth.0010_alter_group_name_max_length... OK
  20. Applying auth.0011_update_proxy_permissions... OK
  21. Applying sessions.0001_initial... OK
  22. $

Model Creation

Now lets create our models - update polls_app/models.py as follows:

  1. $ git diff polls_app/models.py
  2. diff --git a/polls/polls_app/models.py b/polls/polls_app/models.py
  3. index 71a8362..48780e6 100644
  4. --- a/polls/polls_app/models.py
  5. +++ b/polls/polls_app/models.py
  6. @@ -1,3 +1,12 @@
  7. from django.db import models
  8. -# Create your models here.
  9. +
  10. +class Question(models.Model):
  11. + question_text = models.CharField(max_length=200)
  12. + pub_date = models.DateTimeField('date published')
  13. +
  14. +
  15. +class Choice(models.Model):
  16. + question = models.ForeignKey(Question, on_delete=models.CASCADE)
  17. + choice_text = models.CharField(max_length=200)
  18. + votes = models.IntegerField(default=0)
  19. $

Model Activation

Now lets activate our models - update polls/settings.py as follows:

  1. $ git diff polls/settings.py
  2. diff --git a/polls/polls/settings.py b/polls/polls/settings.py
  3. index c2d9e83..f7170c2 100644
  4. --- a/polls/polls/settings.py
  5. +++ b/polls/polls/settings.py
  6. @@ -31,6 +31,7 @@ ALLOWED_HOSTS = []
  7. # Application definition
  8. INSTALLED_APPS = [
  9. + 'polls_app.apps.PollsAppConfig',
  10. 'django.contrib.admin',
  11. 'django.contrib.auth',
  12. 'django.contrib.contenttypes',
  13. $

And lets create our migrations:

  1. $ python3 manage.py makemigrations polls_app
  2. Migrations for 'polls_app':
  3. polls_app/migrations/0001_initial.py
  4. - Create model Question
  5. - Create model Choice
  6. $

[If we wished, we could inspect our migration at this point.]

Check for issues:

  1. $ python3 manage.py check
  2. System check identified no issues (0 silenced).
  3. $

Apply our migrations:

  1. $ python3 manage.py migrate
  2. Operations to perform:
  3. Apply all migrations: admin, auth, contenttypes, polls_app, sessions
  4. Running migrations:
  5. Applying polls_app.0001_initial... OK
  6. $

Examine our migrations:

  1. $ python3 manage.py showmigrations
  2. admin
  3. [X] 0001_initial
  4. [X] 0002_logentry_remove_auto_add
  5. [X] 0003_logentry_add_action_flag_choices
  6. auth
  7. [X] 0001_initial
  8. [X] 0002_alter_permission_name_max_length
  9. [X] 0003_alter_user_email_max_length
  10. [X] 0004_alter_user_username_opts
  11. [X] 0005_alter_user_last_login_null
  12. [X] 0006_require_contenttypes_0002
  13. [X] 0007_alter_validators_add_error_messages
  14. [X] 0008_alter_user_username_max_length
  15. [X] 0009_alter_user_last_name_max_length
  16. [X] 0010_alter_group_name_max_length
  17. [X] 0011_update_proxy_permissions
  18. contenttypes
  19. [X] 0001_initial
  20. [X] 0002_remove_content_type_name
  21. polls_app
  22. [X] 0001_initial
  23. sessions
  24. [X] 0001_initial
  25. $

Create some questions

This should look as follows (I have IPython installed so this will be verbose):

  1. $ python3 manage.py shell
  2. Python 3.5.2 (default, Oct 8 2019, 13:06:37)
  3. Type 'copyright', 'credits' or 'license' for more information
  4. IPython 7.2.0 -- An enhanced Interactive Python. Type '?' for help.
  5. In [1]: from polls_app.models import Question, Choice
  6. In [2]: Question.objects.all()
  7. Out[2]: <QuerySet []>
  8. In [3]: from django.utils import timezone
  9. In [4]: q = Question(question_text="What's new?", pub_date=timezone.now())
  10. In [5]: q.save()
  11. In [6]: q.id
  12. Out[6]: 1
  13. In [7]: Question.objects.all()
  14. Out[7]: <QuerySet [<Question: Question object (1)>]>
  15. In [8]: quit()
  16. $

For convenience lets add string methods to our models:

  1. $ git diff polls_app/models.py
  2. diff --git a/polls/polls_app/models.py b/polls/polls_app/models.py
  3. index 48780e6..4855206 100644
  4. --- a/polls/polls_app/models.py
  5. +++ b/polls/polls_app/models.py
  6. @@ -4,9 +4,13 @@ from django.db import models
  7. class Question(models.Model):
  8. question_text = models.CharField(max_length=200)
  9. pub_date = models.DateTimeField('date published')
  10. + def __str__(self):
  11. + return self.question_text
  12. class Choice(models.Model):
  13. question = models.ForeignKey(Question, on_delete=models.CASCADE)
  14. choice_text = models.CharField(max_length=200)
  15. votes = models.IntegerField(default=0)
  16. + def __str__(self):
  17. + return self.choice_text
  18. $

Now if we restart our API shell, we get more readable results:

  1. $ python3 manage.py shell
  2. Python 3.5.2 (default, Oct 8 2019, 13:06:37)
  3. Type 'copyright', 'credits' or 'license' for more information
  4. IPython 7.2.0 -- An enhanced Interactive Python. Type '?' for help.
  5. In [1]: from polls_app.models import Question, Choice
  6. In [2]: Question.objects.all()
  7. Out[2]: <QuerySet [<Question: What's new?>]>
  8. In [3]:

Lets add some answers:

  1. In [3]: q = Question.objects.get(pk=1)
  2. In [4]: q.choice_set.all()
  3. Out[4]: <QuerySet []>
  4. In [5]: q.choice_set.create(choice_text='Not much', votes=0)
  5. Out[5]: <Choice: Not much>
  6. In [6]: q.choice_set.create(choice_text='The sky', votes=0)
  7. Out[6]: <Choice: The sky>
  8. In [7]: q.choice_set.create(choice_text='Taxes', votes=0)
  9. Out[7]: <Choice: Taxes>
  10. In [8]: q.choice_set.all()
  11. Out[8]: <QuerySet [<Choice: Not much>, <Choice: The sky>, <Choice: Taxes>]>
  12. In [9]: q.choice_set.count()
  13. Out[9]: 3
  14. In [10]: quit
  15. $

Admin Creation

Lets create an Admin user:

  1. $ python3 manage.py createsuperuser
  2. Username (leave blank to use 'owner'): admin
  3. Email address: admin@example.com
  4. Password:
  5. Password (again):
  6. Superuser created successfully.
  7. $

[Password is 123abcde.]

Admin Interface

Lets start the server and see if we can log in:

  1. $ python3 manage.py runserver
  2. Watching for file changes with StatReloader
  3. Performing system checks...
  4. System check identified no issues (0 silenced).
  5. November 26, 2019 - 19:51:08
  6. Django version 2.2.7, using settings 'polls.settings'
  7. Starting development server at http://127.0.0.1:8000/
  8. Quit the server with CONTROL-C.
  9. [26/Nov/2019 19:51:21] "GET /admin/ HTTP/1.1" 302 0
  10. [26/Nov/2019 19:51:21] "GET /admin/login/?next=/admin/ HTTP/1.1" 200 1819
  11. [26/Nov/2019 19:51:21] "GET /static/admin/css/fonts.css HTTP/1.1" 304 0
  12. [26/Nov/2019 19:51:21] "GET /static/admin/fonts/Roboto-Regular-webfont.woff HTTP/1.1" 304 0
  13. [26/Nov/2019 19:51:21] "GET /static/admin/fonts/Roboto-Light-webfont.woff HTTP/1.1" 304 0
  14. [26/Nov/2019 19:52:05] "POST /admin/login/?next=/admin/ HTTP/1.1" 302 0
  15. [26/Nov/2019 19:52:05] "GET /admin/ HTTP/1.1" 200 3042
  16. [26/Nov/2019 19:52:05] "GET /static/admin/css/dashboard.css HTTP/1.1" 200 412
  17. [26/Nov/2019 19:52:05] "GET /static/admin/img/icon-addlink.svg HTTP/1.1" 200 331
  18. [26/Nov/2019 19:52:05] "GET /static/admin/img/icon-changelink.svg HTTP/1.1" 200 380
  19. [26/Nov/2019 19:52:05] "GET /static/admin/fonts/Roboto-Bold-webfont.woff HTTP/1.1" 304 0
  20. ^C$

The logged-in interface at http://127.0.0.1:8000/admin/ should look as follows:

Admin_UI

We need to modify polls_app/admin.py to register Question as follows:

  1. $ git diff polls_app/admin.py
  2. diff --git a/polls/polls_app/admin.py b/polls/polls_app/admin.py
  3. index 8c38f3f..6af8ff6 100644
  4. --- a/polls/polls_app/admin.py
  5. +++ b/polls/polls_app/admin.py
  6. @@ -1,3 +1,5 @@
  7. from django.contrib import admin
  8. -# Register your models here.
  9. +from .models import Question
  10. +
  11. +admin.site.register(Question)
  12. $

Restart our server:

  1. $ python3 manage.py runserver
  2. Watching for file changes with StatReloader
  3. Performing system checks...
  4. System check identified no issues (0 silenced).
  5. November 26, 2019 - 20:00:15
  6. Django version 2.2.7, using settings 'polls.settings'
  7. Starting development server at http://127.0.0.1:8000/
  8. Quit the server with CONTROL-C.
  9. [26/Nov/2019 20:00:21] "GET /admin/ HTTP/1.1" 200 3749
  10. [26/Nov/2019 20:01:54] "GET /admin/polls_app/question/ HTTP/1.1" 200 4374
  11. [26/Nov/2019 20:01:54] "GET /static/admin/css/changelists.css HTTP/1.1" 200 6170
  12. [26/Nov/2019 20:01:54] "GET /admin/jsi18n/ HTTP/1.1" 200 3223
  13. [26/Nov/2019 20:01:54] "GET /static/admin/js/jquery.init.js HTTP/1.1" 200 363
  14. [26/Nov/2019 20:01:54] "GET /static/admin/js/actions.js HTTP/1.1" 200 6766
  15. [26/Nov/2019 20:01:54] "GET /static/admin/js/core.js HTTP/1.1" 200 7099
  16. [26/Nov/2019 20:01:54] "GET /static/admin/js/urlify.js HTTP/1.1" 200 8941
  17. [26/Nov/2019 20:01:54] "GET /static/admin/js/admin/RelatedObjectLookups.js HTTP/1.1" 200 6918
  18. [26/Nov/2019 20:01:54] "GET /static/admin/js/vendor/jquery/jquery.js HTTP/1.1" 200 271817
  19. [26/Nov/2019 20:01:54] "GET /static/admin/js/vendor/xregexp/xregexp.js HTTP/1.1" 200 128820
  20. [26/Nov/2019 20:01:54] "GET /static/admin/js/prepopulate.js HTTP/1.1" 200 1530
  21. [26/Nov/2019 20:01:54] "GET /static/admin/img/tooltag-add.svg HTTP/1.1" 200 331
  22. [26/Nov/2019 20:13:32] "GET /static/admin/css/forms.css HTTP/1.1" 200 8518
  23. [26/Nov/2019 20:13:32] "GET /static/admin/js/change_form.js HTTP/1.1" 200 712
  24. [26/Nov/2019 20:13:32] "GET /static/admin/js/calendar.js HTTP/1.1" 200 7777
  25. [26/Nov/2019 20:13:32] "GET /static/admin/js/prepopulate_init.js HTTP/1.1" 200 495
  26. [26/Nov/2019 20:13:32] "GET /static/admin/js/admin/DateTimeShortcuts.js HTTP/1.1" 200 20218
  27. [26/Nov/2019 20:13:32] "GET /static/admin/css/widgets.css HTTP/1.1" 200 10340
  28. [26/Nov/2019 20:13:32] "GET /static/admin/img/icon-calendar.svg HTTP/1.1" 200 1086
  29. [26/Nov/2019 20:13:32] "GET /static/admin/img/icon-clock.svg HTTP/1.1" 200 677
  30. [26/Nov/2019 20:17:52] "POST /admin/polls_app/question/1/change/ HTTP/1.1" 302 0
  31. [26/Nov/2019 20:17:52] "GET /admin/polls_app/question/ HTTP/1.1" 200 4572
  32. [26/Nov/2019 20:17:52] "GET /admin/jsi18n/ HTTP/1.1" 200 3223
  33. [26/Nov/2019 20:17:52] "GET /static/admin/img/icon-yes.svg HTTP/1.1" 200 436
  34. [26/Nov/2019 20:18:01] "GET /admin/polls_app/question/1/change/ HTTP/1.1" 200 5141
  35. [26/Nov/2019 20:18:02] "GET /admin/jsi18n/ HTTP/1.1" 200 3223
  36. [26/Nov/2019 20:18:05] "GET /admin/polls_app/question/1/history/ HTTP/1.1" 200 2319
  37. [26/Nov/2019 20:24:35] "GET /admin/logout/ HTTP/1.1" 200 1207
  38. ^C$

And if we refresh our browser window we should get:

Admin_UI_with_Questions

And now we can edit our Question:

Question

And we even get a modification history:

Question changelog

[END OF PART 2]

Versions

  • Django 2.2.7
  • Python 3.5.2

To Do

  • Follow parts 3 - 7 of this tutorial

Credits

Part 1:

  1. http://docs.djangoproject.com/en/2.2/intro/tutorial01/

Part 2:

  1. http://docs.djangoproject.com/en/2.2/intro/tutorial02/