0

My django project is called mybooks, and the app is listings. I am writing a python script which is named searchBooks.py which needs some of the models in the listings app. The searchBooks.py script is in the listings folder (same as the models.py) However, I cannot access the models.

I did what some other users suggest here, including

import os os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mybooks.settings") from listings.models import books

However, I get ModuleNotFoundError: No module named 'listings'

Should I be changing anything in the settings.py? Or maybe the directory of the searchBooks.py?

Ibrahim Fakih
  • 61
  • 1
  • 8

1 Answers1

1

You need to write a script that runs in Django context, invoked through manage.py. It's quite easy.

In your app, first create app/management/commands/__init__.py (empty file, you may need to make folders). Then, start by copying this template to app/management/commands/noop.py:

# invoke with ./manage.py noop [--total] 1 2 3 ...
# script in  app/management/noop.py with __init__.py

from django.core.management.base import BaseCommand

class Command( BaseCommand):

    def add_arguments( self, parser):    # parser is Python argparse parser

        parser.add_argument( 'number_list', nargs='+', type=int,
            help='any number of integers to add up',
        )

        parser.add_argument( '--total', action='store_true', default=False,
            help='Print the total as well as the args'
        )

        parser.add_argument( '--file', type=self.infile)

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

        # print( f'Args: {args}' )    # what are args?

        if options['verbosity'] >= 2:  # inherit default options, including verbosity and help.
                                       # use --help to explore the others
            print( f'Options: {options}' )

        if options['total']:
            total = sum( options['number_list'])
            print( f'Total: {total}' )

        if options['file']:
            print('First line is:')
            print( options['file'].readline() )


    def infile( self, arg):
        return open( arg, 'r')

If you are not familiar with argparse, consult its documntation (it's standard Python, not Django): https://docs.python.org/3/library/argparse.html

Once you have established that it works and you can get six with

./manage.py noop --total 1 2 3

copy it as a starting point to some other name in the same folder, and modify it to perform whatever operations you wish to perform from the command line. You'll start by adding

from listings.models import Whatever, ...

and then modify the handle method to do whatever you want with them, as instructed by whatever options you define.

Django doc: https://docs.djangoproject.com/en/2.1/howto/custom-management-commands/

nigel222
  • 7,582
  • 1
  • 14
  • 22
  • I created the two files, __init__.py and noop.py. However, i am never use the command line for any of my scripts. What do I add to my searchBooks.py (the script that is trying to access the models.py? – Ibrahim Fakih Mar 21 '19 at 18:51
  • Import it and call it, or cut the code out and drop it into your admin command (within handle, or as a new method that you invoke from handle). – nigel222 Mar 21 '19 at 18:55
  • I think we might be interpreting "script" differently. I thought you meant *shell* script, i.e. invoke a custom Django operation from the command line or in a cron job, etc. – nigel222 Mar 21 '19 at 18:57
  • Sorry about that, I am learning all of this on my own, and probably using the wrong terminology. Anyways, I when I mean script, I mean the file. I tried running the file searchBooks.py (which trys to import the models file). But still getting the sample problem. How do I incorporate the noop.py file into it? Just by importing noop? – Ibrahim Fakih Mar 21 '19 at 19:13
  • Django puts it together. When you do `./manage.py foo`, django looks for a `foo.py` that defines a `BaseCommand` subclass in the subfolder of `management/commands` of any installed app after initializing all Django context. So just take the useful code you have in `searchbooks.py` and paste it into the `handle` method of `listings/management/commands/searchbooks.py`. (except your imports which go at the top). Then invoke the management command from the command line via `./manage.py searchbooks arguments ...` – nigel222 Mar 21 '19 at 19:25
  • Try something easy first. Modify my noop.py so it fetches and prints some object(s) whose ids get passed as number_list in `noop.py`. You'll just need to import MyModel and replace that sum with a loop `for id in options['number_list']` doing `MyModel.objects.get(id=id)` and print. – nigel222 Mar 21 '19 at 19:35