I want to check if a user has any new messages each time they load the page. Up until now, I have been doing this inside of my views but it's getting fairly hard to maintain since I have a fair number of views now.
I assume this is the kind of thing middleware is good for, a check that will happen every single page load. What I need it to do is so:
Check if the user is logged in
If they are, check if they have any messages
Store the result so I can reference the information in my templates
Has anyone ever had to write any middleware like this? I've never used middleware before so any help would be greatly appreciated.
You could use middleware for this purpose, but perhaps context processors are more inline for what you want to do.
With middleware, you are attaching data to the request object. You could query the database and find a way to jam the messages into the request. But context processors allow you to make available extra entries into the context dictionary for use in your templates.
I think of middleware as providing extra information to your views, while context processors provide extra information to your templates. This is in no way a rule, but in the beginning it can help to think this way (I believe).
def messages_processor(request):
return { 'new_messages': Message.objects.filter(unread=True, user=request.user) }
Include that processor in your settings.py under context processors. Then simply reference new_messages in your templates.
I have written this middleware on my site for rendering messages. It checks a cookie, if it is not present it appends the message to request and saves a cookie, maybe you can do something similar:
class MyMiddleware:
def __init__(self):
#print 'Initialized my Middleware'
pass
def process_request(self, request):
user_id = False
if request.user.is_active:
user_id = str(request.user.id)
self.process_update_messages(request, user_id)
def process_response(self, request, response):
self.process_update_messages_response(request, response)
return response
def process_update_messages(self, request, user_id=False):
update_messages = UpdateMessage.objects.exclude(expired=True)
render_message = False
request.session['update_messages'] = []
for message in update_messages:
if message.expire_time < datetime.datetime.now():
message.expired = True
message.save()
else:
if request.COOKIES.get(message.cookie(), True) == True:
render_message = True
if render_message:
request.session['update_messages'].append({'cookie': message.cookie(), 'cookie_max_age': message.cookie_max_age})
messages.add_message(request, message.level, message)
break
def process_update_messages_response(self, request, response):
try:
update_messages = request.session['update_messages']
except:
update_messages = False
if update_messages:
for message in update_messages:
response.set_cookie(message['cookie'], value=False, max_age=message['cookie_max_age'], expires=None, path='/', domain=None, secure=None)
return response
Related
I am using django restless for an ajax POST request, which took almost 10 to 20 seconds.
Here is my code.
class testEndPoint(Endpoint):
def post(self, request):
testForm = TestEmailForm(request.data)
if testForm.is_valid():
sometable = EmailTable.object.get(**condition)
if sometable.is_email_sent == false:
#Send Email
#Took around 15 seconds
sometable.is_email_sent = true
sometable.save()
else:
result = testForm.errors
return serialize(result)
i am calling it via $.ajax, but the problem is if two request hit this url with milliseconds time difference, both request passed through if sometable.is_email_sent = false: condition.
How can i prevent multiple submission. Right now i have moved sometable.is_email_sent = true;sometable.save(); before email send part, but i need more generic solution as there are dozen more places where this is happening. I am on django 1.5
django restless
You should disable the originating input element before you start your ajax call (that will prevent the majority of these issues).
The remaining problems can be solved by using select_for_update
class testEndPoint(Endpoint):
#transaction.commit_manually
def post(self, request):
testForm = TestEmailForm(request.data)
if testForm.is_valid():
condition['is_email_sent'] = False
try:
rows = EmailTable.objects.select_for_update().filter(**condition)
for row in rows:
row.is_email_sent = True
row.save()
#Send Email
except:
transaction.rollback()
raise
else:
transaction.commit()
else:
result = testForm.errors
return serialize(result)
select_for_update will lock the rows until the end of the transaction (i.e. it needs to be inside a transaction). By adding is_email_sent=False to the condition, we can remove the if. I've moved the changing of is_email_sent above the "Send Email", but it is not strictly necessary -- in any case it will be undone by the transaction rolling back if there is an exception.
I am still learning and none of the other questions answer my question, why do I have to have an HTTP Response?
def view(request):
namesTickers = Company.objects.all().values('name', 'ticker')
names, tickers = [], []
for nameTicker in namesTickers:
names.append(nameTicker['name'])
tickers.append(nameTicker['ticker'])
nameTickerDict = dict(zip(names, tickers))
print nameTickerDict
if 'ticker' in request.POST and request.POST['ticker']:
q = request.POST['ticker']
context = {}
context['companies'] = json.dumps(nameTickerDict)
context['companyInfo'] = Company.objects.filter(ticker__icontains=q)
context['financial'] = Financials.objects.filter(ticker__icontains=q).order_by('-year')
return render( request, "companies/view.html",[context])
Because HTTP is a request/response mechanism. You get a request and you must respond to it. It doesn’t have to be a successful response, though. If you cannot respond meaningfully without a ticker, you may return an error page instead. Or, if you have a form where the user enters a ticker and submits that to your view, then you probably want to return the user back to the same form but with an error message. If that is the case, Django’s forms framework will help you.
In my django piston API, I want to yield/return a http response to the the client before calling another function that will take quite some time. How do I make the yield give a HTTP response containing the desired JSON and not a string relating to the creation of a generator object?
My piston handler method looks like so:
def create(self, request):
data = request.data
*other operations......................*
incident.save()
response = rc.CREATED
response.content = {"id":str(incident.id)}
yield response
manage_incident(incident)
Instead of the response I want, like:
{"id":"13"}
The client gets a string like this:
"<generator object create at 0x102c50050>"
EDIT:
I realise that using yield was the wrong way to go about this, in essence what I am trying to achieve is that the client receives a response right away before the server moves onto the time costly function of manage_incident()
This doesn't have anything to do with generators or yielding, but I've used the following code and decorator to have things run in the background while returning the client an HTTP response immediately.
Usage:
#postpone
def long_process():
do things...
def some_view(request):
long_process()
return HttpResponse(...)
And here's the code to make it work:
import atexit
import Queue
import threading
from django.core.mail import mail_admins
def _worker():
while True:
func, args, kwargs = _queue.get()
try:
func(*args, **kwargs)
except:
import traceback
details = traceback.format_exc()
mail_admins('Background process exception', details)
finally:
_queue.task_done() # so we can join at exit
def postpone(func):
def decorator(*args, **kwargs):
_queue.put((func, args, kwargs))
return decorator
_queue = Queue.Queue()
_thread = threading.Thread(target=_worker)
_thread.daemon = True
_thread.start()
def _cleanup():
_queue.join() # so we don't exit too soon
atexit.register(_cleanup)
Perhaps you could do something like this (be careful though):
import threading
def create(self, request):
data = request.data
# do stuff...
t = threading.Thread(target=manage_incident,
args=(incident,))
t.setDaemon(True)
t.start()
return response
Have anyone tried this? Is it safe? My guess is it's not, mostly because of concurrency issues but also due to the fact that if you get a lot of requests, you might also get a lot of processes (since they might be running for a while), but it might be worth a shot.
Otherwise, you could just add the incident that needs to be managed to your database and handle it later via a cron job or something like that.
I don't think Django is built either for concurrency or very time consuming operations.
Edit
Someone have tried it, seems to work.
Edit 2
These kind of things are often better handled by background jobs. The Django Background Tasks library is nice, but there are others of course.
You've turned your view into a generator thinking that Django will pick up on that fact and handle it appropriately. Well, it won't.
def create(self, request):
return HttpResponse(real_create(request))
EDIT:
Since you seem to be having trouble... visualizing it...
def stuff():
print 1
yield 'foo'
print 2
for i in stuff():
print i
output:
1
foo
2
I have a view like this:
def form1(request):
if request.method == 'POST':
form = SyncJobForm(request.POST)
if form.is_valid():
# do something
in_progress = True
return render_to_response('form1.html', {'in_progress': in_progress})
I would like to know how to set it to refresh the template after is done with the view process. Like rendering the page after its done:
in_progress = True
return render_to_response('form1.html', {'in_progress': in_progress})
# after its finished
finished = True
return render_to_response('form1.html', {'finished': finished})
How can I implement something like this? Thanks in advance.
You can't maintain state between page calls on a global basis, so you'll need to store your data in the database. In addition, a view can't negotiate anything with the browser after it has returned a page, so you need to split this into multiple views and spawn a separate thread for the job. Here's a general outline that might help:
def do_something():
my_job = Jobs.get(id=blah)
my_job.in_progress = True
my_job.save()
# Do some stuff here....
my_job.in_progress = False
my_job.save()
def step1(request):
in_progress = Jobs.get(id=blah).in_progress
if not in_progress:
if request.method == 'POST':
form = SyncJobForm(request.POST)
if form.is_valid():
thread.start_new_thread(do_something)
return HttpResponseRedirect(step2)
else:
return render_to_response('form.html', 'form': form)
else:
form = SyncJobForm()
return render_to_response('form.html', 'form': form)
else:
return HttpResponseRedirect(step2)
def step2(request):
in_progress = Jobs.get(id=blah).in_progress
if in_progress:
return render_to_response('in_progress.html')
else:
return HttpResponseRedirect(finished)
def finished(request):
return render_to_response('finished.html')
Then have your page in_progress.html periodically refresh the page. When the job is completed, you can display a status message in finished.html.
There are more sophisticated ways to do this (write Javascript to poll the server periodically), but you're still going to need to write separate views to respond with the appropriate information. In addition, you could use a job management framework like Celery to create and execute jobs, but again you'll still have to create separate views to handle status information.
I am not able to think of doing this without some sort of call back from the client (unless you use some asynchronous server mechanism, something I am not familiar with). One way would be to have the client poll the server periodically after receiving the "in_progress" notification to see if the processing has finished. The server side can be split into two calls, first to handle the POST as shown in your question and another one to find out and report if a given task is finished.
I've got a view in Django that uses memcached to cache data for the more highly trafficked views that rely on a relatively static set of data. The key word is relatively: I need invalidate the memcached key for that particular URL's data when it's changed in the database. To be as clear as possible, here's the meat an' potatoes of the view (Person is a model, cache is django.core.cache.cache):
def person_detail(request, slug):
if request.is_ajax():
cache_key = "%s_ABOUT_%s" % settings.SITE_PREFIX, slug
# Check the cache to see if we've already got this result made.
json_dict = cache.get(cache_key)
# Was it a cache hit?
if json_dict is None:
# That's a negative Ghost Rider
person = get_object_or_404(Person, display = True, slug = slug)
json_dict = {
'name' : person.name,
'bio' : person.bio_html,
'image' : person.image.extra_thumbnails['large'].absolute_url,
}
cache.set(cache_key)
# json_dict will now exist, whether it's from the cache or not
response = HttpResponse()
response['Content-Type'] = 'text/javascript'
response.write(simpljson.dumps(json_dict)) # Make sure it's all properly formatted for JS by using simplejson
return response
else:
# This is where the fully templated response is generated
What I want to do is get at that cache_key variable in it's "unformatted" form, but I'm not sure how to do this--if it can be done at all.
Just in case there's already something to do this, here's what I want to do with it (this is from the Person model's hypothetical save method)
def save(self):
# If this is an update, the key will be cached, otherwise it won't, let's see if we can't find me
try:
old_self = Person.objects.get(pk=self.id)
cache_key = # Voodoo magic to get that variable
old_key = cache_key.format(settings.SITE_PREFIX, old_self.slug) # Generate the key currently cached
cache.delete(old_key) # Hit it with both barrels of rock salt
# Turns out this doesn't already exist, let's make that first request even faster by making this cache right now
except DoesNotExist:
# I haven't gotten to this yet.
super(Person, self).save()
I'm thinking about making a view class for this sorta stuff, and having functions in it like remove_cache or generate_cache since I do this sorta stuff a lot. Would that be a better idea? If so, how would I call the views in the URLconf if they're in a class?
URLConf should point to any callable. There's no strict requirement to make it point to function exactly. You could implement base class with your cache methods then extend it:
class RealView(BaseViewWithCacheMethods):
def __call__(self, request):
if request.is_ajax():
return self.ajax_view()
return self.html_view()
URLConf definition would be something like that:
from django.conf.urls.defaults import *
from views import RealView
urlpattrens = patterns('',
(r'^$', RealView()),
)