Skip to content

DJango Console - shell_plus CLI

For some operations its is easier or necessary to directly interact with the DJango codebase and use the console, rather than using the web interface or utility scripts.

LabID comes with the DJango shell plus extension.

Starting the shell

Navigate to the project root directory, there were the manage.py file resides.

Make sure your environment is active and you are connected to the correct database

Be careful

The django shell allows you full access to the backend, permission checking and input validation are mostly not executed and can always be circumvented. Please ensure you know what you are doing and only resolve to using the shell as a last resort or on instructions by the developers.

# ensure the PYTHONPATH is set correctly
./manage.py shell_plus
# list the current database setting
$ settings.DATABASES["default"]

Intro

This should open the actual shell with most LabID models pre-imported. If you get an error like "could not import module ..", then ensure you are in the right environment, have all dependencies installed. Also ensure your PYTHONPATH includes the current directory,i.e.export PYTHONPATH=${PWD}:$PYTHONPATH

You can now for example:

# get all available Specimen stock items:
Specimen.objects.all()
# or only of type strain
Specimen.objects.filter(type__name='STRAIN')

Load an ldap user

If a ldap user hasn't logged in to the system before, it will not be available in the system and thus not be visible in drop down menus. To preload such a known user we can execute the following:

> from core.auth import CustomLDAPBackend
> user = CustomLDAPBackend().populate_user('scholtal')
DEBUG Ensuring the user and its primary group has all default global permissions
DEBUG Created Django user scholtal
DEBUG Populating Django user scholtal
DEBUG Ensuring the user and its primary group has all default global permissions

Customproperties

This shows an example on how to change the choices of a custompropertytype. As you will see, this only applies to a plain TEXT field. Choices of CVTERM customproperty can just be added through the Admin UI in the Vocabulary section.

sa = CustomPropertyType.objects.get(name="stocks_antibody_ab_type")
# The choices have to be given as a json string.
sa.choices = "[[\"PRIMARY\", \"PRIMARY\"], [\"SECONDARY\", \"SECONDARY\"]]"
sa.save()

Reset field order

In case something went wrong with the field display order of a given model type, you can use the shell to reset it. For example, to reset the field order on all Consumable stock types, execute the following. Be careful though, this resetted fieldorder might not be what you want.

for stock_type in TypeStore.objects.filter(content_type__model='Consumable'):
  FieldOrder.objects.reset_field_order(stock_type, User.objects.get(username='yourusername'))

Filtering items by creation time range

If you want to bulk update or remove items, you can of course use this shell. This example shows how to bulk delete a number of Stock items based on their creation date. Useful when a bulk import was executed twice or wrong data was loaded.

import datetime
import pytz
from core.utils.shortcuts.auth import get_admin_user

# create the timezone aware times
enddatetime = pytz.timezone('Europe/Berlin').localize(datetime.datetime(2016, 10, 18, 12, 00))
startdatetime = pytz.timezone('Europe/Berlin').localize(datetime.datetime(2016, 10, 18, 11, 50))
admin = get_admin_user()
# create the queryset
plasmids = Consumable.objects.filter(
    type__name="PLASMID",
    owner__username="userA",
    created__range=(startdatetime, enddatetime))
# check results
plasmids.count()
# and delete
plasmids.true_delete(user=admin)

Update stock items to add stock location

The following snippet will show how to add a particular stock location to a list of stock items. The stock location in this case, is a freezer,_i.e._a StorageEquipment object.

freezer_location = Location.objects.get(equipment__name="Liebherr-30freezer")
for plasmid in Consumable.objects.filter(type__name="PLASMID", owner__username="userA"):
    # get the appropriate stocklocation model and create the stock location instance
    #_i.e._ConsumableLocation()
    plasmid_location = plasmid.stock_locations.model(
        location_id=freezer_location.id,
        container_name="", # add container name if needed
        stock=plasmid)
    # save
    plasmid_location.save()

Creating a CV Term

Although easier through the UI, the shell also gives you the option to create CV Terms as shown here.

from permissions.shortcuts import bulk_assign_group_perm
# set the current user to the admin user to use in the object creation
from core.utils.shortcuts.auth import get_admin_user
admin = get_admin_user()

# create the new Term
Term.objects.create(
    name="Bacillus subtilis", dbxref_id="Bacillus subtilis", category=Category.objects.get(name="species"),
    owner=admin, modified_by=admin, created_by=admin)

# assigning view permissions to certain groups - (unsupported)
term_queryset = Term.objects.filter(name="Bacillus subtilis")
for group in Group.objects.filter(name__startswith="Staff_"):
   bulk_assign_group_perm(["view"], group, term_queryset)

or you've got a list of terms needed to be added in a category -

from core.utils.shortcuts.auth import get_admin_user
admin = get_admin_user()

terms = ["ATK_Algae_FlashFrozen", "ATK_Whole_EtOH"]

category = Category.objects.get(name="trec_protocol_codes")
defaults = {
  "category":category,
  "owner": admin,
  "owned_by": admin.primary_group,
  "public":True,
  "created_by": admin,
  "modified_by": admin,
}
for term in terms:
  Term.objects.create(name=term, dbxref_id=term, "description":"", **defaults)