PyCharm 2022.2 Help

Step 4. Create and Run your first Django project

Before you start

Make sure that the following prerequisites are met:

  • You are working with PyCharm version 2022.2 or later. If you still do not have PyCharm, download it from this page. To install PyCharm, follow the instructions, depending on your platform.

This tutorial has been created with the following assumptions:

  • Python 3.10.5.

  • Django 4.1.

  • The example used in this tutorial is similar to the one used in Django documentation.

Creating a new project

  1. From the main menu, choose File | New Project, or click the New Project button in the Welcome screen. New Project dialog opens.

    Create a Django project
  2. In the New Project dialog, do the following:

    • Specify project type Django.

    • If required, change the default project location.

    • Select New environment using Virtualenv

  3. Click More settings (More Settings), and specify polls in the Application name field.

  4. Click Create.

Exploring project structure

The newly created project contains Django-specific files and directories.

The structure of the project is visible in the Project tool window:

Django project structure
  • MyDjangoProject directory is a container for your project. It is denoted with bold font.

  • manage.py is a command-line utility that lets you interact with your Django project. Refer to the Django documentation for details.

  • The nested directory MyDjangoProject is the actual Python package for your project.

  • MyDjangoProject/__init__.py: This empty file tells Python that this directory should be considered a Python package.

  • MyDjangoProject/settings.py: This file contains configuration for your Django project.

  • MyDjangoProject/urls.py: This file contains the URL declarations for your Django project.

  • MyDjangoProject/wsgi.py: This file defines an entry-point for WSGI-compatible web servers to serve your project. See How to deploy with WSGI for more details.

  • The nested directory polls contains all the files required for developing a Django application:

    • Again, polls/_init_.py tells Python that this directory should be considered a Python package.

    • polls/models.py: In this file, we'll create models for our application.

    • polls/views.py: In this file, we'll create views.

  • templates directory is by now empty. It will contain Django templates.

  • The nested directory migrations contains by now only the package file _init_.py, but will be used in the future to propagate the changes you make to your models (adding a field, deleting a model, and so on) into your database schema. Read the migrations description here.

Launching Django server

The Django server run/debug configuration is created automatically. If required, you can edit it by selecting the Edit Configurations command in the run/debug configuration list on the main toolbar:

Edit configurations

For example, you can choose to open a browser window automatically when the configuration is launched:

Run/Debug configuration for a Django server

Run the MyDjangoProject configuration by clicking App actions execute. If a browser window does not open automatically, click the link in the Run tool window.

The following page opens:

Django server test page

Writing views

Django views are functions that take web request and return web responses. By convention, views are defined in views.py files inside of project and application directories.

  1. Open the file polls/views.py and type the following Python code:

    from django.http import HttpResponse def index(request): return HttpResponse("Hello, world. You're at the polls index.")

    The above message will be shown on the index page of the polls application.

  2. Now we need to instruct the application to render the index view.

    In the polls directory, create the file urls.py and type the following code in it:

    from django.urls import path from . import views app_name = 'polls' urlpatterns = [ path('', views.index, name='index'), ]

  3. Next, open the file MyDjangoProject/urls.py (which PyCharm has already created for you) and add a URL for the index page. You should end up with the following code:

    from django.contrib import admin from django.urls import include, path urlpatterns = [ path('polls/', include('polls.urls')), path('admin/', admin.site.urls), ]

    Don't forget to import django.urls.include!

  4. Open the page http://127.0.0.1:8000/polls/ in your browser. You should see the following text:

    Polls application index page
  5. Next, let’s add more views. Add the following code to the file 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)

    The above views take one argument (question_id), and then use it in the responses.

  6. Map these new views to URLs by adding patterns in the /polls/urls.py file. The full code should look as follows:

    from django.urls import path from . import views app_name = 'polls' urlpatterns = [ path('', views.index, name='index'), path('<int:question_id>/', views.detail, name='detail'), path('<int:question_id>/results/', views.results, name='results'), path('<int:question_id>/vote/', views.vote, name='vote'), ]

If you now open the corresponding pages in your browser, you will see the following:

Application views in browser

Creating database

By default, PyCharm automatically creates an SQLite database for a Django project.

We need to create the tables in the database for all applications in the current Django project. To do that, press Ctrl+Alt+R and type migrate followed by Enter in the manage.py console, that opens.

You should see Process finished with exit code 0 in the console output.

Creating and activating models

Django models define the fields and behaviors of your data. They are represented by Python classes, which are subclasses of the django.db.models.Model class.

Let's create two models for our polls app: Question and Choice. To do that, open the file polls/models.py, and add the following code after the import statement:

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)

Each model here has class variables represented by instances of a Field class:

  • The Question model:

    • question_text. An instance of the CharField class, contains the text of the question.

    • pub_date. An instance of the DateTimeField class, contains the publication date of the question.

      'date published' is an optional first positional argument representing the human-readable name of the field.

  • The Choice model:

    • question. Association with a Question.

    • choice_text. An instance of the CharField class, contains the text of the choice.

    • votes. An instance of the IntegerField class, contains the vote tally.

For more information about model fields, refer to the Django documentation.

To make Django aware of the new models, run the following command in the manage.py console:

makemigrations polls

The polls/migrations directory now contains the migration file 0001_initial.py:

New Django migration

Migrations are human-editable files, in which Django stores changes to data models. To apply changes and create tables in the database for the two new models, run the migrate command again:

The 'migrate' command output in console

Performing administrative functions

Admin sites are used to add, edit, and otherwise manage the content. Django allows creating an admin site for your project automatically.

Setting up an admin site

  1. Firstly, we need to create a superuser. To do that, type the createsuperuser command in the manage.py console, specify your email address, and password:

    Creating a superuser
  2. Now go to /admin/ on your Django server, for example, http://127.0.0.1:8000/admin/. You should see the following login page:

    Django admin site login page

After you log in, the administration page is displayed. It has a section Authentication and Authorization (Groups and Users), but Polls is not available. Why so?

We must tell the admin that Question objects have an admin interface.

Adding content

  1. Open the file polls/admin.py, and type the following code:

    from django.contrib import admin from .models import Question admin.site.register(Question)
  2. Refresh the page in the browser. The Polls section with Questions should appear:

    Django admin site with polls section
  3. Click Add to create a question:

    Adding question in Django admin site

    When you a ready, click SAVE.

The newly created question appears in the list as Question object (1). Such naming makes content management complicated, as you have to open each question to see its text.

Let's fix it by adding a __str__() method for both Question and Choice. Open polls/models.py and add the following lines:

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

You should end up with the following:

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

The list of questions now consists of human-readable names:

List of questions on the admin site

By design, each question must have a number of choices. However, choices are still not available in the admin interface. Let's fix that.

Providing features

  • Open the file polls/admin.py and edit it to get the folowing result:

    from django.contrib import admin from .models import Choice, Question class ChoiceInline(admin.TabularInline): model = Choice extra = 3 class QuestionAdmin(admin.ModelAdmin): fieldsets = [ (None, {'fields': ['question_text']}), ('Date information', {'fields': ['pub_date'], 'classes': ['collapse']}), ] inlines = [ChoiceInline] admin.site.register(Question, QuestionAdmin)

    Now you can add choices to a question:

    Change question page

Creating Django templates

Until now, the design of the polls application pages has been hardcoded in views. To make the application usable, you need to separate the visual representation of the output from the Python code. That can be done by using Django templates.

Open the file polls/views.py and replace its contents with the following code:

from django.http import HttpResponse from django.shortcuts import get_object_or_404, 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) def detail(request, question_id): question = get_object_or_404(Question, pk=question_id) return render(request, 'polls/detail.html', {'question': question}) def results(request, question_id): question = get_object_or_404(Question, pk=question_id) return render(request, 'polls/results.html', {'question': question}) def vote(request, question_id): return HttpResponse("You're voting on question %s." % question_id)

You can see unresolved references to the template files index.html, detail.html, and results.html:

Unresolved references to Django templates

PyCharm suggests a quick-fix: if you click the light bulb, or press Alt+Enter, you can choose to create the corresponding template file in the templates folder:

Quick-fix for Django a template

PyCharm also creates the directory polls where this template should reside. Confirm this operation:

Confirmation of directory creation

By now, the file index.html is empty. Fill it with the following code:

{% 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 %}

The code generates the list of available questions, or displays "No polls are available" if there are none.

Pay attention to the icons html type and python type that appear in the gutter of the files views.py and index.html respectively:

Gutter icons for html and python references

These icons enable you to jump between a view method and its template straight away. Read more about this kind of navigation in the articles Navigate between templates and views and Part 6. Django-specific navigation.

Now let's add the detail.html template file with the code that generates a page with a question text, radio buttons for choices, and a Vote button:

<form action="{% url 'polls:vote' question.id %}" method="post"> {% csrf_token %} <fieldset> <legend><h1>{{ question.question_text }}</h1></legend> {% if error_message %}<p><strong>{{ error_message }}</strong></p>{% endif %} {% 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 %} </fieldset> <input type="submit" value="Vote"> </form>

The results.html template will generate a page with voting results for all choices and a link for answering the same question again. Create the file and fill it with the following code:

<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>

Go to http://127.0.0.1:8000/polls/ in your browser and click the question link. You should see the following:

Django application question page

Select an option and click Vote. You will see a stub page with the "You are voting on question 1" message. That happens because we only have a dummy implementation of the vote() function in /polls/views.py. Let's create a real one.

Open /polls/views.py and replace the vote() function definition with the following one:

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,)))

This key elements of the above code are:

  • request.POST['choice'] returns the ID of the selected choice.

  • The except block is used to redisplay the question with an error message if no choice is provided.

  • HttpResponseRedirect redirects the user to a URL returned by the reverse() function.

  • The reverse() function is used to avoid hardcoding the URL. It accepts the name of the view that we want to pass control to and returns the URL of the voting results for the question.

Don't forget to update the import statements in /polls/views.py as follows:

from django.http import HttpResponseRedirect from django.shortcuts import get_object_or_404, render from django.urls import reverse from .models import Choice, Question

Now, if you go to http://127.0.0.1:8000/polls/ again and answer the question, you should see the following:

Results of voting

Here we are!

Now all features of our application work as designed. You can use the admin site to add as many questions as you like. While the Django server is running, you can access the list of questions at http://127.0.0.1:8000/polls/ and vote as many times as you like:

List of available polls

As you may have noticed, our app has a usability problem. When you click Vote again, it redirects you to the same question. A link to the list of all questions would be much more helpful. How do you fix that?

Check yourself

  1. Open results.html.

  2. Edit the last line to get the following:

    <a href="{% url 'polls:index' %}">Vote again?</a>

Testing the application

Now let’s see how PyCharm helps simplify testing your application.

There is already the file tests.py in the polls directory. By now, this file is empty. Naturally, it is advisable to place the new tests in this particular file. For example, we'd like to make sure our poll is not empty:

import datetime from django.urls import reverse from django.test import TestCase from django.utils import timezone from .models import Question def create_question(question_text, days): time = timezone.now() + datetime.timedelta(days=days) return Question.objects.create(question_text=question_text, pub_date=time) class QuestionViewTests(TestCase): def test_index_view_with_no_questions(self): """ If no questions exist, an appropriate message should be displayed. """ response = self.client.get(reverse('polls:index')) self.assertEqual(response.status_code, 200) self.assertContains(response, "No polls are available.") self.assertQuerysetEqual(response.context['latest_question_list'], [])

To run this test, right-click the background of the file tests.py in the editor, choose the option Run, or just press Ctrl+Shift+F10. PyCharm suggests two options: to run UnitTest (which is defined as the default test runner), or a Django test.

The test results show in the Test Runner tab of the Run tool window:

Running tests

Summary

This brief tutorial is over. You have successfully created and launched a simple Django application. Let's repeat what you managed to do with the help of PyCharm:

  • Created a Django project with an application

  • Launched a Django server

  • Configured a database

  • Created models, views and templates

  • Launched the application

  • Created and executed a test

Last modified: 18 August 2022