Project Structure¶
Basically, the project has the following folder structure:
TkDQMDoctor
├───certhelper
│ │ admin.py
│ │ apps.py
│ │ filters.py
│ │ forms.py
│ │ manager.py
│ │ models.py
│ │ query.py
│ │ signals.py
│ │ tables.py
│ │ urls.py
│ │ views.py
│ │ __init__.py
│ │
│ ├───migrations
│ ├───static
│ ├───templates
│ └───utilities
├───doc
├───dqmsite
│ settings.py
│ test_ci_settings.py
│ test_settings.py
│ urls.py
│ wsgi.py
│ __init__.py
│
├───runregistry
├───static
└───tests
├───certhelper
├───fixtures
├───selenium
└───utils
runregsitry¶
runregistry is a python module, dedicated for accessing the Run
Registry. Although a Run Registry client for python called rhapi.py
already exists (https://github.com/valdasraps/resthub), it is not
compatible with Python 3. Therefore a new client had to be written that
is Python 3 compliant. If interested a dedicated GitHub repository for a
Python 3 Run Registry client can be found at
https://github.com/CMSTrackerDPG/runregcrawlr
dqmsite¶
The dqmsite module contains the settings files for both testing and
production environment.
tests¶
The tests module is dedicated to unit tests. They can be executed
locally via pytest or automatically via Travis CI when pushing a
branch to GitHub. A detailed description about testing can be found in
chapter Testing.
static¶
The static folder consists of static files like javascript files,
css files and images. This folder together with static files from other
applications will be
collected
and then served by the
WhiteNoise middleware when
deploying to production.
certhelper¶
certhelper is the main application, the “Certification Helper”. All
the shifter and shift leader related tools are implemented there.
urls.py¶
https://docs.djangoproject.com/en/1.11/topics/http/urls/
Every time a new page is added or the path of an existing page updated,
changes to urls.py have to be made. An excerpt of this file from the
TkDQmDoctor website looks like this:
urlpatterns is a list of URLs which consist of the URL path
expressed in regular expressions, the view function which is called when
visiting the URL and a unique name for easy referral.
The views are implemented in views.py and can be either function
based views or class-based views. In the example above the view
shiftleader_view is a function based view and
```CreateRun````is a class-based view which can be easily found
out by the python naming convention. Function names should always be
lowercase with an underscore as word separator and class names should
always start with a capital letter with the CamelCase naming convention.
If the view is a class-based view then additionally the .as_view()
method of that class has to be called in the second url parameter.
The first view that is called when a user visits
https://tkdqmdoctor.web.cern.ch/ is views.listruns as it is the only
pattern in the urlpatterns list that matches the url: r'^$'
views.py¶
https://docs.djangoproject.com/en/1.11/topics/http/views/
This views.py file consists of all the views that exist in the app.
A view function takes a Web request and returns a Web response. In most
cases the response consists of the HTML content of a web page, that will
be displayed when a user tries to visit a page. It can also be a 404
error, a JSON file, an image, etc.
A view has to be mapped to a URL in the urls.py file with an unambiguous url path.
Most commonly a view uses a template to generate HTML code. In order to specify which data should be used in the template the context dictionary has to be filled accordingly
context["mydata""] = "Hello World"
models.py¶
https://docs.djangoproject.com/en/1.11/topics/db/models/
This file contains classes which inherit from django.db.models.Model. Each model maps to a single database table and each instance of the python class represents a line in that table.
The most important model is the RunInfo model. It represents a certified run that will be created when a shifter submits the “Add Run” form.
class RunInfo(SoftDeletionModel):
# ...
userid = models.ForeignKey(User, on_delete=models.CASCADE, blank=True)
type = models.ForeignKey(Type, on_delete=models.CASCADE)
reference_run = models.ForeignKey(ReferenceRun, on_delete=models.CASCADE)
run_number = models.PositiveIntegerField()
number_of_ls = models.PositiveIntegerField()
int_luminosity = models.DecimalField(max_digits=20, decimal_places=2)
# ...
manager.py¶
https://docs.djangoproject.com/en/1.11/topics/db/managers/
Managers are responsible for accessing the database for certain Django models. Custom managers for a particular model extend the functionality of the base Manager. This extra functionality, for example, could be to only show runs that were certified as “Good”. Every Django model has at least one manager, most commonly the objects manager.
query.py¶
https://docs.djangoproject.com/en/1.11/ref/models/querysets/
When a manager accesses the database a QuerySet object will be returned containing the desired entity. The QuerySet object itself has methods which can be used to further tailor the database query.
For example, does the cosmics method filter the QuerySet to only
“Cosmics” runs that were certified, rather than “Collisions”.
def cosmics(self):
return self.filter(type__runtype="Cosmics")
tables.py¶
https://django-tables2.readthedocs.io/en/latest/
When data should be presented on the website it can often be done in a simple HTML table. The tables.py describe how these tables should look like and what attributes of what model should be used.
signals.py¶
https://docs.djangoproject.com/en/1.11/topics/signals/ https://django-allauth.readthedocs.io/en/latest/signals.html
Signals provide a way of notifying an application when a certain event happens. One signal could, for example, be to automatically update the privileges (like shift leader or admin status) when a user performs a login into the website.
admin.py¶
https://docs.djangoproject.com/en/1.11/ref/contrib/admin/
Django provides an automatic admin interface which manages all the models. This admin interface can be customized in the admin.py file.
apps.py¶
https://docs.djangoproject.com/en/1.11/ref/applications/
Before an application can be used it has to be configured in a registry called django.apps which is done in apps.py
filters.py¶
https://django-filter.readthedocs.io/en/master/index.html
It is often desired to only show a small portion of a database table. Filters provide an easy way of filtering this data based on specific criteria. One example of a filter is the run filter in the shifter view.
The way the filter should behave is specified in filters.py
forms.py¶
https://docs.djangoproject.com/en/1.11/topics/forms/
When certifying a new run or updating an existing run the data has to be entered in a form. forms.py specifies which attributes and which model should be used and also how the valid form data should look like. Form validation is performed with one of the clean methods of a form class.
class RunInfoForm(ModelForm):
# ...
def clean(self):
cleaned_data = super(RunInfoForm, self).clean()
is_sistrip_bad = cleaned_data.get('sistrip') == 'Bad'
is_tracking_good = cleaned_data.get('tracking') == 'Good'
if is_sistrip_bad and is_tracking_good:
self.add_error(None, ValidationError(
"Tracking can not be GOOD if SiStrip is BAD. Please correct."))
# ...
templates¶
https://docs.djangoproject.com/en/1.11/ref/templates/language/
A template is a text document which can generate HTML code. Templates have a close relationship with views, which take care of retrieving the actual data that needs to be displayed. The data that should be displayed in the template are defined in the context dictionary of the view.
It can then be accessed directly like this:
{{ mydata }}