{"id":20285411,"url":"https://github.com/mramshaw/writing_django","last_synced_at":"2026-05-19T04:11:14.978Z","repository":{"id":48962878,"uuid":"121170837","full_name":"mramshaw/Writing_Django","owner":"mramshaw","description":"Django Hello World","archived":false,"fork":false,"pushed_at":"2024-09-04T20:51:53.000Z","size":202,"stargazers_count":0,"open_issues_count":9,"forks_count":0,"subscribers_count":0,"default_branch":"master","last_synced_at":"2025-07-25T00:19:16.963Z","etag":null,"topics":["django","pip","python","sqlite3"],"latest_commit_sha":null,"homepage":null,"language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mramshaw.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-02-11T21:52:42.000Z","updated_at":"2019-11-26T14:58:44.000Z","dependencies_parsed_at":"2024-09-06T05:32:15.252Z","dependency_job_id":null,"html_url":"https://github.com/mramshaw/Writing_Django","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/mramshaw/Writing_Django","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mramshaw%2FWriting_Django","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mramshaw%2FWriting_Django/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mramshaw%2FWriting_Django/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mramshaw%2FWriting_Django/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mramshaw","download_url":"https://codeload.github.com/mramshaw/Writing_Django/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mramshaw%2FWriting_Django/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33201543,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-18T09:27:30.708Z","status":"online","status_checked_at":"2026-05-19T02:00:06.763Z","response_time":58,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["django","pip","python","sqlite3"],"created_at":"2024-11-14T14:26:30.650Z","updated_at":"2026-05-19T04:11:14.949Z","avatar_url":"https://github.com/mramshaw.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Writing Django\n\nPLEASE REFER TO http://github/mramshaw/Writing_Django_2 FOR A CURRENT VERSION OF DJANGO WITH PYTHON.\n\n[![Known Vulnerabilities](https://snyk.io/test/github/mramshaw/Writing_Django/badge.svg?style=plastic\u0026targetFile=requirements.txt)](https://snyk.io/test/github/mramshaw/Writing_Django?style=plastic\u0026targetFile=requirements.txt)\n\nHaving used the [Flask](http://flask.pocoo.org/) framework (it describes itself as a _microframework_)\nwith [SQLAlchemy](http://www.sqlalchemy.org/) for my [OAuth 2.0 repo](http://github.com/mramshaw/OAuth2.0),\nI thought it might be fun to check out Python's [Django](http://www.djangoproject.com/) framework.\n\nAs far as I can tell, it is a heavyweight MVC framework very much like PHP's [Laravel](http://laravel.com/).\nIt has its own ORM (for Flask there is SQLAlchemy but Django's ORM apparently does not play nicely with NoSQL\nsolutions such as [DynamoDB](http://aws.amazon.com/dynamodb/) or [MongoDB](http://www.mongodb.com/)).\n\n[For a more flexible option - somewhere between Flask and Django - there is [Pyramid](http://trypyramid.com/).\n Pyramid apparently can play nicely with DynamoDB/Mongo but doesn't have the fuller set of features of Django.\n Of course, if you are looking at NoSQL solutions you probably are not interested in an ORM anyway.]\n\n__tl;dr__ As with `pip` versus `npm` (where the similiarities seem to far outnumber any differences),\nthere are naming differences between `Django` and `Laravel` but the overall workflow and structure\nseems - perhaps not all that surprisingly - almost exactly the same.\n\n## Prerequisites\n\nPython is required, also a package manager (either `pip` or `pip3`) appropriate to the Python version.\n\nVerify the installed version of Python as follows:\n\n    $ python --version\n\n[Python 2.7.12 in my case. Don't worry about version issues, Django will create needed `__future__` import statements auto-magically.]\n\nInstall the latest version of Django (plus dependencies) as follows:\n\n    $ pip install --user -r requirements.txt\n\n[Replace `pip` with `pip3` as appropriate.]\n\n[The dependency Python Time Zone module `pytz` will also be installed.]\n\nVerify the installed version of Django as follows:\n\n    $ python -m django --version\n\n[Version 1.11.18 in my case.]\n\n## Create a Project\n\nUse the `django-admin` command to do this:\n\n    $ django-admin startproject polls\n\nNote that [django-admin](http://docs.djangoproject.com/en/1.11/ref/django-admin/)\n creates a folder plus infra-structure files, much like `maven` or `sbd`.\n\nLets check the development server works:\n\n    $ cd polls\n    $ python manage.py runserver\n\nThe results should be something like:\n\n```bash\nPerforming system checks...\n\nSystem check identified no issues (0 silenced).\n\nYou have 13 unapplied migration(s). Your project may not work properly until you apply the migrations for app(s): admin, auth, contenttypes, sessions.\nRun 'python manage.py migrate' to apply them.\n\nJanuary 10, 2019 - 20:16:30\nDjango version 1.11.18, using settings 'polls.settings'\nStarting development server at http://127.0.0.1:8000/\nQuit the server with CONTROL-C.\n^C$\n```\n\nThe development server at http://127.0.0.1:8000/ should look something like:\n\n![Development_Server](images/Development_Server.png)\n\n## Projects versus Apps\n\nA project is mostly concerned with a website, whereas an app is mostly concerned with an application (or `microservice` if you will).\n\nAn app can live anywhere, but for the sake of convenience we will create this one in our current project.\n\n## Create an App\n\nThis needs to be done in the folder where `manage.py` lives:\n\n    $ python manage.py startapp polls-app\n\nAnd if, like me, you are from a polyglot background, you will now get a reminder\nthat Python prefers underscores to hyphens:\n\n    CommandError: 'polls-app' is not a valid app name. Please use only numbers, letters and underscores.\n    $\n\nSo lets get with the program:\n\n    $ python manage.py startapp polls_app\n\nThis will create a `polls_app` folder, plus files.\n\n## Create a View\n\nOpen `polls_app/views.py` and change it as follows:\n\n    $ diff -uw views.py.orig views.py\n    --- views.py.orig\t2018-02-11 14:18:23.894106000 -0800\n    +++ views.py\t2018-02-11 14:25:03.776911375 -0800\n    @@ -3,4 +3,7 @@\n     \n     from django.shortcuts import render\n     \n    -# Create your views here.\n    +from django.http import HttpResponse\n    +\n    +def index(request):\n    +    return HttpResponse(\"Hello, world. You're at the polls index.\")\n    $\n\nCreate a `polls_app/urls.py` file and change it as follows:\n\n    # -*- coding: utf-8 -*-\n    from __future__ import unicode_literals\n    \n    from django.conf.urls import url\n    \n    from . import views\n    \n    urlpatterns = [\n        url(r'^$', views.index, name='index'),\n    ]\n\nNext update the `polls/urls.py` file as follows:\n\n    $ diff -uw urls.py.orig urls.py\n    --- urls.py.orig\t2018-02-11 14:37:19.727374508 -0800\n    +++ urls.py\t2018-02-11 14:45:15.909210776 -0800\n    @@ -13,9 +13,11 @@\n         1. Import the include() function: from django.conf.urls import url, include\n         2. Add a URL to urlpatterns:  url(r'^blog/', include('blog.urls'))\n     \"\"\"\n    +from django.conf.urls import include\n     from django.conf.urls import url\n     from django.contrib import admin\n     \n     urlpatterns = [\n    +    url(r'^polls/', include('polls_app.urls')),\n         url(r'^admin/', admin.site.urls),\n     ]\n    $\n\nAgain, lets check to see if everything works:\n\n    $ python manage.py runserver\n\nThe polls app at http://127.0.0.1:8000/polls/ should look as follows:\n\n![polls](images/polls.png)\n\nThe admin interface at http://127.0.0.1:8000/admin/ should look as follows:\n\n![admin](images/admin.png)\n\nAnd our development server at http://127.0.0.1:8000/ should now look like:\n\n![404](images/404.png)\n\n[END OF PART 1]\n\n[START OF PART 2]\n\n## Database setup\n\nWe _could_ open `polls/settings.py` and change the database settings but as \nI prefer to leave the time zone set to UTC this will not be needed. We will\nalso stick with the default `sqlite3` database.\n\nSo lets run our [database migrations](http://docs.djangoproject.com/en/1.11/topics/migrations/):\n\n    $ python manage.py migrate\n\nThe results should look as follows:\n\n    Operations to perform:\n      Apply all migrations: admin, auth, contenttypes, sessions\n    Running migrations:\n      Applying contenttypes.0001_initial... OK\n      Applying auth.0001_initial... OK\n      Applying admin.0001_initial... OK\n      Applying admin.0002_logentry_remove_auto_add... OK\n      Applying contenttypes.0002_remove_content_type_name... OK\n      Applying auth.0002_alter_permission_name_max_length... OK\n      Applying auth.0003_alter_user_email_max_length... OK\n      Applying auth.0004_alter_user_username_opts... OK\n      Applying auth.0005_alter_user_last_login_null... OK\n      Applying auth.0006_require_contenttypes_0002... OK\n      Applying auth.0007_alter_validators_add_error_messages... OK\n      Applying auth.0008_alter_user_username_max_length... OK\n      Applying sessions.0001_initial... OK\n    $\n\n## Model Creation\n\nNow lets create our models - update `polls_app/models.py` as follows:\n\n    $ git diff polls_app/models.py\n    diff --git a/polls/polls_app/models.py b/polls/polls_app/models.py\n    index 1dfab76..04bb7f0 100644\n    --- a/polls/polls_app/models.py\n    +++ b/polls/polls_app/models.py\n    @@ -3,4 +3,13 @@ from __future__ import unicode_literals\n     \n     from django.db import models\n     \n    -# Create your models here.\n    +\n    +class Question(models.Model):\n    +    question_text = models.CharField(max_length=200)\n    +    pub_date = models.DateTimeField('date published')\n    +\n    +\n    +class Choice(models.Model):\n    +    question = models.ForeignKey(Question, on_delete=models.CASCADE)\n    +    choice_text = models.CharField(max_length=200)\n    +    votes = models.IntegerField(default=0)\n    $\n\n## Model Activation\n\nNow lets activate our models - update `polls/settings.py` as follows:\n\n    $ git diff polls/settings.py\n    diff --git a/polls/polls/settings.py b/polls/polls/settings.py\n    index 787a666..5892350 100644\n    --- a/polls/polls/settings.py\n    +++ b/polls/polls/settings.py\n    @@ -31,6 +31,7 @@ ALLOWED_HOSTS = []\n     # Application definition\n     \n     INSTALLED_APPS = [\n    +    'polls_app.apps.PollsAppConfig',\n         'django.contrib.admin',\n         'django.contrib.auth',\n         'django.contrib.contenttypes',\n    $\n\nAnd lets create our migrations:\n\n    $ python manage.py makemigrations polls_app\n\nThe results should look like:\n\n    Migrations for 'polls_app':\n      polls_app/migrations/0001_initial.py\n        - Create model Choice\n        - Create model Question\n        - Add field question to choice\n    $\n\nLets verify what the resulting SQL looks like:\n\n    $ python manage.py sqlmigrate polls_app 0001\n\nIt should look like (bear in mind this is unformatted SQLite):\n\n    BEGIN;\n    --\n    -- Create model Choice\n    --\n    CREATE TABLE \"polls_app_choice\" (\"id\" integer NOT NULL PRIMARY KEY AUTOINCREMENT, \"choice_text\" varchar(200) NOT NULL, \"votes\" integer NOT NULL);\n    --\n    -- Create model Question\n    --\n    CREATE TABLE \"polls_app_question\" (\"id\" integer NOT NULL PRIMARY KEY AUTOINCREMENT, \"question_text\" varchar(200) NOT NULL, \"pub_date\" datetime NOT NULL);\n    --\n    -- Add field question to choice\n    --\n    ALTER TABLE \"polls_app_choice\" RENAME TO \"polls_app_choice__old\";\n    CREATE TABLE \"polls_app_choice\" (\"id\" integer NOT NULL PRIMARY KEY AUTOINCREMENT, \"choice_text\" varchar(200) NOT NULL, \"votes\" integer NOT NULL, \"question_id\" integer NOT NULL REFERENCES \"polls_app_question\" (\"id\"));\n    INSERT INTO \"polls_app_choice\" (\"choice_text\", \"votes\", \"id\", \"question_id\") SELECT \"choice_text\", \"votes\", \"id\", NULL FROM \"polls_app_choice__old\";\n    DROP TABLE \"polls_app_choice__old\";\n    CREATE INDEX \"polls_app_choice_question_id_38df74ee\" ON \"polls_app_choice\" (\"question_id\");\n    COMMIT;\n    $\n\nThis can all be customized of course but it's a pretty good starting point for something that was auto-generated.\n\nJust for fun we will run the following code to see if there are any problems so far:\n\n    $ python manage.py check\n\nAnd happily there are no issues:\n\n    System check identified no issues (0 silenced).\n    $\n\nNow we will __migrate__ again to apply our migrations:\n\n    $ python manage.py migrate\n\nAnd the results should look like:\n\n    Operations to perform:\n      Apply all migrations: admin, auth, contenttypes, polls_app, sessions\n    Running migrations:\n      Applying polls_app.0001_initial... OK\n    $\n\nLets use `showmigrations` to see what migrations now exist:\n\n    $ python manage.py showmigrations\n\nAnd the results should look like:\n\n    admin\n     [X] 0001_initial\n     [X] 0002_logentry_remove_auto_add\n    auth\n     [X] 0001_initial\n     [X] 0002_alter_permission_name_max_length\n     [X] 0003_alter_user_email_max_length\n     [X] 0004_alter_user_username_opts\n     [X] 0005_alter_user_last_login_null\n     [X] 0006_require_contenttypes_0002\n     [X] 0007_alter_validators_add_error_messages\n     [X] 0008_alter_user_username_max_length\n    contenttypes\n     [X] 0001_initial\n     [X] 0002_remove_content_type_name\n    polls_app\n     [X] 0001_initial\n    sessions\n     [X] 0001_initial\n    $\n\nThe 'X' in the square brackets indicates that the migration has been run (for unapplied migrations this field would be blank).\n\nThe migrations of the most concern to us are the `polls_app` ones (only `0001_initial` for now).\n\n## Django API\n\nLets invoke the Django API as follows:\n\n    $ python manage.py shell\n\nThe results should look as follows (I have IPython installed so this will be verbose):\n\n    Python 2.7.12 (default, Dec  4 2017, 14:50:18) \n    Type \"copyright\", \"credits\" or \"license\" for more information.\n    \n    IPython 2.4.1 -- An enhanced Interactive Python.\n    ?         -\u003e Introduction and overview of IPython's features.\n    %quickref -\u003e Quick reference.\n    help      -\u003e Python's own help system.\n    object?   -\u003e Details about 'object', use 'object??' for extra details.\n    \n    In [1]: \n\nType in `from polls_app.models import Question, Choice` followed by `Question.objects.all()`.\n\nThis should result in an empty set as follows:\n\n    In [1]: from polls_app.models import Question, Choice\n    \n    In [2]: Question.objects.all()\n    Out[2]: \u003cQuerySet []\u003e\n    \n    In [3]:\n\nSo lets create a question:\n\n    In [3]: from django.utils import timezone\n    \n    In [4]: q = Question(question_text=\"What's new?\", pub_date=timezone.now())\n    \n    In [5]: q.save()\n    \n    In [6]: q.id\n    Out[6]: 1\n    \n    In [7]:\n\nAnd query for questions again:\n\n    In [7]: Question.objects.all()\n    Out[7]: \u003cQuerySet [\u003cQuestion: Question object\u003e]\u003e\n    \n    In [8]:\n\nFor convenience lets add string methods to our models:\n\n    $ git diff polls_app/models.py\n    diff --git a/polls/polls_app/models.py b/polls/polls_app/models.py\n    index 04bb7f0..e2118e1 100644\n    --- a/polls/polls_app/models.py\n    +++ b/polls/polls_app/models.py\n    @@ -2,14 +2,21 @@\n     from __future__ import unicode_literals\n     \n     from django.db import models\n    +from django.utils.encoding import python_2_unicode_compatible\n     \n     \n    +@python_2_unicode_compatible\n     class Question(models.Model):\n         question_text = models.CharField(max_length=200)\n         pub_date = models.DateTimeField('date published')\n    +    def __str__(self):\n    +        return self.question_text\n     \n     \n    +@python_2_unicode_compatible\n     class Choice(models.Model):\n         question = models.ForeignKey(Question, on_delete=models.CASCADE)\n         choice_text = models.CharField(max_length=200)\n         votes = models.IntegerField(default=0)\n    +    def __str__(self):\n    +        return self.choice_text\n    $\n\nNow if we restart our API shell, we get a more readable result:\n\n    $ python manage.py shell\n    Python 2.7.12 (default, Dec  4 2017, 14:50:18) \n    Type \"copyright\", \"credits\" or \"license\" for more information.\n    \n    IPython 2.4.1 -- An enhanced Interactive Python.\n    ?         -\u003e Introduction and overview of IPython's features.\n    %quickref -\u003e Quick reference.\n    help      -\u003e Python's own help system.\n    object?   -\u003e Details about 'object', use 'object??' for extra details.\n    \n    In [1]: from polls_app.models import Question, Choice\n    \n    In [2]: Question.objects.all()\n    Out[2]: \u003cQuerySet [\u003cQuestion: What's new?\u003e]\u003e\n    \n    In [3]: \n\nLets add some answers:\n\n    In [3]: q = Question.objects.get(pk=1)\n    \n    In [4]: q.choice_set.all()\n    Out[4]: \u003cQuerySet []\u003e\n    \n    In [5]: q.choice_set.create(choice_text='Not much', votes=0)\n    Out[5]: \u003cChoice: Not much\u003e\n    \n    In [6]: q.choice_set.create(choice_text='The sky', votes=0)\n    Out[6]: \u003cChoice: The sky\u003e\n    \n    In [7]: q.choice_set.create(choice_text='Taxes', votes=0)\n    Out[7]: \u003cChoice: Taxes\u003e\n    \n    In [8]: q.choice_set.all()\n    Out[8]: \u003cQuerySet [\u003cChoice: Not much\u003e, \u003cChoice: The sky\u003e, \u003cChoice: Taxes\u003e]\u003e\n    \n    In [9]: q.choice_set.count()\n    Out[9]: 3\n    \n    In [10]: quit\n    $\n\n## Admin Creation\n\nLets create an Admin user:\n\n    $ python manage.py createsuperuser\n    Username (leave blank to use 'owner'): admin\n    Email address: admin@example.com\n    Password: \n    Password (again): \n    This password is too common.\n    Password: \n    Password (again): \n    This password is too common.\n    Password: \n    Password (again): \n    This password is too common.\n    Password: \n    Password (again): \n    This password is too short. It must contain at least 8 characters.\n    This password is too common.\n    Password: \n    Password (again): \n    Superuser created successfully.\n    $\n\n[Password verification is reasonably strict - 'password', 'drowssap', 'passw0rd' and '123abc' were all rejected. I eventually used '123abcde'.]\n\n## Admin Interface\n\nLets start the server and see if we can log in:\n\n    $ python manage.py runserver\n\nThe logged-in interface at http://127.0.0.1:8000/admin/ should look as follows:\n\n![Admin_UI](images/Admin_UI.png)\n\nWe need to modify `polls_app/admin.py` to register Question as follows:\n\n    $ git diff polls_app/admin.py\n    diff --git a/polls/polls_app/admin.py b/polls/polls_app/admin.py\n    index 13be29d..03ddead 100644\n    --- a/polls/polls_app/admin.py\n    +++ b/polls/polls_app/admin.py\n    @@ -3,4 +3,6 @@ from __future__ import unicode_literals\n     \n     from django.contrib import admin\n     \n    -# Register your models here.\n    +from .models import Question\n    +\n    +admin.site.register(Question)\n    $\n\nAnd now if we refresh our browser window we should get:\n\n![Admin_UI_with_Questions](images/Admin_UI_with_Questions.png)\n\nAnd now we can edit our Question:\n\n![Question](images/Question.png)\n\n[END OF PART 2]\n\n## Notes on Updating Django\n\nAs these instructions were an exhaustive list, the simplest solution was\nsimply to delete the base `polls` folder and start again from scratch.\n\nWe ___could___ have saved our database (`polls/db.sqlite3`) first, and this\nmight have saved some work. But it was simple in this case to re-create it.\nObviously, if any ___Migrations___ had been written then deleting the `polls`\nfolder would not have been a viable strategy. [SemVer](http://semver.org) means\nthis was a ___point release___ (i.e. 1.11.__10__ -\u003e 1.11.__18__). If it had been\na ___major release___ (say Django __1__ to Django __2__), then things would\nprobably have been different too (generally, a ___point release___ means only\nbugfixes and minor changes, with any breaking changes requiring a ___major release___).\n\nThe nice thing about `git` is that it can be used very effectively to\nmonitor progress.\n\nIn the end there were very minimal differences, with the main difference\nbeing the generation comments and the generated __SECRET\\_KEY__.\n\n```bash\n$ git status\nOn branch master\nYour branch is up-to-date with 'origin/master'.\nChanges not staged for commit:\n  (use \"git add \u003cfile\u003e...\" to update what will be committed)\n  (use \"git checkout -- \u003cfile\u003e...\" to discard changes in working directory)\n\n\tmodified:   README.md\n\tmodified:   polls/polls/settings.py\n\tmodified:   polls/polls_app/migrations/0001_initial.py\n\nno changes added to commit (use \"git add\" and/or \"git commit -a\")\n$\n```\n\n[These notes apply to upgrading from an insecure Django 1.11.10 -\u003e 1.11.18.]\n\n## To Do\n\n- [x] Update for latest LTS Django (1.11.18 as of the time of writing)\n- [x] Create a `requirements.txt` file for dependencies\n- [x] Add Snyk.io vulnerability scanning and badge\n- [ ] Follow parts 3 - 7 of this tutorial\n\n## Credits\n\nPart 1:\n\n    http://docs.djangoproject.com/en/1.11/intro/tutorial01/\n\nPart 2:\n\n    http://docs.djangoproject.com/en/1.11/intro/tutorial02/\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmramshaw%2Fwriting_django","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmramshaw%2Fwriting_django","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmramshaw%2Fwriting_django/lists"}