How best to return from a cliffhanger ending – in a previous post we used Django’s Model class .save() to write network state—that is CLI standard output transformed to JSON using pyATS—into a PostgreSQL database table. Django also helped us convert, or migrate, a Pythonic class-based model into this SQL table in the first place.
Now that we have populated the database, we can shift our focus from the back-end (the modelling) to the front-end (presenting the data to our stakeholders with web-development tools). But before we start making HTML templates we must confirm that our modelled data and controller function actually populated the database. We also will want to provide the user various ways inside of Views to trigger the automation (controller Python pyATS jobs) from the application’s web interface.
Giving The User Control Over The Network Automation
The first set view and capability I write is a page, the On-Demand Centre, that provides users the ability to either:
- Click a button to trigger the pyATS show ip interface brief job against all devices in the Devices table
- Provide an input box the user can keyword-filter using the keys from the Devices model to reduce the number of devices from which we parse show ip interface brief
Recall the trinity between URLs, Views, and Templates from the first article. We first need to define the URL the user will visit in their browser to reach the On-Demand Centre. Django also allows us to include other folders so we can actually make a sub-program to Merlin called OnDemand. This also helps keep the application modular and we can store all URLs and Views inside a dedicated subfolder called OnDemand.
We have configured http://localhost:8000/OnDemand as a URL that calls the View “button” (views.button) as well as a placeholder page for the View to call when the specific button is pressed. Let’s take a look at these two Views.
Button is simply the landing page that presents the user with all of the available buttons. The show_ip_int_brief_all_ondemand view triggers the pyATS job (os.system command), which in turn populates the database with fresh network state.
Moving into the HTML templates, first let’s create base.html. This is a base layer of HTML, Cascading Style Sheets (CSS), JavaScripts (JS), and any other content we want to be inherited by every downstream HTML template (for example the Merlin logo).
Brief interlude – all of those scripts and stylesheets you see included in the headers of all HTML pages in this project are from either datatables.net or getbootstrap.com – which in my case specifically enhance the HTML tables I use to present network state to the users. Datatables allows me to make a commercial-grade UI for free and with very little work. Bootstrap provides enterprise-grade visualizations such as process spinners.
Back to our templates – now that we have a base.html we can build our On-Demand Centre sub-page. You will notice this template extends base.html thus inheriting all of the scripts and static files. You will also notice the table has an ID and class we will reference later.
At the end of the ondemand.html template we will add the datatable JavaScript that will transform the plain-old-HTML-table into an interactive datatable.
We want this button click to trigger the pyATS automation. It will take several seconds to complete, so we can display a bootstrap spinner while the user waits. Using our own main.js file we can add this script.
The spinner spins while the pyATS job runs in the background on the server.
The button (URL – View – Template) is effectively a bulk operation against all devices in the Devices table. But what if we want to update the network only for a single device or group of devices? Using an input box in the HTML template instead of a button we can provide the user this capability as well. We will need a new URL and View and will enhance the existing template.
This view will be a little more complex and we will make a new Class from the ListView. We must reference the template where the input will be coming from (template_name) and then define, specifically, a get_queryset(self) function.
You will see a reference to a new model, DynamicJobInput, which I decided to set up (and migrate) into the database to store the users’ input (input_field). You will notice a different pyATS job – filter_job.py – is then executed. The only difference between the pyATS job that the button click runs and the job that the input text job runs is that we filter, using the Q package (think of this as a powerful OR operator), the devices against the input.
Our last step is to add the Input text box into the template and optionally the list of available keywords to help guide the user.
The final On-Demand Centre looks great, is easy to use, and provides users the ability to either click a button or keyword-limit the show ip interface brief command and refresh the PostgreSQL database with real-time network state.
We are just getting started with Views! I thought it important to make the connection between the View and Controller in the Model View Controller approach. Next time we will focus strictly on presentation options. Until then, stay safe and start writing some Python!