In last tutorial we left off by creating and migrating models. This means that we have everything ready and the only thing we need to do is add data into the database. For doing so Django has a Database API which allows us to access and manipulate the database using Python code only. Let's play with this API and learn them on the way. We can use the Python shell to do so. Type the following to open the Python shell
python manage.py shell
Once in the shell, let's explore the Database API.
from polls.models import Question, Choice # Import the model classes we just wrote. # currently the database is empty. Question.objects.all() # Output: # <Queryset > Choice.objects.all() # Output: # <Queryset > # Let's create a new Question first # If you remember the Question model has a pub_date field, which stores a datetime # Although Python has datetime.datetime.now(), # we will use the Django's implementation of the same # which uses the timezone setting to create a datetime # with timezone info included. from django.utils import timezone q = Question(question_text="What would you say, Dear Sir, is up?", pub_date=timezone.now()) # The above statement only creates a Python Model Object. # To persist it in the database we do the following q.save(); # Above 2 statements can be combined using the objects.create() method as follows # It creates the Python model and saves it in Database in a single statement q = Question.objects.create(question_text="What would you say, Dear Sir, is up?", pub_date=timezone.now()) # Access the model fields as Python attributes q.id # Output: # 1 # Note: In some databases the above value may be 1L instead of just being 1. # It is completely normal, # Python read them as Long integers rather than regular integers. q.question_text # Output: # "What's up?" q.pub_date # Output: # datetime.datetime(2017, 6, 01, 13, 0, 0, 775217, tzinfo=<UTC>) # Changing the value is as simple as changing the attributes and then calling save(). q.question_text = "What's up" q.save() # To list all the questions in database, we use objects.all(). Question.objects.all() # Output: # <QuerySet [<Question: Question object>]>
<Question: Question object> is a completely useless annotation for an object. We can change this by mentioning the string representation for any Model object. We do so by adding a
__str__() method in the model declaration.
# Python Code # polls/models.py from django.db import models from django.utils.encoding import python_2_unicode_compatible @python_2_unicode_compatible # only if you need to support Python 2 class Question(models.Model): # ... def __str__(self): return self.question_text @python_2_unicode_compatible # only if you need to support Python 2 class Choice(models.Model): # ... def __str__(self): return self.choice_text
Now the Question object will be displayed as follows:
from polls.models import Question, Choice Question.objects.all() # Output: # <QuerySet [<Question: What's up?>]>
It’s important to add
__str__() methods to your models, not only for your own convenience when dealing with the interactive prompt, but also because objects’ representations are used throughout Django’s automatically-generated admin.
We could also add custom methods to the model and make them rich with convenience methods.
# Python Code # 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)
Now we can get a computed information using this method for a Question model object. Note the addition of
import datetime and
from django.utils import timezone, to reference Python’s standard
datetime module and Django’s time-zone-related utilities in
Save these changes and start a new Python interactive shell again.
from polls.models import Question, Choice # Django provides a rich database lookup API that's entirely driven by # keyword arguments. Question.objects.get(id=1) # Output: # <Question: What's up?> Question.objects.filter(id=1) # Output: # <QuerySet [<Question: What's up?>]> Question.objects.filter(question_text__startswith='What') # Output: # <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) # Output: # <Question: What's up?> # Request an ID that doesn't exist, this will raise an exception. Question.objects.get(id=2) # Output: # 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) # Output: # <Question: What's up?> # Make sure our custom method worked. q = Question.objects.get(pk=1) q.was_published_recently() # Output: # 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() # Output: # <QuerySet > # Create three choices. q.choice_set.create(choice_text='Not much', votes=0) # Output: # <Choice: Not much> q.choice_set.create(choice_text='The sky', votes=0) # Output: # <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 # Output: # <Question: What's up?> # And vice versa: Question objects get access to Choice objects. q.choice_set.all() # Output: # <QuerySet [<Choice: Not much>, <Choice: The sky>, <Choice: Just hacking again>]> q.choice_set.count() # Output: # 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) # Output: # <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()
Much more can be done using this Database API. We will dig deeper into the subject later in the series.
Django comes packaged with an admin site that can be used to manage the Data by the staff or clients. This site is not for site visitors to use rather for the site managers to interact with the data, like add, change and delete content. Any model can be added into this site for manipulation by the staff. This is done with very less configuration to plug any model into the Django admin site.
Let's see how we use the admin site. 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.
You will then be prompted for your desired email address:
Email address: email@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.
Now the superuser with access to everything in the admin site is created. Using this user credentials we can login into the admin site. But we have to start the server to be able to do so. To do that we run the following command:
python manage.py runserver
This starts a development server. Now open a Web browser and go to "/admin/" on your local domain - e.g., http://127.0.0.1:8000/admin/ you will see the admin's login screen as follows:
Login with the superuser credentials you registered with previously. You will see the Django admin index page when logged in.
Users models are provided by
django.contrib.auth, the authentication framework shipped with Django.
But we don't see our Models here. For that we only need to do one thing: we need to tell the admin that
Question objects are to be displayed in admin site. To do this, we add this line in polls/admin.py (or admin.py file in your choice of app).
# Python code # polls/admin.py from django.contrib import admin from .models import Question admin.site.register(Question)
Now you can explore the whole admin site and get a feel for the same.
We develop web applications to our customers using python/django/angular.
Contact us at firstname.lastname@example.org