Execute Django shell command as cron - python

I'm try to Execute Django shell command as cron,
I have some queries and objects tasks to search and read and write using the models and queries of my django app.
How can I execute this 1 or 2 times a day?
For example, how can I run these queries periodically:
from django.contrib.auth.models import User
from perfil.models import *
for user in usuarios:
profiles = Perfil.objects.filter(user=user)
create_task = Task.objects.create(user=user)

Take a look at Custom management commands for django.
As a basic example:
from django.core.management.base import BaseCommand, CommandError
from django.contrib.auth.models import User
from perfil.models import *
class Command(BaseCommand):
help = 'What does this do? '
def handle(self, *args, **options):
for user in usuarios:
profiles = Perfil.objects.filter(user=user)
create_task = Task.objects.create(user=user)
On a side note, you should be more explicit about your import and not use from perfil.models import *.
From that, you can execute the command based on the file you saved it in. If you saved the file in yourapp/management/commands/dofunstuff.py than you could execute it via python manage.py dofunstuff.

Related

Python: Calculate time between current time and last login. (Automated Communication)

I'm trying to make a celery task that would send a basic reminder to our users. So in our automated communication project, we have these tasks:
As you can see there are few actions that are different. So for now I have created a logic that fetches all the users from the DB and then continues by checking the time difference. But for now, I only have set-up for 2 hours or more. How should I use it correctly? I do not want to re-write each if statement because it's bad practice. How should I make it clear and reduce the system load?
#app.task
def check_registered_users():
from apps.users.models import User
from apps.notifications.models import AutomatedCommunicationNotifications
day_start = datetime.utcnow().date()
day_end = day_start + timedelta(days=1)
users = User.objects.filter(is_active=True, date_joined__range=(day_start, day_end))
users_that_received_notification = AutomatedCommunicationNotifications.objects.all().values('user__id')
excluded_users = users.exclude(id__in=users_that_received_notification)
for user in excluded_users:
if user.last_login < user.last_login + timedelta(hours=2):
# Sign-up uncompleted Push notification 2 hours after last login
template = SiteConfiguration.get_solo().automated_comms_signup_uncompleted
send_plain_email_task(
email=user.email,
subject=template.subject,
html_message=template.content,
from_email=f'{settings.EMAIL_FROM_PREFIX} <{settings.DEFAULT_FROM_EMAIL}>',
)
P.S AutomatedCommunicationNotifications table is for us to track which user has already received a notification.
class AutomatedCommunicationNotifications(BaseModel):
""" Model for automated comms notifications """
user = models.ForeignKey(User, on_delete=models.CASCADE)
type = models.CharField(
max_length=255,
choices=NotificationTypes.get_choices(),
default=NotificationTypes.EMAIL_NOTIFICATION
)
def __str__(self):
return str(self.user.phone)
You'll have to iterate over your queried users at least once but here are tips that may help:
models.py
class User(...):
# add a field to determine if the user has registered or not
# set this to `True` when a User successfully registers:
is_registered = models.BooleanField(default=False)
class AutomatedCommunicationNotifications(BaseModel):
# add a related name field for easier coding:
user = models.ForeignKey(..., related_name = 'notifications')
tasks.py
# load packages outside of your function so this only runs once on startup:
from django.models import F
from apps.users.models import User
from apps.notifications.models import AutomatedCommunicationNotifications
#app.task
def check_registered_users():
# timestamps:
two_hours_ago = datetime.now() - timedelta(hours=2)
# query for unregistered users who have not received a notification:
users = User.objects.filter(
is_registered = False,
last_login__lt = two_hours_ago # last logged in 2 or more hours ago
).exclude(
notifications__type = "the type"
).prefetch_related(
'notifications' # prejoins tables to improve performance
)
for user in users:
# send email
...
I would do this with a cron job. You can let it run whenever you want, depends on how fast after your give time frame you want to sent this.
You start with making a folder in your app:
/django/yourapp/management/commands
There you make a python file which contains your logic. Make sure to import the right modules from your views.
from django.core.management.base import BaseCommand, CommandError
from yourapp.models import every, module, you, need
from django.utils import timezone
from datetime import datetime, date, timedelta
from django.core.mail import send_mail, EmailMessage
class Command(BaseCommand):
help = 'YOUR HELP TEXT FOR INTERNAL USE'
def handle(self, *args, **options):
# Your logic
I added the crontab to the www-data users crontab like this:
# m h dom mon dow command
45 3 * * * /websites/vaccinatieplanner/venv/bin/python /websites/vaccinatieplanner/manage.py reminder
You can use that crontab file to tweak your optimal time between checks. If you remove the 3 and replace it by a * then you will have it check every 45 mins.

I want to send terminal print data to database

I'm new to Django, I have created a selenium project in which It automates mobile recharge. After completion of "recharge successful" I need it to send a successful receipt into my database. I used print(order_id.text) to get receipt in my terminal. now I don't know how to send that receipt to my database.
Probably the easiest way to implement this is with a custom management command [Django-doc]. In your amazon app, yoou can define a management command:
amazon/
management/
commands/
amazonpay.py
# …
In that amazonpay.py file, you then implement the custom management command:
# amazon/management/commands.amazonpay.py
from django.core.management.base import BaseCommand
from amazon.models import Amazon
class Command(BaseCommand):
help = 'Some description...'
def handle(self, *args, **options):
# … run selenium …
Amazon.objects.create(
o=ord_id
)
You can then run this command with:
python3 manage.py amazonpay
In fact runserver, makemigrations, etc. are all defined as management commands as well.

Django: How to switch relations between two objects

I am having issues updating a website I run. Essentially, the users on the website cannot be used anymore, so people have to create new accounts. However, users have ManyToMany relations with other tables in the database, and I want to be able to move the relations from the old users to the new ones.
Is there any good way to do this in Django or directly in the database? I am using PostgreSQL.
Django has a management command framework for this.
https://docs.djangoproject.com/en/3.1/howto/custom-management-commands/
This should live in PROJECT/APPNAME/management/commands/
from django.core.management import BaseCommand
from django.contrib.auth import get_user_model
User = get_user_model()
#The class must be named Command, and subclass BaseCommand
class Command(BaseCommand):
# Show this when the user types help
help = "fix users relations"
# A command must define handle()
def handle(self, *args, **options):
self.stdout.write("fixing users begin")
for user in User.objects.all():
...user fix code...
self.stdout.write("fix users complete")

Cronjob to periodically refresh cache for django view

I've had some trouble trying to reset my cache every hour for a particular django view.
Right now, I am using the cache_page decorator to cache my view using Memcached. But the cache expires after a while and the request is uncached from some users.
#cache_page(3600)
def my_view(request):
...
How do I write my own django manage.py command to refresh my cache for this view every hour from cron?
In other words, what do I put in my refresh_cache.py file mentioned in the answer here:
Django caching - can it be done pre-emptively?
Thanks!
In your app, you can create a folder called management which contains another folder commands and an empty __init__.py file. Inside commands you create another __init__.py and a file where you write your custom command. Let's called it refresh.py:
# refresh.py
from django.core.management.base import BaseCommand, CommandError
from main.models import * # You may want to import your models in order to use
# them in your cron job.
class Command(BaseCommand):
help = 'Posts popular threads'
def handle(self, *args, **options):
# Code to refresh cache
Now you can add this file to your cron jobs. You can take a look at this tutorial but basically you use crontab -e to edit your cron jobs and crontab -l to see which cron jobs are running.
You can find all of this and more in the Django documentation.
I want to expand on Roberts answer to fill out the # Code to refresh cache
Timezome+location make caches much hard to work with, in my case I just disabled them, also I am not sure about using the test methods in the application code, but it seems to work nicely.
from django.core.management.base import BaseCommand, CommandError
from django.test.client import RequestFactory
from django.conf import settings
from ladder.models import Season
from ladder.views import season as season_view
class Command(BaseCommand):
help = 'Refreshes cached pages'
def handle(self, *args, **options):
"""
Script that calls all season pages to refresh the cache on them if it has expired.
Any time/date settings create postfixes on the caching key, for now the solution is to disable them.
"""
if settings.USE_I18N:
raise CommandError('USE_I18N in settings must be disabled.')
if settings.USE_L10N:
raise CommandError('USE_L10N in settings must be disabled.')
if settings.USE_TZ:
raise CommandError('USE_TZ in settings must be disabled.')
self.factory = RequestFactory()
seasons = Season.objects.all()
for season in seasons:
path = '/' + season.end_date.year.__str__() + '/round/' + season.season_round.__str__() + '/'
# use the request factory to generate the correct url for the cache hash
request = self.factory.get(path)
season_view(request, season.end_date.year, season.season_round)
self.stdout.write('Successfully refreshed: %s' % path)

Python Django sqlite connection

I would like to create a simple dynamic Sudoku game. Idea is to create new "puzzle" every hour then put it to database and let users solve it. Each solve attempt is compared with database for verification. For that purpose I would like to create python script that generates puzzle and puts it to the database. My database set in models looks like this:
from django.db import models
class user(models.Model):
name = models.CharField(max_length=30)
password = models.CharField(max_length=30)
time_registered=models.DateTimeField()
time_uploaded=models.DateTimeField()
points=models.IntegerField()
saved_sudoku=models.CommaSeparatedIntegerField(max_length=81)
solved=models.BooleanField()
def __str__(self):
return self.name
class server_sudoku(models.Model):
time_uploaded=models.DateTimeField()
generated_sudoku=models.CommaSeparatedIntegerField(max_length=81)
Now, when I use :
name1=request.POST["name"]
pass1=request.POST["password"]
newuser=user(name=name1,password=pass1,time_registered=datetime.datetime.now(),time_uploaded=datetime.datetime.now(),points=0,saved_sudoku="",solved=False)
newuser.save()
in views.py it creates new user. So to verify my idea I created application "generate_sudoku.py". To test its connection to database I just try to add user. Code looks as follows:
#!/usr/bin/env python
from db_interface.models import user
import random
import datetime
newuser=user(name="name", password="pass", time_registered=datetime.datetime.now() ,time_uploaded=datetime.datetime.now(), points=0, saved_sudoku="", solved=False)
newuser.save()
This simple app gives me this error:
raise ImportError("Settings cannot be imported, because environment variable %s is undefined." % ENVIRONMENT_VARIABLE)
ImportError: Settings cannot be imported, because environment variable DJANGO_SETTINGS_MODULE is undefined.
Hope I made it clear, I would like to run this application by windows scheduler so that it is automatically run every hour...
Use a custom manage.py command.
First link on google : http://eliasbland.wordpress.com/2010/01/25/importerror-settings-cannot-be-imported-because-environment-variable-django_settings_module-is-undefined/ ;)
This works for me (in a lambda script, not _ _init _ _.py file) :
import os
os.environ['DJANGO_SETTINGS_MODULE'] = 'settings'
from django.contrib.auth.models import User #import django stuff after
print User.objects.all()

Categories