+2347067162698
tclassified.com@gmail.com

Django Stack-up

Educational Technology and ICT

Created with Sketch.

Django Stack-up

Django is a python web framework.

create a new folder on the desktop—foldDjang
open the folder in your vscode
$ python -m pip install Django
$ python -m django –version
$ django-admin startproject pollster

you see this
pollster/
manage.py
pollster/
init.py
settings.py
urls.py
asgi.py
wsgi.py

These files are:

The outer pollster/ root directory is a container for your project. Its name doesn’t matter to Django; you can rename it to anything you like.
manage.py: A command-line utility that lets you interact with this Django project in various ways. You can read all the details about manage.py in django-admin and manage.py.
The inner pollster/ directory is the actual Python package for your project. Its name is the Python package name you’ll need to use to import anything inside it (e.g. pollster.urls).
pollster/init.py: An empty file that tells Python that this directory should be considered a Python package. If you’re a Python beginner, read more about packages in the official Python docs.
pollster/settings.py: Settings/configuration for this Django project. Django settings will tell you all about how settings work.
pollster/urls.py: The URL declarations for this Django project; a “table of contents” of your Django-powered site. You can read more about URLs in URL dispatcher.
pollster/asgi.py: An entry-point for ASGI-compatible web servers to serve your project. See How to deploy with ASGI for more details.
pollster/wsgi.py: An entry-point for WSGI-compatible web servers to serve your project. See How to deploy with WSGI for more details.

$ python manage.py runserver

Performing system checks…

System check identified no issues (0 silenced).

You have unapplied migrations; your app may not work properly until they are applied.
Run ‘python manage.py migrate’ to apply them.


Django version 3.1, using settings ‘pollster.settings’
Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.

$ python manage.py startapp polls

polls/
init.py
admin.py
apps.py
migrations/
init.py
models.py
tests.py
views.py

Write your first view¶
Let’s write the first view. Open the file polls/views.py and put the following Python code in it:

from django.http import HttpResponse

def index(request):
return HttpResponse(“Hello, world. You’re at the polls index.”)

This is the simplest view possible in Django. To call the view, we need to map it to a URL – and for this we need a URLconf.

To create a URLconf in the polls directory, create a file called urls.py. Your app directory should now look like:

polls/
init.py
admin.py
apps.py
migrations/
init.py
models.py
tests.py
urls.py
views.py

In the polls/urls.py file include the following code:

from django.urls import path

from . import views

urlpatterns = [
path(‘ ‘, views.index, name=‘index’),
]

The next step is to point the root URLconf at the polls.urls module. In mysite/urls.py, add an import for django.urls.include and insert an include() in the urlpatterns list, so you have:

pollster/urls.py¶
from django.contrib import admin
from django.urls import include, path

urlpatterns = [
path(‘polls/’, include(‘polls.urls’)),
path(‘admin/’, admin.site.urls),
]
The include() function allows referencing other URLconfs. Whenever Django encounters include(), it chops off whatever part of the URL matched up to that point and sends the remaining string to the included URLconf for further processing.

The idea behind include() is to make it easy to plug-and-play URLs. Since polls are in their own URLconf (polls/urls.py), they can be placed under “/polls/”, or under “/fun_polls/”, or under “/content/polls/”, or any other path root, and the app will still work.

You have now wired an index view into the URLconf. Verify it’s working with the following command:


$ python manage.py runserver
Go to http://localhost:8000/polls/ in your browser, and you should see the text “Hello, world. You’re at the polls index.”, which you defined in the index view.

The path() function is passed four arguments, two required: route and view, and two optional: kwargs, and name. At this point, it’s worth reviewing what these arguments are for.

path() argument: route¶
route is a string that contains a URL pattern. When processing a request, Django starts at the first pattern in urlpatterns and makes its way down the list, comparing the requested URL against each pattern until it finds one that matches.

Patterns don’t search GET and POST parameters, or the domain name. For example, in a request to https://www.example.com/myapp/, the URLconf will look for myapp/. In a request to https://www.example.com/myapp/?page=3, the URLconf will also look for myapp/.

path() argument: view¶
When Django finds a matching pattern, it calls the specified view function with an HttpRequest object as the first argument and any “captured” values from the route as keyword arguments. We’ll give an example of this in a bit.

path() argument: kwargs¶
Arbitrary keyword arguments can be passed in a dictionary to the target view. We aren’t going to use this feature of Django in the tutorial.

path() argument: name¶
Naming your URL lets you refer to it unambiguously from elsewhere in Django, especially from within templates. This powerful feature allows you to make global changes to the URL patterns of your project while only touching a single file.

When you’re comfortable with the basic request and response flow, read part 2 of this tutorial to start working with the database.

$ python manage.py migrate

The migrate command looks at the INSTALLED_APPS setting and creates any necessary database tables according to the database settings in your mysite/settings.py file and the database migrations shipped with the app (we’ll cover those later). You’ll see a message for each migration it applies. If you’re interested, run the command-line client for your database and type \dt (PostgreSQL), SHOW TABLES; (MariaDB, MySQL), .schema (SQLite), or SELECT TABLE_NAME FROM USER_TABLES; (Oracle) to display the tables Django created.

polls/models.py

from django.db import models class Question(models.Model): question_text = models.CharField(max_length=200) pub_date = models.DateTimeField(‘date published’) class Choice(models.Model): question = models.ForeignKey(Question, on_delete=models.CASCADE) choice_text = models.CharField(max_length=200) votes = models.IntegerField(default=0)

mysite/settings.py

INSTALLED_APPS = [ ‘polls.apps.PollsConfig’, ‘django.contrib.admin’, ‘django.contrib.auth’, ‘django.contrib.contenttypes’, ‘django.contrib.sessions’, ‘django.contrib.messages’, ‘django.contrib.staticfiles’, ]

$ python manage.py makemigrations polls
Migrations for ‘polls’: polls/migrations/0001_initial.py – Create model Question – Create model Choice

$ python manage.py sqlmigrate polls 0001

BEGIN — Create model Question  CREATE TABLE “polls_question” ( “id” serial NOT NULL PRIMARY KEY, “question_text” varchar(200) NOT NULL, “pub_date” timestamp with time zone NOT NULL );  — Create model Choice  CREATE TABLE “polls_choice” ( “id” serial NOT NULL PRIMARY KEY, “choice_text” varchar(200) NOT NULL, “votes” integer NOT NULL, “question_id” integer NOT NULL ); ALTER TABLE “polls_choice” ADD CONSTRAINT “polls_choice_question_id_c5b4b260_fk_polls_question_id” FOREIGN KEY (“question_id”) REFERENCES “polls_question” (“id”) DEFERRABLE INITIALLY DEFERREDCREATE INDEX “polls_choice_question_id_c5b4b260” ON “polls_choice” (“question_id”); COMMIT;

$ python manage.py migrate

Operations to perform: Apply all migrations: admin, auth, contenttypes, polls, sessions Running migrations: Rendering model states… DONE Applying polls.0001_initial… OK


$ python manage.py shell

>>> from polls.models import Choice, Question # Import the model classes we just wrote. # No questions are in the system yet. >>> Question.objects.all() <QuerySet []> # Create a new Question. # Support for time zones is enabled in the default settings file, so # Django expects a datetime with tzinfo for pub_date. Use timezone.now() # instead of datetime.datetime.now() and it will do the right thing. >>> from django.utils import timezone >>> q = Question(question_text=”What’s new?”, pub_date=timezone.now()) # Save the object into the database. You have to call save() explicitly. >>> q.save() # Now it has an ID. >>> q.id 1 # Access model field values via Python attributes. >>> q.question_text “What’s new?” >>> q.pub_date datetime.datetime(2012, 2, 26, 13, 0, 0, 775217, tzinfo=<UTC>) # Change values by changing the attributes, then calling save(). >>> q.question_text = “What’s up?” >>> q.save() # objects.all() displays all the questions in the database. >>> Question.objects.all() <QuerySet [<Question: Question object (1)>]>


polls/models.py

from django.db import models class Question(models.Model): # … def __str__(self): return self.question_text class Choice(models.Model): # … def __str__(self): return self.choice_text

polls/models.py

import datetime from django.db import models from django.utils import timezone class Question(models.Model): # … def was_published_recently(self): return self.pub_date >= timezone.now() – datetime.timedelta(days=1)


>>> from polls.models import Choice, Question # Make sure our __str__() addition worked. >>> Question.objects.all() <QuerySet [<Question: What’s up?>]> # Django provides a rich database lookup API that’s entirely driven by # keyword arguments. >>> Question.objects.filter(id=1) <QuerySet [<Question: What’s up?>]> >>> Question.objects.filter(question_text__startswith=’What’) <QuerySet [<Question: What’s up?>]> # Get the question that was published this year. >>> from django.utils import timezone >>> current_year = timezone.now().year >>> Question.objects.get(pub_date__year=current_year) <Question: What’s up?> # Request an ID that doesn’t exist, this will raise an exception. >>> Question.objects.get(id=2) Traceback (most recent call last): … DoesNotExist: Question matching query does not exist. # Lookup by a primary key is the most common case, so Django provides a # shortcut for primary-key exact lookups. # The following is identical to Question.objects.get(id=1). >>> Question.objects.get(pk=1) <Question: What’s up?> # Make sure our custom method worked. >>> q = Question.objects.get(pk=1) >>> q.was_published_recently() True # Give the Question a couple of Choices. The create call constructs a new # Choice object, does the INSERT statement, adds the choice to the set # of available choices and returns the new Choice object. Django creates # a set to hold the “other side” of a ForeignKey relation # (e.g. a question’s choice) which can be accessed via the API. >>> q = Question.objects.get(pk=1) # Display any choices from the related object set — none so far. >>> q.choice_set.all() <QuerySet []> # Create three choices. >>> q.choice_set.create(choice_text=’Not much’, votes=0) <Choice: Not much> >>> q.choice_set.create(choice_text=’The sky’, votes=0) <Choice: The sky> >>> c = q.choice_set.create(choice_text=’Just hacking again’, votes=0) # Choice objects have API access to their related Question objects. >>> c.question <Question: What’s up?> # And vice versa: Question objects get access to Choice objects. >>> q.choice_set.all() <QuerySet [<Choice: Not much>, <Choice: The sky>, <Choice: Just hacking again>]> >>> q.choice_set.count() 3 # The API automatically follows relationships as far as you need. # Use double underscores to separate relationships. # This works as many levels deep as you want; there’s no limit. # Find all Choices for any question whose pub_date is in this year # (reusing the ‘current_year’ variable we created above). >>> Choice.objects.filter(question__pub_date__year=current_year) <QuerySet [<Choice: Not much>, <Choice: The sky>, <Choice: Just hacking again>]> # Let’s delete one of the choices. Use delete() for that. >>> c = q.choice_set.filter(choice_text__startswith=’Just hacking’) >>> c.delete()

creating an admin user
First we’ll need to create a user who can login to the admin site. Run the following command:

 
$ python manage.py createsuperuser
Enter your desired username and press enter.
Username: admin
You will then be prompted for your desired email address:
Email address: admin@example.com
The final step is to enter your password. You will be asked to enter your password twice, the second time as a confirmation of the first.
Password: ********** Password (again): ********* Superuser created successfully.

Start the development server
The Django admin site is activated by default. Let’s start the development server and explore it.
If the server is not running start it like so:

 
$ python manage.py runserver
Now, open a Web browser and go to “/admin/” on your local domain – e.g., http://127.0.0.1:8000/admin/. You should see the admin’s login screen:

polls/admin.py

from django.contrib import admin from .models import Question admin.site.register(Question)

Writing more views

polls/views.py

def detail(request, question_id):

    return HttpResponse(“You’re looking at question %s.” % question_id)

def results(request, question_id):

     response = “You’re looking at the results of question

%s.”

    return HttpResponse(response % question_id)

def vote(request, question_id):

    return HttpResponse(“You’re voting on question %s.” % question_id)

polls/urls.py

from django.urls import path

from . import views

urlpatterns = [

    # ex: /polls/

    path(”, views.index, name=’index’),

    # ex: /polls/5/

    path(‘<int:question_id>/’, views.detail, name=’detail’),

    # ex: /polls/5/results/

    path(‘<int:question_id>/results/’, views.results, name=’results’),

    # ex: /polls/5/vote/

    path(‘<int:question_id>/vote/’, views.vote, name=’vote’),

]

Take a look in your browser, at “/polls/34/”. It’ll run the detail() method and display whatever ID you provide in the URL. Try “/polls/34/results/” and “/polls/34/vote/” too – these will display the placeholder results and voting pages.

When somebody requests a page from your website – say, “/polls/34/”, Django will load the mysite.urls Python module because it’s pointed to by the ROOT_URLCONF setting. It finds the variable named urlpatterns and traverses the patterns in order. After finding the match at ‘polls/’, it strips off the matching text (“polls/”) and sends the remaining text – “34/” – to the ‘polls.urls’ URLconf for further processing. There it matches ‘<int:question_id>/’, resulting in a call to the detail() view like so:

detail(request=<HttpRequest object>, question_id=34)

The question_id=34 part comes from <int:question_id>. Using angle brackets “captures” part of the URL and sends it as a keyword argument to the view function. The :question_id> part of the string defines the name that will be used to identify the matched pattern, and the <int: part is a converter that determines what patterns should match this part of the URL path.

Write views that actually do something

polls/views.py

from django.http import HttpResponse

from .models import Question

def index(request):

    latest_question_list = Question.objects.order_by(‘-pub_date’)[:5]

    output = ‘, ‘.join([q.question_text for q in latest_question_list])

    return HttpResponse(output)

# Leave the rest of the views (detail, results, vote) unchanged

polls/templates/polls/index.html

{% if latest_question_list %}

    <ul>

    {% for question in latest_question_list %}

        <li><a href=”/polls/{{ question.id }}/”>{{ question.question_text }}</a></li>

    {% endfor %}

    </ul>

{% else %}

    <p>No polls are available.</p>

{% endif %}

Update index view in polls/views.py to use the template:

polls/views.py

from django.http import HttpResponse

from django.template import loader

from .models import Question

def index(request):

    latest_question_list = Question.objects.order_by(‘-pub_date’)[:5]

    template = loader.get_template(‘polls/index.html’)

    context = {

        ‘latest_question_list’: latest_question_list,

    }

    return HttpResponse(template.render(context, request))

A shortcut: render()

polls/views.py

from django.shortcuts import render

from .models import Question

def index(request):

    latest_question_list = Question.objects.order_by(‘-pub_date’)[:5]

    context = {‘latest_question_list’: latest_question_list}

    return render(request, ‘polls/index.html’, context)

Raising a 404 error

polls/views.py

from django.http import Http404

from django.shortcuts import render

from .models import Question

# …

def detail(request, question_id):

    try:

        question = Question.objects.get(pk=question_id)

    except Question.DoesNotExist:

        raise Http404(“Question does not exist”)

    return render(request, ‘polls/detail.html’, {‘question’: question})

polls/templates/polls/detail.html

{{ question }}

A shortcut: get_object_or_404()

polls/views.py

from django.shortcuts import get_object_or_404, render

from .models import Question

# …

def detail(request, question_id):

    question = get_object_or_404(Question, pk=question_id)

    return render(request, ‘polls/detail.html’, {‘question’: question})

Use the template system

polls/templates/polls/detail.html

<h1>{{ question.question_text }}</h1>

<ul>

{% for choice in question.choice_set.all %}

    <li>{{ choice.choice_text }}</li>

{% endfor %}

polls/templates/polls/detail.html

Write a minimal form

polls/templates/polls/detail.html

<h1>{{ question.question_text }}</h1>

{% if error_message %}<p><strong>{{ error_message }}
</strong></p>{% endif %}

<form action="{% url 'polls:vote' question.id %}"
method="post">
{% csrf_token %}
{% for choice in question.choice_set.all %}
    <input type="radio" name="choice" id="choice{{ forloop.counter }}" value="{{ choice.id }}">
    <label for="choice{{ forloop.counter }}">{{ choice.choice_text }}</label><br>
{% endfor %}
<input type="submit" value="Vote">
</form>

polls/urls.py

path('<int:question_id>/vote/', views.vote, name='vote'),

polls/views.py

from django.http import HttpResponse, HttpResponseRedirect
from django.shortcuts import get_object_or_404, render
from django.urls import reverse

from .models import Choice, Question
# ...
def vote(request, question_id):
    question = get_object_or_404(Question, pk=question_id)
    try:
        selected_choice = question.choice_set.get(pk=request.POST['choice'])
    except (KeyError, Choice.DoesNotExist):
        # Redisplay the question voting form.
        return render(request, 'polls/detail.html', {
            'question': question,
            'error_message': "You didn't select a choice.",
        })
    else:
        selected_choice.votes += 1
        selected_choice.save()
        # Always return an HttpResponseRedirect after successfully dealing
        # with POST data. This prevents data from being posted twice if a
        # user hits the Back button.
        return HttpResponseRedirect(reverse('polls:results', args=(question.id,)))

polls/views.py

from django.shortcuts import get_object_or_404, render


def results(request, question_id):
    question = get_object_or_404(Question, pk=question_id)
    return render(request, 'polls/results.html', {'question': question})

create a polls/results.html template:

polls/templates/polls/results.html

<h1>{{ question.question_text }}</h1>

<ul>
{% for choice in question.choice_set.all %}
    <li>{{ choice.choice_text }} -- {{ choice.votes }} vote{{ choice.votes|pluralize }}</li>
{% endfor %}
</ul>

<a href="{% url 'polls:detail' question.id %}">Vote again?</a>

Amend URLconf

polls/urls.py

from django.urls import path

from . import views

app_name = 'polls'
urlpatterns = [
    path('', views.IndexView.as_view(), name='index'),
    path('<int:pk>/', views.DetailView.as_view(), name='detail'),
    path('<int:pk>/results/', views.ResultsView.as_view(), name='results'),
    path('<int:question_id>/vote/', views.vote, name='vote'),
]

Amend views

polls/views.py

from django.http import HttpResponseRedirect
from django.shortcuts import get_object_or_404, render
from django.urls import reverse
from django.views import generic

from .models import Choice, Question


class IndexView(generic.ListView):
    template_name = 'polls/index.html'
    context_object_name = 'latest_question_list'

    def get_queryset(self):
        """Return the last five published questions."""
        return Question.objects.order_by('-pub_date')[:5]


class DetailView(generic.DetailView):
    model = Question
    template_name = 'polls/detail.html'


class ResultsView(generic.DetailView):
    model = Question
    template_name = 'polls/results.html'


def vote(request, question_id):
    ... # same as above, no changes needed.

Leave a Reply

Your email address will not be published. Required fields are marked *

Open chat