Cronjobs are not not created using django-crontab - cron

I want to create cronjobs dynamically, not by manually writing them in the CRONJOBS variable in the config.settings.py module source code
Here is my code:
from django.conf import settings
from sender.auxfunc.create_cronjob import func
class MailingCreateView(CreateView):
model = ConfigMailing
user = self.request.user
fields = '__all__'
template_name = 'sender/profile.html'
success_url = reverse_lazy('sender:profile')
def form_valid(self, form):
self.object = form.save()
create_cronjob = func.format(user, mailing)
#block of code that creates a cronjob function in the client's individual folder.
#This block works correctly
target_dir = f'sender/crons/{user}/{self.object.pk}'
with open(f'{target_dir}/cron.py', 'w', encoding='utf-8') as f:
f.write(f'{create_cronjob}')
cronjob = (self.object.cron_period, self.object.cron_path)
settings.CRONJOBS.append(cronjob)
os.system('python3 manage.py crontab add')
os.system('python3 manage.py crontab show >> show_crons_log.txt')
print(settings.CRONJOBS) #cronjobs are added to the variable and displayed correctly
return super().form_valid(form)
When creating multiple instances of the Mailing class in succession, the print(settings.CRONJOBS) command prints all created cronjobs.
However, running the python3 manage.py crontab show command shows that the cronjobs do not exist.
The django-crontab documentation is very sparse, but I conclude that the program creates registers crontab only from the source code of the variable CRONJOBS from module config.settings.py which is empty
Is it possible to somehow correct the situation? Thanks for any answer.
The only solution I see is to rewrite the CRONJOBS variable with loops and regular expressions. But this is insecure and will kill performance and has no prospects for scaling the project

Related

Get data from process

Suppose I have a python script program.py
that looks as follows:
# program.py
import random
class Program
def __init__(self):
self.data = []
def run():
while True:
self.data.append(random.random()]
if __name__ == "__main__":
program = Program()
program.run()
Now suppose that I have another script script.py that calls program.py as a separate process.
# script.py
import subprocess
import time
process = subprocess.Popen(["py", "program.py"])
while True:
data = get_program_data(process)# how?
time.sleep(10)
The purpose of script.py is to illustrate the fact that I don't have access to the class Program. In my case this is due to the fact that I will be triggering program.py from a .NET application. I thought I'll try to understand how to deal with this problem from a python script first then apply it to the .NET application. So here is my question (keep in mind that I can alter the code in program.py and script.py, but script.py can not access program.py):
How should I go about accessing self.data from the process? I have been searching all over and I'm not quite sure in what direction I should be going. In my case, I will need to trigger difference commands for different ind of data generated in Program, i.e. get_program_data1(), get_program_data2(),....
The way I have been "solving" this issue is to have a file controller.json that script.py modifies and program.py reads and acts accordingly. I does not feel quite right doing and so I want your opinion about this. Remember that ultimately, script.py is a .NET application. Thanks

How to write batch of data to Django's sqlite db from a custom written file?

For a pet project I am working on I need to import list of people to sqlite db. I have 'Staff' model, as well as a users.csv file with list of users. Here is how I am doing it:
import csv
from staff.models import Staff
with open('users.csv') as csv_file:
csv_reader = csv.DictReader(csv_file, delimiter=',')
line_count = 0
for row in csv_reader:
firstname = row['firstname']
lastname = row['lastname']
email = row['email']
staff = Staff(firstname=firstname, lastname=lastname, email=email)
staff.save()
csv_file.close()
However, I am getting below error message:
raise ImproperlyConfigured(
django.core.exceptions.ImproperlyConfigured: Requested setting INSTALLED_APPS, but settings are not configured. You must either define the environment variable DJANGO_SETTINGS_MODULE or call settings.configure() before accessing settings.
Is what I am doing correct? If yes what I am missing here?
Django needs some environment variables when it is being bootstrapped to run. DJANGO_SETTINGS_MODULE is one of these, which is then used to configure Django from the settings. Typically many developers don't even notice because if you stay in Django-land it isn't a big deal. Take a look at manage.py and you'll notice it sets it in that file.
The simplest thing is to stay in django-land and run your script in its framework. I recommend creating a management command. Perhaps a more proper way is to create a data migration and put the data in a storage place like S3 if this is something many many people need to do for local databases... but it seems like a management command is the way to go for you. Another option (and the simplest if this is really just a one-time thing) is to just run this from the django shell. I'll put that at the bottom.
It's very simple and you can drop in your code almost as you have it. Here are the docs :) https://docs.djangoproject.com/en/3.2/howto/custom-management-commands/
For you it might look something like this:
/app/management/commands/load_people.py <-- the file name here is what manage.py will use to run the command later.
from django.core.management.base import BaseCommand, CommandError
import csv
from staff.models import Staff
class Command(BaseCommand):
help = 'load people from csv'
def handle(self, *args, **options):
with open('users.csv') as csv_file:
csv_reader = csv.DictReader(csv_file, delimiter=',')
line_count = 0
for row in csv_reader:
firstname = row['firstname']
lastname = row['lastname']
email = row['email']
staff = Staff(firstname=firstname, lastname=lastname, email=email)
staff.save()
# csv_file.close() # you don't need this since you used `with`
which you would call like this:
python manage.py load_people
Finally, the simplest solution is to just run the code in the Django shell.
python manage.py shell
will open up an interactive shell with everything loaded properly. You can execute your code there and it should work.

Automate python argparse script with pre-generated inputs

I have a program which takes folder paths and other inputs through the command line with argparse. I want this script to run automatically on a server, but I also want to keep its argparse functionality in case I want to run the script manually. Is there a way to have the script use pre-generated inputs from a file but also retain its flag based input system with argparse? Here is my current implementation:
parser = argparse.ArgumentParser(description='runs batch workflow on root directory')
parser.add_argument("--root", type=str, default='./', help="the path to the root directory
to process")
parser.add_argument("--data", type=str, default='MS', help="The type of data to calculate ")
args = parser.parse_args()
root_dir = args.root
option = args.data
I'm pretty new to this stuff, and reading the argparse documentation and This stack overflow question is not really what I want, if possible I would like to keep the root and data flags, and not just replace them with an input file or stdin.
If using argparse, the default keyword argument is a good, standard way to approach the problem; embed the default behavior of the program in the script source, not an external configuration file. However, if you have multiple configuration files that you want to deploy differently, the approach you mentioned (pre-generated from an input) is desirable.
argparse to dictionary
The argparse namespace can be converted to a dictionary. This is convenient as we can make a function that accepts a dictionary, or keyword arguments, and have it process the program with a convenient function signature. Also, file parsers can just as easily load dictionaries and interact with the same function. The python json module is used as an example. Of course, others can be used.
Example Python
def main(arg1=None, arg2=None, arg3=None):
print(f"{arg1}, {arg2}, {arg3}")
if __name__ == "__main__":
import sys
import json
import argparse
# script called with nothing -- load default
if len(sys.argv) == 1:
with open("default.json", "r") as dfp:
conf = json.load(dfp)
main(**conf)
else: # parse arguments
parser = argparse.ArgumentParser()
parser.add_argument('-a1', dest='arg1', metavar='arg1', type=str)
parser.add_argument('-a2', dest='arg2', metavar='arg2', type=str)
parser.add_argument('-a3', dest='arg3', metavar='arg3', type=str)
args = parser.parse_args()
conf = vars(args)
main(**conf)
default.json
{
"arg1" : "str1",
"arg2" : "str2",
"arg3" : "str3"
}
Using Fire
The python Fire module can be used more conveniently as well. It has multiple modes that the file can be interacted with minimal effort. The github repo is available here.

Start a different script as thread knowing script's name

I have 2 different python scripts, the first called main.py and the second called running.py
the main.py script is the following:
#setting things up and stuff
while True:
#stuff
Here running.py should be started
#stuff
while running.py contains the following
#various imports
while True:
#stuff
My question is, how can i run running.py from main.py as a new thread knowing only the name of the running script?
I looked a bit into it and, since i need to communicate and share data between main.py and running.py, I don't think creating a subprocess is the best course of action but I haven't found a way to run a whole script in a thread only knowing the script's name.
For various (stupid) company reasons I can't change the content of running.py and i can't import it into main.py so creating a threading class inside it is not a possibility but i have free rein on main.py
Is what i'm trying to do even possible?

Can't get my Application running after adding a tkinter interface

Both my application's "motor" in Python 3.7.0 and my tkinter interface work without a hitch by themselves. The problem starts when I put the two together.
The following is a very simplified version of the beginning of my application, but it illustrates the basic problem:
from tkinter import *
request={} # this get more than just one piece of info.
def init():
global request
request['dir'] = text1.get()
# The real interface has:
# 2 Entry Widgets: file extention and keyword.
# 2 Buttons: Select Directory and Organize Files.
# this here is minimal interface
w = Tk()
text1 = StringVar()
Label(text=' Folder ').grid(row=0,column=0)
Entry(textvariable = text1).grid(row=0,column=1) # gets the input
Button(text='Organize', command=init).grid(row=4,column=0)
w.mainloop()
# End of interface.
# ---------- Script starts here ----------------
# here I import several built-in and several personal modules like phps and helpers
# this modules have a whole bunch of functions.
# ----------- VARIABLE ASSIGNMENT ------------- ##
# Here is where I need the interface and the script to connect.
# Path to the directory that will be looped through
BaseDir=request[0]+'/*'
extRequired=request[1] # txt or docs, etc.
# a part of the basename e.g. my new filename keyword = "my new"
Keyword=request[2]
# more vars ....
## ----------- SEARCH DIRECTORY ------------- ##
files=glob.glob(BaseDir)
for file in files:
# EXTRACT file INFO
info=phps.pathinfo(file) # phps is a module I made.
# EXCLUDE Directories
if not os.path.isdir(file):
# SERACH for the Keyword
Keyword_Exist = info['basename'].find(Keyword)
# IS the KEYWORD in the String?
if Keyword_Exist > -1 and info["ext"]==extRequired:
RawfName = info["filename"][3:]
## USE RawfName in the WRITE CONTENT TO FILE Section.
## ----------- GET FILE ------------- ##
lines=open(file).readlines()
# etc ....
If you run the snippet, type a directory's name in the input box, and click on the button, nothing seems to happen, but it does. If you
close the interface, you'll see the user input needed to run the for loop appear on Python's shell, but the loop didn't run.
Any ideas on how I can get this two separate scripts working together?
I basically want to keep the interface open, run the application which starts by looping through files according to the user's input, have it do what it needs to, and then prestent a report to the user on a new window. The user can close this pop-up, and may do another operation without having to restart the application.
Thanks in advance.
I had to reread your question and your comments but I think I understand now what you are trying to do.
If you want to have a pop-up then Toplevel() is what you need. It will open a new window over the main window.
Here we can apply the for loop to add labels to the top level window.
You can do whatever you want here but as long as you do not close the mainloop() then you can have as many pop-ups as you need using Toplevel() without losing any data in the dict.
Let me know if the below helps or if it is something else you actual are trying to do:
from tkinter import *
w = Tk()
request={}
def init():
top = Toplevel(w)
request['dir'] = text1.get()
for key, value in request.items():
Label(top, text=value).pack()
text1 = StringVar()
Label(text=' Folder ').grid(row=0,column=0)
Entry(textvariable = text1).grid(row=0,column=1)
Button(text='Organize', command=init).grid(row=4,column=0)
w.mainloop()

Resources