unbit / uwsgi

uWSGI application server container
http://projects.unbit.it/uwsgi
Other
3.46k stars 691 forks source link

how to transfer object to spool? #743

Closed xurwxj closed 10 years ago

xurwxj commented 10 years ago

when uwsgi spooler work with django, how to transfer model instance, request, etc. to spooler? also how to get context work in spooler?

uwsgi spooler only support str param now.

unbit commented 10 years ago

You can serialize (pickle and friends), but i strongly suggest you to not do it. Work by references, passing the id/pk of the objects to the spooler and similar. You have to consider it as an external system

xurwxj commented 10 years ago

It's quite painful, we do pass the pk or string value. But unable to find the template to render with: [code] import sys, os try: import uwsgi sys.path.insert(0, uwsgi.opt['chdir']) os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'test.settings') except: pass from django.conf import settings

when with render_tostring, i got: django.template.base.TemplateDoesNotExist: workflow/msg/material

but the template actually exist.

when run without spool, it all ok.

unbit commented 10 years ago

You have to treat the spooler as an external script. Based on the version of Django you need to initialize it. Your approach works (iirc) only for 1.6, 1.7 requires calling django.setup(), older django requires calling setup_environ()

xurwxj commented 10 years ago

i'm use django 1.7, i tried your method with calling django.setup(), but still get following error:

when with render_to_string, i got: File "./shining3d/libs/workflow/heper.py", line 169, in send_wfmsg ... django.template.base.TemplateDoesNotExist: workflow/msg/material

@spool def flow_init(arguments):

from django.utils.six.moves import cPickle as pickle

# flow_obj = pickle.loads(arguments['args'])
import django
django.setup()
flow_obj = get_instance_class_id(arguments['flow_obj_class'], arguments['flow_obj_id'])
if flow_obj:
    flow_obj.init_flow()

def send_wf_msg(recipients, receiptsummary, msg_type, wf_log=None, wf_node=None, way_list=['mail', 'sms', 'rtx']): import django django.setup() wf_type = receiptsummary.wf_type templates = [ 'workflow/msg/%(wftype)s%(msgtype)s%(msg_part)s.txt', 'workflow/msg/%(msgtype)s%(msg_part)s.txt', 'workflow/msg/%(msg_part)s.html', ] templ_name_dict = {'wf_type': wf_type, 'msg_type': msg_type, 'msg_part': 'subject'} subject_templates = [e % templ_name_dict for e in templates] ctx = {'obj': receiptsummary, 'log': wf_log, 'node': wf_node, 'sys_base_url': settings.SYS_BASE_URL} subject = render_to_string(subject_templates, ctx) templ_name_dict['msg_part'] = 'body' body_templates = [e % templ_name_dict for e in templates] msg_body = render_to_string(body_templates, ctx) send_sys_msg(msg_body, recipients=recipients, subject=subject, way_list=way_list)

all got success without render tempate.

i consider maybe something wrong with loading django template in uwsgi spool.

unbit commented 10 years ago

Honestly it is too django-related, and i fear i am not able to help you, you should search the way to correctly access templates from external scripts. I leave the ticket open, so if someone already faced the issue can help you

xurwxj commented 10 years ago

thank you, i'll go with your advice and feed back when got solved.

xurwxj commented 10 years ago

through django management command or python exec file calling in spool is the perfect way for now, can resolve template render and url parse problem, but need transaction roll back control for big thing.

hope uwsgi can load full django env with spool in future.

unbit commented 10 years ago

Sorry, but why you think it is something uWSGI has to manage ? this is at the python level, you can rebuild the same environment like the django command suite does. My previous answer was a simply "i do not know how to do it" (as i never needed to deal with django templates from async jobs) :)

xurwxj commented 10 years ago

uwsgi load django configure environment, but lost something like template and url related. these all works with django management command or python exec file. for same load method:

sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(os.path.realpath(os.path.dirname(inspect.stack()[0][1]))))))
    os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'project.settings')
    import django
    django.setup()
    from django.shortcuts import render_to_response
    from django.core.urlresolvers import reverse

render_to_response template in uwsgi spool must with template_dir specifacted when works in other environment. and reverse not work in uwsgi spool.

the difference i think is in environment after loaded django configure.

bwesen commented 5 years ago

In case someone else comes here (like me), yes, I get the same problem (now with Django 2.2). Even after calling django.setup(), templates are not found but everything else works (I realize this has nothing to do with uwsgi but it must be a pretty common use-case though, spooling email sending and stuff that needs templates).

Edit: I located the problem, the issue is that DjangoTemplates does not find its application dirs (where the templates are located) automagically as it normally does if its config option APP_DIRS is True, if setup stand-alone in the spooler process. So it will look like templates stop working when you try to use them in the spooler. The workaround is to explicitly list the absolute path of the template dirs you need, in the DIRS option (like below) in settings.py:

TEMPLATES = [ { 'BACKEND': 'django.template.backends.django.DjangoTemplates', 'DIRS': [ '/mysite/myapp/templates' ], # req. for uWSGI spooler invocation 'APP_DIRS': True, .... }]

NotANormalNerd commented 3 years ago

Hello fellow developers,

If you are here, you seem to be in confusion and distress. The correct solution for the problem above and others (not having a correctly setup django environment in your uwsgi spooler) is twofold:

  1. set --spooler-chdir to your Django Applications root directory.
  2. do a import django; django.setup(set_prefix=False) in your tasks.py

This way, the spooler (which should be seen as a completely different python process) will change into the correct location and sets up the Django environment correctly.

Hope this helps someone! Best regards, Dennis