24. Using the ORM in views.py
We’ve now looked at the underlying database and building a simple normalized database. We’ve also briefly looked at how to add some data to your database via the administration interface, or via a script that you might write.
This should hopefully give us enough background knowledge to allow us to consider how to work with data inside our web application at runtime.
Let’s use this opportunity to build a simple web page, that can show the contents of our database to the users.
Firstly we navigate in VSC to bioweb/urls.py as we want to send various user requested paths to our web application. We need to add path(”, include(‘genedata.urls’)) here:
urlpatterns = [ path('', include('genedata.urls')), path('admin/', admin.site.urls), ]
We also need to ensure we are importing include too:
from django.urls import include, path
We’re making a promise that there is a urls file within genedata here, so we need to go to the genedata folder and create a new urls.py file here.
from django.urls import include, path from . import views urlpatterns = [ path('', views.index, name='index'), ]
If we run the server now in CMD, we will get this error:
AttributeError: module 'genedata.views' has no attribute 'index'
In our web app in the views file we don’t have anything called index. We’ve promised this function exists, but it doesn’t yet, so we can go ahead and fix that quite simply.
In genedata/views.py we can add a simple test response:
def index(request): response = "Hello" return render(request, 'genedata/index.html', {'message': response})
Once we save views.py this will trigger a reload of the server and the error message disappears.
What we need to do now is create the template that it needs to use.
Inside the genedata folder we can create a new folder called templates, and inside here another new folder called genedata. Then inside here we can create a new index.html file and set this up as follows:
<html> <head> </head> <body> <p> {{ message }} </p> </body> </html>
If I now run the server and try to go to http://127.0.0.1:8000/ I may find that the host is not allowed. I will need to go back and add localhost and 127.0.0.1 to the allowed hosts in settings.py:
ALLOWED_HOSTS = [ 'localhost', '127.0.0.1', ]
Now if I go to http://127.0.0.1:8000/ I will see that I get the word hello returned. This is because the variable response has been set to ‘hello’ in views.py, and this is returned in the next line of the method on that page. Viewing the page source will see our template, with hello instead of {{ message }}.
So now we know the template works, we want to make use of the models which read the database. So back to views.py and add
from .models import *
and then put this in the index function:
def index(request): genes = Gene.objects.all() return render(request, 'genedata/index.html', {'genes': genes})
genes is asking for objects.all – it’s waht Django calls a Query Set. It’s an iterable object that represents the results of a database query.
objects.all is very much like the SQL command SELECT *
In this instance, you can essentially think of it as a python list where each element in the list is one row from the gene database table.
The database query is not run, however, until we attempt to iterate over this object.
We can now jump back to index.htm; and show the user the data in this object by making this change:
<html> <head> </head> <body> <h1>D.Bucha Genes</h1> <table> <tr><th>Gene ID</th></tr> {% for gene in genes %} <tr><td>{{gene.gene_id}}</td></tr> {% endfor %} </table> </body> </html>
This part is the iteration:
<tr><th>Gene ID</th></tr> {% for gene in genes %} <tr><td>{{gene.gene_id}}</td></tr>
D.Bucha is a made up name for this exercise. Now if we go back to http://127.0.0.1:8000/ we’ll see a list of genes.
We’re seeing the list of genes called gene_id we specified that name in the template. Because in the Gene class in models.py we added this:
def __str__ (self): return self.gene_id
we could get the same result if we just wrote {{gene}} – it returns gene_id.
We could show more detail by having a page for each gene, like this in our template:
<tr><td><a href="/gene/{{gene.pk}}" >{{gene}}</a></td></tr>
We now have links and we need to create the page to show these.
In urls.py we can add a new path which handles requests for genes:
urlpatterns = [ path('', views.index, name='index'), path('gene/', views.gene, name='gene'), ]
We will also need to go to views.py and add a new function called gene:
def gene(request, pk): gene = Gene.objects.get(pk=pk) return render(request, 'genedata/gene.html', {'gene': gene})
What’s happening here? In urlpatterns the new path is capturing an integer where it says . In views we then need to check that this pk equals the same pk in our database, hence the (pk=pk).
It’s like the SQL command SELECT * WHERE pk=this value we passed to it (we passed it in def gene(request, pk). It’s just confusing that we called it pk here too)
We can see now that a path to gene/1 will need to go to a template in genedata called gene.html so we will need to create that.
<html> <head> </head> <body> <h1>{{gene}}</h1> <table> <tr><th>Key</th><th>Value</th></tr> <tr><td>Entity: </td><td>{{gene.entity}}</td></tr> <tr><td>Start: </td><td>{{gene.start}}</td></tr> <tr><td>Stop: </td><td>{{gene.stop}}</td></tr> <tr><td>Sense: </td><td>{{gene.sense}}</td></tr> <tr><td>Start Codon: </td><td>{{gene.start_codon}}</td></tr> </table> </body> </html>
This then creates a template and we can see the data on each page.
Wednesday 3 November 2021, 674 views
Next post: 25. Joins, filters and chaining commands Previous post: 23. Adding to the database by writing a script
Advanced Web Development index
- 38. Writing API tests
- 37. Testing in Django
- 36. Class-based views in the Django REST framework
- 35. Building a RESTful web service in Django
- 34. Introduction to CRUD, REST and APIs
- 33. Refactoring with generic views in Django
- 32. Django validators
- 31. Django forms (2) – using the ModelForm class
- 30. Django forms (1)
- 29. JavaScript basics
- 28. Adding CSS to the template
- 27. Django templating
- 26. Deleting and updating records
- 25. Joins, filters and chaining commands
- 24. Using the ORM in views.py
- 23. Adding to the database by writing a script
- 22. Adding to the database with Django Admin
- 21. Migrations
- 20. ORM – work through example
- 19. An introduction to the Object-Relational Mapper
- 18. Altering the database
- 17. SQL functions and summaries
- 16. SQL Query performance
- 15. Queries and table joins in SQL
- 14. Inserts and queries in SQL
- 13. Good practice in relational database design
- 12. Limitations to database modelling
- 11. Building a database using SQL
- 10. Introduction to PostgreSQL
- 9. How to start writing a new application in Django
- 8. Building a lightweight project
- 7. Django URLs
- 6. Django templates
- 5. Django models
- 4. Django views
- 3. Creating a new hello app
- 2. Creating a new virtual environment
- 1. Setting up Django
Leave a Reply