I love how django server auto-reloads itself on code change, so that no restarting the server is required.
We currently use django custom management commands that may take a very long time to complete.
Is there any way we can use the
auto-reloading feature of the django
server for our management command?
For example, if the change of the underlying django codebase is detected, the command reloads itself and resumes execution of the very long (stateless) loop.
Whatever your management command is doing, abstract that to a single function and call that function using django.utils.autoreload.main
from django.utils import autoreload
def do_something(*args, **kwargs):
# management command logic
class Command(BaseCommand):
def handle(self, *args, **options):
self.stdout('This command auto reloads. No need to restart...')
autoreload.main(do_something, args=None, kwargs=None)
For django 2.2 or above use
autoreload.run_with_reloader(do_something, args=None, kwargs=None)
Checkout the way runserver (specifically the run method) does it with the django.utils.autoreload module. You'll want to copy this pattern with your custom command.
Related
I’m trying to start python-telegram-bot in a web application with the django framework. To do this, I follow any example from the Telegram library and end up calling the method application.run_polling(). I know it’s not the best option because this blocks my web server, and I want to replace it with a better one, but I can’t find it.
According to official documentation, there is a tip that indicates the following:
When combining python-telegram-bot with other asyncio based frameworks, using this method is likely not the best choice, as it blocks the event loop until it receives a stop signal as described above. Instead, you can manually call the methods listed below to start and shut down the application and the updater. Keeping the event loop running and listening for a stop signal is then up to you.
And then I find the following section:
See also
initialize(), start(), stop(), shutdown() telegram.ext.Updater.start_polling(), telegram.ext.Updater.stop(), run_webhook()
I’ve tried to understand the methods in the list, but I can’t figure out how to run python-telegram-bot in the background and not affect my main server.
Are there any links or documents that expand the information or detail the steps to follow in these cases?
Thank you in advance
EDIT: Telegram I run it from an app configured in django as follows:
import asyncio
from django.apps import AppConfig
from telegram import Update
from telegram.ext import ContextTypes, Application, CommandHandler
from TaixTracking.configApp import ConfigApp
async def help_command(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
await update.message.reply_text("Help!")
async def start_telegram():
application = Application.builder().token(ConfigApp().get_value('telegram', 'token', '')).build()
application.add_handler(CommandHandler("help", help_command))
await application.initialize()
await application.start()
await application.updater.start_polling()
print('Telegram load')
class CommunicationConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'communication'
def ready(self):
if not ConfigApp().is_telegram_launch():
ConfigApp().set_telegram_launch(True)
asyncio.run(start_telegram())
Consider the following manage.py command:
class Command(BaseCommand):
def handle(self, *args, **options):
raise Exception('Test exception')
Is there a way to make django log that exception to a specific file automatically without wrapping handle() function in a big try-catch or without hacking the manage.py itself, which basically mean I do the logging myself.
I mean something like configuring admin mail handler for views, but log to file instead of an email and management command instead of a view. Then raise exceptions from any place inside a management command and be sure they will be logged.
I have gone through this post, but it didn't contain any relevant answer.
I am using Django 1.11 , and my views.py is modular (not class based).
I want to test views modules (functions) in the shell, in django's python shell.
>>> python manage.py shell
By directly importing views like:
>>> from my_app import views
It works, but this doesn't seem to be preferred way to me.
Is there any preferred way or shall I import views from django in shell or copy the function directly ? What is the best practice for this?
So your going to be much better off just writing Django tests for your views instead of trying to run them from the shell since it will be the same code, but you will be able to easily run the test multiple times.
So to create a test for a single view you would create a tests.py in your django app and write test for the view using django's test client. This test client is a dummy web browser that can be used to make http requests. A simple tests.py would look like this:
from django.tests import TestCase, Client
class MyViewsTestCase(TestCase):
def setUp(self):
self.client = Client() #This sets up the test client
def test_my_view(self):
# A simple test that the view returns a 200 status code
# In reality your test needs to check more than this depending on what your view is doing
response = self.client.get('the/view/url')
self.assertEqual(response.status_code, 200)
you would then run this with the commands python manage.py test or django-admin test from your terminal
Again you could do this from the shell, but it's going to be better in the long run to use the test framework
Django has some good docs on writing and running tests here: https://docs.djangoproject.com/en/2.0/topics/testing/overview/
and info on the test client along with some other testing tools here: https://docs.djangoproject.com/en/2.0/topics/testing/tools/
My old worker installed Pinax through PIP and it's installed in site-packages. All the apps lives there. Our own apps are within our Django project structure.
I want to modify Pinax's account app, by switching the create_user's is_active flag to False. Currently, the app makes it True. I also want to add additional functionality to create_user or whatever function I want to do.
from pinax.account import forms
class MyCustomizeForm(forms.SignupForm):
def create_user(....):
super(....)
// additional...
Maybe this?
But doesn't that require me to do at least two commit transactions talking to DB?
Is that preferable? Also, does doing this require me to change anything else in my Django project (how users signup, what views it uses... what forms it uses)?
Currently, I've an app living in my Django project supposes to deal with the extension / customization of account app. I can't commit site-packages to VCS.... I mean.. I am not supposed to make any changes there.
Thanks.
Pinax account/models.py
class Account(models.Model):
...
def its_own_method(...)
# this is in the same indentation level as class Account
def create_account(sender, instance=None, **kwargs):
if instance is None:
return
account, created = Account.objects.get_or_create(user=instance)
post_save.connect(create_account, sender=User)
You can use the django signals for exactly this situation. Signals are meant for apps that need to be distributed generally and won't always know how they will be integrated into a project.
The signal of interest to you here is the pre_save. You can connect a pre_save to the pinax.account model and be notified when a save is about to happen. This will give you a chance to make changes to that model instance. Signals are synchronous, meaning you are making your change serially, right before the pinax.accounts will finish committing the save
Previously I've been using some older version of django-registration which seems to be deprecated now. Because my server does not allow me to install python plugins I need to use 'registration' as separate django application. Now my question is what do I need to modify in order to get registation running as django-app ? Can I just copy 'registration' to my django project catalog, add it in settings and it should work ? Previously there was no such thing as 'backend' defined, now backend init file with function get_backend, that takes 'path' as argument. I guess this path is sent via url right ?
url(r'^activate/(?P<activation_key>\w+)/$',
activate,
{'backend': 'registration.backends.default.DefaultBackend'},
name='registration_activate'),
Inside this catalog there's also init file with DefaultBackend class, with classes activate and register.
http://paste.pocoo.org/show/225790/
They both use signals. Do I need to bother with those signals in any way ? (I still don't quite get what they're used for).
Last thing. Previously after registration it was redirecting te either given success_url or set template in this way :
return HttpResponseRedirect(success_url or reverse('registration_complete'))
Now code responsible for this looks :
if success_url is None:
to, args, kwargs = backend.post_registration_redirect(request, new_user)
return redirect(to, *args, **kwargs)
else:
return redirect(success_url)
and the post_registration_redirect :
def post_registration_redirect(self, request, user):
"""
Return the name of the URL to redirect to after successful
user registration.
"""
return ('registration_complete', (), {})
So why was this changed in this way if it still simply redirect to 'registration_complete' ? The args and kwargs are empty so why bother ?
The situation is much simpler than you're making it out to be. Django applications (like registration) are just normal Python packages and can be imported as such. What that means is that registration can live anywhere that's in your python path already. Oftentimes the simplest place for that is in your root project directory.
The backend argument there just takes a python import path. The argument was added so that people could extend Django-Registration to use custom backends if they so desire.
If you put the registration directory on your python path the existing string should work just fine.
Quote:
"Because my server does not allow me to install python plugins I need to
use 'registration' as separate django application."
Is this because you don't have root access? Have you tried using virtualenv (Link is to my own blog) to create your own (fully writeable) Python/Django install? Alternatively, creating a writeable directory in a place you do have write access, installing django-registration there and pointing your PYTHON_PATH to that location?
IMO, it seems like you gave up too quickly on the "install django-registration" option and moved to the more complicated "run it on a different server" one.