how to make django management command not open a transaction?

  • Last Update :
  • Techknowledgy :

You can specify database connections with read uncommitted with the following database settings in your settings.py:

DATABASES: {
   'default': {
      ...
   }
   'uncommitted_db': {
      'ENGINE': ...
         'NAME': ...
         'USER': '...',
      'PASSWORD': '...',
      'HOST': '...',
      'OPTIONS': {
         'init_command': 'SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED'
         #MySQL 'init_command': 'SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED'
         #Postgres
      }
   }
}

With this in place you can access your non-transactional database connection using Django's normal multidatabase syntax:

Model.objects.using('uncommitted_db').all()

Of course, you might not want to have your non-transactional database connection globally available in your entire application, so you'd ideally want a way to have it only available during the execution of this management command. Unfortunately, management commands don't work like that: once you hit the handle method on the Command class, your settings.py has already been parsed and your database connections have already been created. If you can find a way to re-initialise Django with a new set of database settings after runtime, or having a logical split in your settings.py based on your launch conditions, like so:

import sys
if 'some_management_cmd' in sys.argv:
   DATABASES['default']['OPTIONS']['init_command'] = 'SET TRANSACTION...'

Suggestion : 2

You can specify database connections with read uncommitted with the following database settings in your settings.py:,How to set a cronjob to run a Django management command in AWS elastic beanstalk,How do I make Django signal handlers not fail silently when an exception is encountered in the signal handler?,How to execute python manage.py django management command via button on the website on Heroku

You can specify database connections with read uncommitted with the following database settings in your settings.py:

DATABASES: {
   'default': {
      ...
   }
   'uncommitted_db': {
      'ENGINE': ...
         'NAME': ...
         'USER': '...',
      'PASSWORD': '...',
      'HOST': '...',
      'OPTIONS': {
         'init_command': 'SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED'
         #MySQL 'init_command': 'SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED'
         #Postgres
      }
   }
}

With this in place you can access your non-transactional database connection using Django's normal multidatabase syntax:

Model.objects.using('uncommitted_db').all()

Of course, you might not want to have your non-transactional database connection globally available in your entire application, so you'd ideally want a way to have it only available during the execution of this management command. Unfortunately, management commands don't work like that: once you hit the handle method on the Command class, your settings.py has already been parsed and your database connections have already been created. If you can find a way to re-initialise Django with a new set of database settings after runtime, or having a logical split in your settings.py based on your launch conditions, like so:

import sys
if 'some_management_cmd' in sys.argv:
   DATABASES['default']['OPTIONS']['init_command'] = 'SET TRANSACTION...'

Suggestion : 3

The new custom command can be called using python manage.py closepoll <poll_ids>.,The handle() method takes one or more poll_ids and sets poll.opened to False for each one. If the user referenced any nonexistent polls, a CommandError is raised. The poll.opened attribute does not exist in the tutorial and was added to polls.models.Question for this example.,The same closepoll could be easily modified to delete a given poll instead of closing it by accepting additional command line options. These custom options can be added in the add_arguments() method like this:,The closepoll.py module has only one requirement – it must define a class Command that extends BaseCommand or one of its subclasses.

polls /
   __init__.py
models.py
management /
   __init__.py
commands /
   __init__.py
_private.py
closepoll.py
tests.py
views.py
from django.core.management.base
import BaseCommand, CommandError
from polls.models
import Question as Poll

class Command(BaseCommand):
   help = 'Closes the specified poll for voting'

def add_arguments(self, parser):
   parser.add_argument('poll_ids', nargs = '+', type = int)

def handle(self, * args, ** options):
   for poll_id in options['poll_ids']:
   try:
   poll = Poll.objects.get(pk = poll_id)
except Poll.DoesNotExist:
   raise CommandError('Poll "%s" does not exist' % poll_id)

poll.opened = False
poll.save()

self.stdout.write(self.style.SUCCESS('Successfully closed poll "%s"' % poll_id))
self.stdout.write("Unterminated line", ending = '')
class Command(BaseCommand):
   def add_arguments(self, parser):
   # Positional arguments
parser.add_argument('poll_ids', nargs = '+', type = int)

# Named(optional) arguments
parser.add_argument(
   '--delete',
   action = 'store_true',
   help = 'Delete poll instead of closing it',
)

def handle(self, * args, ** options):
   #...
   if options['delete']:
   poll.delete()
#...
from django.core.management.base
import BaseCommand, no_translations

class Command(BaseCommand):
   ...

   @no_translations
def handle(self, * args, ** options):
   ...
self.stdout.write(self.style.SUCCESS('...'))

Suggestion : 4

Write a management command where Django doesn't even touch the database leaving all the transaction control completely manual? ,Write a management command where you can define transaction characteristics only for it? ,I'm writing a management command where I want to change the default isolation level. Django and my database will default it to "READ COMITTED" and I need it to be "READ UNCOMMITTED" only for this particular management command., django-admin command has the advantage of being available wherever you are on your filesystem. Django comes with a number of builtin management commands, using python manage.py [command] or, when manage.py has +x (executable) rights simply ./manage.py [command] .


. / manage.py my_command
polls / __init__.pymodels.pymanagement / __init__.py commands / __init__.py _private.py closepoll.pytests.pyviews.py
from django.core.management.base
import BaseCommand, CommandError from polls.models
import Question as Poll class Command(BaseCommand): help = 'Closes the specified poll for voting'
def add_arguments(self, parser): parser.add_argument('poll_ids', nargs = '+', type = int) def handle(self, * args, ** options): for poll_id in options['poll_ids']: try: poll = Poll.objects.get(pk = poll_id) except Poll.DoesNotExist: raise CommandError('Poll "%s"does not exist' % poll_id) poll.opened = False poll.save() self.stdout.write(self.style.SUCCESS('Successfully closed poll "%s"' % poll_id))
self.stdout.write("Unterminated line", ending = '')
class Command(BaseCommand): def add_arguments(self, parser): # Positional arguments parser.add_argument('poll_ids', nargs = '+', type = int) # Named(optional) arguments parser.add_argument('--delete', action = 'store_true', help = 'Delete poll instead of closing it', ) def handle(self, * args, ** options): #...
   if options['delete']: poll.delete() #...
from django.core.management.base
import BaseCommand, no_translations class Command(BaseCommand): ...@no_translationsdef handle(self, * args, ** options): ...

Suggestion : 5

To perform actions in Django using commandline or other services (where the user/request is not used), you can use the management commands.,Note that starting a command can take a few second (because of the import of the modules). So in some cases it is advised to create daemon processes instead of management commands.,The name of the management command is the name of the file containing it. To run the command in the example above, use the following in your project directory:,For each command a separate file needs to be created: myapp/management/commands/my_command.py (The management and commands directories must have an empty __init__.py file)

For each command a separate file needs to be created: myapp/management/commands/my_command.py
(The management and commands directories must have an empty __init__.py file)

from django.core.management.base
import BaseCommand, CommandError

#
import additional classes / modules as needed
# from myapp.models
import Book

class Command(BaseCommand):
   help = 'My custom django management command'

def add_arguments(self, parser):
   parser.add_argument('book_id', nargs = '+', type = int)
parser.add_argument('author', nargs = '+', type = str)

def handle(self, * args, ** options):
   bookid = options['book_id']
author = options['author']
# Your code goes here

# For example:
   # books = Book.objects.filter(author = "bob")
#
for book in books:
   # book.name = "Bob"
# book.save()

The name of the management command is the name of the file containing it. To run the command in the example above, use the following in your project directory:

python manage.py my_command

Suggestion : 6

Aug 27, 2018

python manage.py help
Type 'manage.py help <subcommand>' for help on a specific subcommand.

   Available subcommands:

   [auth]
   changepassword
   createsuperuser

   [contenttypes]
   remove_stale_contenttypes

   [django]
   check
   compilemessages
   createcachetable
   dbshell
   diffsettings
   dumpdata
   flush
   inspectdb
   loaddata
   makemessages
   makemigrations
   migrate
   sendtestemail
   shell
   showmigrations
   sqlflush
   sqlmigrate
   sqlsequencereset
   squashmigrations
   startapp
   startproject
   test
   testserver

   [sessions]
   clearsessions

   [staticfiles]
   collectstatic
   findstatic
   runserver
mysite / < --project directory |
   --core / < --app directory |
   | --management /
   |
   | + --commands /
   |
   | + --my_custom_command.py < --module where command is going to live |
   | --migrations /
   |
   | + --__init__.py |
   | --__init__.py |
   | --admin.py |
   | --apps.py |
   | --models.py |
   | --tests.py |
   + --views.py |
   --mysite /
   |
   | --__init__.py |
   | --settings.py |
   | --urls.py |
   | --wsgi.py +
   --manage.py
python manage.py my_custom_command
from django.core.management.base
import BaseCommand
from django.utils
import timezone

class Command(BaseCommand):
   help = 'Displays current time'

def handle(self, * args, ** kwargs):
   time = timezone.now().strftime('%X')
self.stdout.write("It's now %s" % time)
python manage.py what_time_is_it

Suggestion : 7

Throughout the previous chapters -- including this one -- you've relied on management commands invoked through the manage.py script included in all Django projects. For example, to start the development server of a Django project you've used the runserver command (e.g. python manage.py runserver) and to consolidate a project's static resources you've used the collectstatic command (e.g. python manage.py collectstatic).,In most circumstances, it's rare to have a fixed Django management command like the one in listing 5-33 that uses no arguments to alter its logical workflow. For example, the Django runserver command accepts argument like addrport and --nothreading to influence how a web server is launched.,For example, if a user uploads an image in a Django application and you want the image to become publicly accessible, you'll need to run the collectstatic command so the image makes its way to the public & consolidation location (STATIC_ROOT) . Similarly, you may want to run a cleanuprofile command every time a user logs in.,What I'll do next is describe how to create custom management commands in your Django apps, so you can simplify the execution of routine or complex tasks through a single instruction.

Listing 5-33. Django management command class with no arguments

from django.core.management.base
import BaseCommand, CommandError
from django.conf
import settings

class Command(BaseCommand):
   help = 'Send test emails'

def handle(self, * args, ** options):
   for admin_name, email in settings.ADMINS:
   try:
   self.stdout.write(self.style.WARNING("About to send email to %s" % (email)))
# Logic to send email here
# Any other Python logic can also go here
self.stdout.write(self.style.SUCCESS('Successfully sent email to "%s"' % email))
raise Exception
except Exception:
   raise CommandError('Failed to send test email')

Listing 5-34. Django management task class with arguments

from django.core.management.base
import BaseCommand, CommandError
from django.conf
import settings

class Command(BaseCommand):
   help = 'Clean up stores'

def add_arguments(self, parser):
   # Positional arguments are standalone name
parser.add_argument('store_id')

# Named(optional) arguments start with--
parser.add_argument(
   '--delete',
   default = False,
   help = 'Delete store instead of cleaning it up',
)
def handle(self, * args, ** options):
   # Access arguments inside ** options dictionary #options = {
      'store_id': '1',
      'settings': None,
      'pythonpath': None,
      # 'verbosity': 1,
      'traceback': False,
      'no_color': False,
      'delete': False
   }

Listing 5-35. Django management task folder structure and location

+-<BASE_DIR_project_name>
   |
   +-manage.py
   |
   |
   +---+-<PROJECT_DIR_project_name>
      |
      +-__init__.py
      +-settings.py
      +-urls.py
      +-wsgi.py
      |
      +-about(app)-+
      | +-__init__.py
      | +-models.py
      | +-tests.py
      | +-views.py
      | +-management-+
      | +-__init__.py
      | +-commands-+
      | +-__init__.py
      | |
      | |
      | +-sendtestemails.py
      |
      +-stores(app)-+
      +-__init__.py
      +-models.py
      +-tests.py
      +-views.py
      +-management-+
      +-__init__.py
      +-commands-+
      +-__init__.py
      |
      |
      +-cleanupstores.py
      +-updatemenus.py

Suggestion : 8

To do this, just add a management/commands directory to the application. Django will register a manage.py command for each Python module in that directory whose name doesn’t begin with an underscore. For example:,The handle() method takes one or more poll_ids and sets poll.opened to False for each one. If the user referenced any nonexistent polls, a CommandError is raised. The poll.opened attribute does not exist in the tutorial and was added to polls.models.Question for this example.,A management command which takes one or more installed application labels as arguments, and does something with each of them.,On Python 2, be sure to include __init__.py files in both the management and management/commands directories as done above or your command will not be detected.

To do this, just add a management/commands directory to the application. Django will register a manage.py command for each Python module in that directory whose name doesn’t begin with an underscore. For example:

polls /
   __init__.py
models.py
management /
   __init__.py
commands /
   __init__.py
_private.py
closepoll.py
tests.py
views.py

To implement the command, edit polls/management/commands/closepoll.py to look like this:

from django.core.management.base
import BaseCommand, CommandError
from polls.models
import Question as Poll

class Command(BaseCommand):
   help = 'Closes the specified poll for voting'

def add_arguments(self, parser):
   parser.add_argument('poll_id', nargs = '+', type = int)

def handle(self, * args, ** options):
   for poll_id in options['poll_id']:
   try:
   poll = Poll.objects.get(pk = poll_id)
except Poll.DoesNotExist:
   raise CommandError('Poll "%s" does not exist' % poll_id)

poll.opened = False
poll.save()

self.stdout.write(self.style.SUCCESS('Successfully closed poll "%s"' % poll_id))

When you are using management commands and wish to provide console output, you should write to self.stdout and self.stderr, instead of printing to stdout and stderr directly. By using these proxies, it becomes much easier to test your custom command. Note also that you don’t need to end messages with a newline character, it will be added automatically, unless you specify the ending parameter:

self.stdout.write("Unterminated line", ending = '')

If, for some reason, your custom management command needs to use a fixed locale, you should manually activate and deactivate it in your handle() method using the functions provided by the I18N support code:

from django.core.management.base
import BaseCommand, CommandError
from django.utils
import translation

class Command(BaseCommand):
   ...

   def handle(self, * args, ** options):

   # Activate a fixed locale, e.g.Russian
translation.activate('ru')

# Or you can activate the LANGUAGE_CODE # chosen in the settings:
   from django.conf
import settings
translation.activate(settings.LANGUAGE_CODE)

# Your command logic here
   ...

   translation.deactivate()

An instance attribute that helps create colored output when writing to stdout or stderr. For example:

self.stdout.write(self.style.SUCCESS('...'))

When you are using management commands and wish to provide console output, you should write to self.stdout and self.stderr, instead of printing to stdout and stderr directly. By using these proxies, it becomes much easier to test your custom command. Note also that you don’t need to end messages with a newline character, it will be added automatically, unless you specify the ending parameter:

self.stdout.write("Unterminated line", ending = '')

An instance attribute that helps create colored output when writing to stdout or stderr. For example:

self.stdout.write(self.style.SUCCESS('...'))

If you implement __init__ in your subclass of BaseCommand, you must call BaseCommand’s __init__:

class Command(BaseCommand):
   def __init__(self, * args, ** kwargs):
   super(Command, self).__init__( * args, ** kwargs)
#...