Django: save() vs update() to update the database? - python
I'm writing a Django app, and I need a function to update a field in the database. Is there any reason to do one of these methods rather than the other?
def save_db_field(name,field,value):
obj = MyModel.objects.get(name=name)
obj.field = value
obj.save()
def update_db_field(name,field,value):
MyModel.objects.get(name=name).update(field=value)
It seems like the second is better because it does it in one DB call instead of two. Is there a reason why fetching, then updating is any better?
There are several key differences.
update is used on a queryset, so it is possible to update multiple objects at once.
As #FallenAngel pointed out, there are differences in how custom save() method triggers, but it is also important to keep in mind signals and ModelManagers. I have build a small testing app to show some valuable differencies. I am using Python 2.7.5, Django==1.7.7 and SQLite, note that the final SQLs may vary on different versions of Django and different database engines.
Ok, here's the example code.
models.py:
from __future__ import print_function
from django.db import models
from django.db.models import signals
from django.db.models.signals import pre_save, post_save
from django.dispatch import receiver
__author__ = 'sobolevn'
class CustomManager(models.Manager):
def get_queryset(self):
super_query = super(models.Manager, self).get_queryset()
print('Manager is called', super_query)
return super_query
class ExtraObject(models.Model):
name = models.CharField(max_length=30)
def __unicode__(self):
return self.name
class TestModel(models.Model):
name = models.CharField(max_length=30)
key = models.ForeignKey('ExtraObject')
many = models.ManyToManyField('ExtraObject', related_name='extras')
objects = CustomManager()
def save(self, *args, **kwargs):
print('save() is called.')
super(TestModel, self).save(*args, **kwargs)
def __unicode__(self):
# Never do such things (access by foreing key) in real life,
# because it hits the database.
return u'{} {} {}'.format(self.name, self.key.name, self.many.count())
#receiver(pre_save, sender=TestModel)
#receiver(post_save, sender=TestModel)
def reicever(*args, **kwargs):
print('signal dispatched')
views.py:
def index(request):
if request and request.method == 'GET':
from models import ExtraObject, TestModel
# Create exmple data if table is empty:
if TestModel.objects.count() == 0:
for i in range(15):
extra = ExtraObject.objects.create(name=str(i))
test = TestModel.objects.create(key=extra, name='test_%d' % i)
test.many.add(test)
print test
to_edit = TestModel.objects.get(id=1)
to_edit.name = 'edited_test'
to_edit.key = ExtraObject.objects.create(name='new_for')
to_edit.save()
new_key = ExtraObject.objects.create(name='new_for_update')
to_update = TestModel.objects.filter(id=2).update(name='updated_name', key=new_key)
# return any kind of HttpResponse
That resuled in these SQL queries:
# to_edit = TestModel.objects.get(id=1):
QUERY = u'SELECT "main_testmodel"."id", "main_testmodel"."name", "main_testmodel"."key_id"
FROM "main_testmodel"
WHERE "main_testmodel"."id" = %s LIMIT 21'
- PARAMS = (u'1',)
# to_edit.save():
QUERY = u'UPDATE "main_testmodel" SET "name" = %s, "key_id" = %s
WHERE "main_testmodel"."id" = %s'
- PARAMS = (u"'edited_test'", u'2', u'1')
# to_update = TestModel.objects.filter(id=2).update(name='updated_name', key=new_key):
QUERY = u'UPDATE "main_testmodel" SET "name" = %s, "key_id" = %s
WHERE "main_testmodel"."id" = %s'
- PARAMS = (u"'updated_name'", u'3', u'2')
We have just one query for update() and two for save().
Next, lets talk about overriding save() method. It is called only once for save() method obviously. It is worth mentioning, that .objects.create() also calls save() method.
But update() does not call save() on models. And if no save() method is called for update(), so the signals are not triggered either. Output:
Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.
# TestModel.objects.get(id=1):
Manager is called [<TestModel: edited_test new_for 0>]
Manager is called [<TestModel: edited_test new_for 0>]
save() is called.
signal dispatched
signal dispatched
# to_update = TestModel.objects.filter(id=2).update(name='updated_name', key=new_key):
Manager is called [<TestModel: edited_test new_for 0>]
As you can see save() triggers Manager's get_queryset() twice. When update() only once.
Resolution. If you need to "silently" update your values, without save() been called - use update. Usecases: last_seen user's field. When you need to update your model properly use save().
Both looks similar, but there are some key points:
save() will trigger any overridden Model.save() method, but update() will not trigger this and make a direct update on the database level. So if you have some models with overridden save methods, you must either avoid using update or find another way to do whatever you are doing on that overridden save() methods.
obj.save() may have some side effects if you are not careful. You retrieve the object with get(...) and all model field values are passed to your obj. When you call obj.save(), django will save the current object state to record. So if some changes happens between get() and save() by some other process, then those changes will be lost. use save(update_fields=[.....]) for avoiding such problems.
Before Django version 1.5, Django was executing a SELECT before INSERT/UPDATE, so it costs 2 query execution. With version 1.5, that method is deprecated.
In here, there is a good guide or save() and update() methods and how they are executed.
save() method can be used to insert new record and update existing record and generally used for saving instance of single record(row in mysql) in database.
update() is not used to insert records and can be used to update multiple records(rows in mysql) in database.
Using update directly is more efficient and could also prevent integrity problems.
From the official documentation https://docs.djangoproject.com/en/3.0/ref/models/querysets/#django.db.models.query.QuerySet.update
If you’re just updating a record and don’t need to do anything with
the model object, the most efficient approach is to call update(),
rather than loading the model object into memory. For example, instead
of doing this:
e = Entry.objects.get(id=10)
e.comments_on = False
e.save()
…do this:
Entry.objects.filter(id=10).update(comments_on=False)
Using update() also prevents a race condition wherein something might
change in your database in the short period of time between loading
the object and calling save().
Update only works on updating querysets. If you want to update multiple fields at the same time, say from a dict for a single object instance you can do something like:
obj.__dict__.update(your_dict)
obj.save()
Bear in mind that your dictionary will have to contain the correct mapping where the keys need to be your field names and the values the values you want to insert.
Update will give you better performance with a queryset of more than one object, as it will make one database call per queryset.
However save is useful, as it is easy to override the save method in your model and add extra logic there. In my own application for example, I update a dates when other fields are changed.
Class myModel(models.Model):
name = models.CharField()
date_created = models.DateField()
def save(self):
if not self.pk :
### we have a newly created object, as the db id is not set
self.date_created = datetime.datetime.now()
super(myModel , self).save()
Use _state.adding to differentiate update from create https://docs.djangoproject.com/en/3.2/ref/models/instances/
def save(self, *args, **kwargs):
# Check how the current values differ from ._loaded_values. For example,
# prevent changing the creator_id of the model. (This example doesn't
# support cases where 'creator_id' is deferred).
if not self._state.adding and (
self.creator_id != self._loaded_values['creator_id']):
raise ValueError("Updating the value of creator isn't allowed")
super().save(*args, **kwargs)
one of the differences that might cause a lot of headaches is that save updates, but update does NOT update columns of type DateTimeField(auto_now=True)
or ModificationDateTimeField
These fields automatically (should) set their date when an object is saved to the database.
save():
can be used with model object but not with QuerySet or Manager objects.
with select_for_update() can run SELECT FOR UPDATE query.
update()
can be used with QuerySet or Manager objects but not with model object.
with select_for_update() cannot run SELECT FOR UPDATE query.
For example, I have Person model as shown below:
# "store/models.py"
from django.db import models
class Person(models.Model):
name = models.CharField(max_length=30)
def __str__(self):
return self.name
Then, you can use save() with Person model object as shown below:
# "store/views.py"
from .models import Person
from django.http import HttpResponse
def test(request):
person = Person.objects.get(id=1)
person.name = 'Tom'
person.save() # Here
return HttpResponse("Test")
# "store/views.py"
from .models import Person
from django.http import HttpResponse
def test(request):
person = Person.objects.filter(pk=1).first()
person.name = 'Tom'
person.save() # Here
return HttpResponse("Test")
But, you cannot use save() with QuerySet object as shown below:
# "store/views.py"
from .models import Person
from django.http import HttpResponse
def test(request):
person = Person.objects.filter(pk=1)
person.name = 'Tom'
person.save() # Here
return HttpResponse("Test")
Then, the error below occurs:
AttributeError: 'QuerySet' object has no attribute 'save'
And, you cannot use save() with Manager object as shown below:
# "store/views.py"
from .models import Person
from django.http import HttpResponse
def test(request):
person = Person.objects
person.name = 'Tom'
person.save() # Here
return HttpResponse("Test")
Then, the error below occurs:
AttributeError: 'Manager' object has no attribute 'save'
Then, you can use update() with QuerySet object as shown below:
# "store/views.py"
from .models import Person
from django.http import HttpResponse
def test(request):
person = Person.objects.filter(pk=1)
person.update(name="Tom") # Here
return HttpResponse("Test")
And, you can use update() with Manager object as shown below:
# "store/views.py"
from .models import Person
from django.http import HttpResponse
def test(request):
person = Person.objects
person.update(name="Tom") # Here
return HttpResponse("Test")
But, you cannot use update() with Person model object as shown below:
# "store/views.py"
from .models import Person
from django.http import HttpResponse
def test(request):
person = Person.objects.get(id=1)
person.update(name="Tom") # Here
return HttpResponse("Test")
# "store/views.py"
from .models import Person
from django.http import HttpResponse
def test(request):
person = Person.objects.filter(pk=1).first()
person.update(name="Tom") # Here
return HttpResponse("Test")
Then, the error below occurs:
AttributeError: 'Person' object has no attribute 'update'
Next for example, select_for_update() is used to prevent race condition(lost update or write skew) when updating data in Django.
And, I have test view with save() and select_for_update().filter(pk=1).first() as shown below:
# "store/views.py"
from django.db import transaction
from .models import Person
from django.http import HttpResponse
#transaction.atomic
def test(request):
person = Person.objects.select_for_update().filter(pk=1).first() # Here
person.name = 'Tom'
person.save() # Here
return HttpResponse("Test")
Then, when I run test view, SELECT FOR UPDATE and UPDATE queries are run as shown below. *I used PostgreSQL and these logs below are the query logs of PostgreSQL and you can check On PostgreSQL, how to log SQL queries with transaction queries such as "BEGIN" and "COMMIT":
Now, I remove first() to use update() as shown below:
# "store/views.py"
from django.db import transaction
from .models import Person
from django.http import HttpResponse
#transaction.atomic
def test(request):
person = Person.objects.select_for_update().filter(pk=1) # Here
person.update(name="Tom") # Here
return HttpResponse("Test")
Then, when I run test view, SELECT FOR UPDATE query is not run and only UPDATE query is run as shown below:
And, I have test view with save() and select_for_update().get(pk=1) as shown below:
# "store/views.py"
from django.db import transaction
from .models import Person
from django.http import HttpResponse
#transaction.atomic
def test(request):
person = Person.objects.select_for_update().get(pk=1) # Here
person.name = 'Tom'
person.save() # Here
return HttpResponse("Test")
Then, when I run test view, SELECT FOR UPDATE and UPDATE queries are run as shown below:
Now, I remove get() to use update() as shown below:
# "store/views.py"
from django.db import transaction
from .models import Person
from django.http import HttpResponse
#transaction.atomic
def test(request):
person = Person.objects.select_for_update() # Here
person.update(name="Tom") # Here
return HttpResponse("Test")
Then, when I run test view, SELECT FOR UPDATE query is not run and only UPDATE query is run as shown below:
So, save() with select_for_update() can run SELECT FOR UPDATE query while update() with select_for_update() cannot.
Related
Why using validators=[URLValidator] when defining a model CharField doesn't make it check for URL-validity upon saving the corresponding ModelForm?
app.models.py: from django.core.validators import URLValidator from django.db import models class Snapshot(models.Model): url = models.CharField(max_length=1999, validators=[URLValidator]) app.forms.py: from django import forms from .models import Snapshot class SnapshotForm(forms.ModelForm): class Meta: model = Snapshot fields = ('url',) app.views.py: from django.http import HttpResponse from .forms import SnapshotForm def index(request): snapshot_form = SnapshotForm(data={'url': 'not an URL!'}) if snapshot_form.is_valid(): snapshot_form.save() return HttpResponse("") Why does it save 'not an URL!' into DB, despite the fact that it ain't a valid URL?! What is the right way to incorporate URLValidator?
You've specified the validators for your field like so: validators=[URLValidator]. This is incorrect because the validators argument takes in a list of callables that perform the validation. In this case even though URLValidator is callable but that's actually the __init__ method of the class being called. You need to pass an instance of the class for it to work properly: # Note the brackets after URLValidator to instantiate the class url = models.CharField(max_length=1999, validators=[URLValidator()]) Better yet since you want to take input a URL you should simply use the URLField class for your field: url = models.URLField(max_length=1999)
Django Rest Framework Returns old Data after post_save Signal
I have game,genre and producer tables. User creates new games through admin panel. After user creates a new game i need to do something but i have a problem. After new game has been created django sends signal and runs game_changed method. Problem is when i send get request to /api/game/ (Django rest framework endpoint) after i got signal of new game has been created response doesn't have this new model. More interesting is first i get count of game table through Game.objects.count i get 3 (correct) after that i send get request to game endpoint and response has 2 games. What causes this? Models: class Game(models.Model): name=models.CharField(max_length=50) producer=models.ForeignKey("Producer",on_delete=models.CASCADE) genres=models.ManyToManyField("Genre") def __str__(self): return self.name class Producer(models.Model): name=models.CharField(max_length=50) def __str__(self): return self.name class Genre(models.Model): name=models.CharField(max_length=50) def __str__(self): return self.name Signals: from django.db.models import signals from django.dispatch import receiver from .models import Game #receiver(signals.post_save,sender=Game) def game_changed(sender,**kwargs): print(Game.objects.count())#Returns 3 import requests url="http://localhost:8000/api/game/" response=requests.get(url) print(response.json())# returns 2 games instead of 3 Views: from rest_framework.viewsets import ReadOnlyModelViewSet from .serializers import GenreSerializer,GameSerializer,ProducerSerializer from .models import Genre,Game,Producer class GenreViewSet(ReadOnlyModelViewSet): queryset=Genre.objects.all() serializer_class=GenreSerializer search_fields=("name",) class GameViewSet(ReadOnlyModelViewSet): queryset=Game.objects.all() serializer_class=GameSerializer filterset_fields=("genres","producer") search_fields=("name",) class ProducerViewSet(ReadOnlyModelViewSet): queryset=Producer.objects.all() serializer_class=ProducerSerializer search_fields=("name",)
I believe what's occuring here is a transaction isolation timing issue. While the transaction has been committed the database hasn't gotten to the point where it's readable. You can configure the transaction isolation level in your database settings. Or you can use transaction.on_commit. I'd probably reach for transaction.on_commit as modifying your transaction isolation level can have wide reaching effects.
how to access field using django signals
I would like to check the value of a field (lightStatusA) when a new record is saved into my Django database. I feel like iv'e read the docs 10 times and still can't grasp how to get this. Here is my current models.py code: from django.db import models from accounts.models import Customer from django.conf import settings from django.contrib.auth import get_user_model from django.db.models.signals import post_save class Data(models.Model): author = models.ForeignKey(get_user_model(),on_delete=models.CASCADE,) tempData= models.CharField(max_length=50,blank=True,) humidData= models.CharField(max_length=50,blank=True,) lightStatusA= models.BooleanField(default=True,) dateTime = models.DateTimeField(auto_now_add=True) def __str__(self): return str(self.author) def check_light_status(sender, **kwargs): if kwargs['created']: #make sure its a new record #need logic to grab instance.lightStatusA and check it's value post_save.connect(check_light_status, sender = Data) Is there some way of passing this value as an argument to the signal?
The check_light_status function can accept an instance parameter. From the docs: instance The actual instance being saved. Update: You said this: instance returns the author of the post. I am going to use my powers of deduction to guess that you tried print(instance) and saw the author. Look at your __str__ implementation. def __str__(self): return str(self.author) I'd say you sabotaged yourself a bit there ;)
Ahh ok got it: def check_light_status(sender, instance, **kwargs): if kwargs['created']: #make sure its a new record print(instance.lightStatusA) This prints the the field I need to run some logic against.
In Django, how to find rows which would violate a unique together constraint?
For the following API endpoint, import json from django.contrib.auth.decorators import login_required from django.http import JsonResponse, HttpResponseBadRequest from django.views.decorators.http import require_POST from lucy_web.models import UserApn #login_required #require_POST def save_apn(request, version): player_id = json.loads(request.body).get('player_id') if player_id: UserApn.objects.get_or_create(user=request.user, player_id=player_id) return JsonResponse({'status': 'success'}) else: return HttpResponseBadRequest() Here is the underlying model: from django.contrib.auth.models import User from django.db import models from .timestamped_model import TimeStampedModel class UserApn(TimeStampedModel): user = models.ForeignKey(User) player_id = models.CharField(max_length=255) The call to get_or_create() has been raising some MultipleObjectsReturned errors. To fix this, I'd like to impose a unique_together constraint on the user and player_id. Firstly, however, I have to write a data migration that eliminates rows that violate this unique together constraint. How could I write a query that selects these? Right now the following has been proposed: def remove_duplicate_apns(apps, schema_editor): UserApn = apps.get_model('lucy_web', 'UserApn') previous_user_id = None previous_player_id = None for apn in UserApn.objects.all().order_by('user_id', 'player_id'): if apn.user_id == previous_user_id and apn.player_id == previous_player_id: print(f'deleting {apn} (id: {apn.id})') apn.delete() else: previous_user_id = apn.user_id previous_player_id = apn.player_id It seems, though, that this could also be done in a single query. Update I've found that one can pass the two fields, user and player_id, to .values(), and then check for duplicates using .distinct(). For example, the following test passes: from django.test import TestCase from django.contrib.auth.models import User from myapp.models import UserApn class UserApnTest(TestCase): def test_1(self): user = User.objects.create_user(username='jayz') apn1 = UserApn.objects.create(user=user, player_id='foo') apn2 = UserApn.objects.create(user=user, player_id='foo') apn3 = UserApn.objects.create(user=user, player_id='bar') self.assertEqual( len(UserApn.objects.values('user', 'player_id')) - len(UserApn.objects.values('user', 'player_id').distinct()), 1) The problem remains, however, that the output from this is dictionaries with user_id and player_id, but the original id is lost, so I can't subsequently get() the duplicate objects and delete them. How can I do something similar but retain references to the duplicate objects?
I managed to group the duplicate UserApns into the following queryset: UserApn.objects.all().difference(UserApn.objects.distinct('user', 'player_id')) Note that passing multiple arguments to distinct() only works on PostgreSQL.
Accessing the user's request in a post_save signal
I have done the below post_save signal in my project. from django.db.models.signals import post_save from django.contrib.auth.models import User # CORE - SIGNALS # Core Signals will operate based on post def after_save_handler_attr_audit_obj(sender, **kwargs): print User.get_profile() if hasattr(kwargs['instance'], 'audit_obj'): if kwargs['created']: kwargs['instance'].audit_obj.create(operation="INSERT", operation_by=**USER.ID**).save() else: kwargs['instance'].audit_obj.create(operation="UPDATE").save() # Connect the handler with the post save signal - Django 1.2 post_save.connect(after_save_handler_attr_audit_obj, dispatch_uid="core.models.audit.new") The operation_by column, I want to get the user_id and store it. Any idea how can do that?
Can't be done. The current user is only available via the request, which is not available when using purely model functionality. Access the user in the view somehow.
I was able to do it by inspecting the stack and looking for the view then looking at the local variables for the view to get the request. It feels like a bit of a hack, but it worked. import inspect, os #receiver(post_save, sender=MyModel) def get_user_in_signal(sender, **kwargs): for entry in reversed(inspect.stack()): if os.path.dirname(__file__) + '/views.py' == entry[1]: try: user = entry[0].f_locals['request'].user except: user = None break if user: # do stuff with the user variable
Ignacio is right. Django's model signals are intended to notify other system components about events associated with instances and their respected data, so I guess it's valid that you cannot, say, access request data from a model post_save signal, unless that request data was stored on or associated with the instance. I guess there are lots of ways to handle it, ranging from worse to better, but I'd say this is a prime example for creating class-based/function-based generic views that will automatically handle this for you. Have your views that inherit from CreateView, UpdateView or DeleteView additionally inherit from your AuditMixin class if they handle verbs that operate on models that need to be audited. The AuditMixin can then hook into the views that successfully create\update\delete objects and create an entry in the database. Makes perfect sense, very clean, easily pluggable and gives birth to happy ponies. Flipside? You'll either have to be on the soon-to-be-released Django 1.3 release or you'll have to spend some time fiddlebending the function-based generic views and providing new ones for each auditing operation.
You can do that with the help of middleware. Create get_request.py in your app. Then from threading import current_thread from django.utils.deprecation import MiddlewareMixin _requests = {} def current_request(): return _requests.get(current_thread().ident, None) class RequestMiddleware(MiddlewareMixin): def process_request(self, request): _requests[current_thread().ident] = request def process_response(self, request, response): # when response is ready, request should be flushed _requests.pop(current_thread().ident, None) return response def process_exception(self, request, exception): # if an exception has happened, request should be flushed too _requests.pop(current_thread().ident, None) Then add this middleware to your settings: MIDDLEWARE = [ .... '<your_app>.get_request.RequestMiddleware', ] Then add import to your signals: from django.db.models.signals import post_save from django.contrib.auth.models import User from <your_app>.get_request import current_request # CORE - SIGNALS # Core Signals will operate based on post def after_save_handler_attr_audit_obj(sender, **kwargs): print(Current User, current_request().user) print User.get_profile() if hasattr(kwargs['instance'], 'audit_obj'): if kwargs['created']: kwargs['instance'].audit_obj.create(operation="INSERT", operation_by=**USER.ID**).save() else: kwargs['instance'].audit_obj.create(operation="UPDATE").save() # Connect the handler with the post save signal - Django 1.2 post_save.connect(after_save_handler_attr_audit_obj, dispatch_uid="core.models.audit.new")
Why not adding a middleware with something like this : class RequestMiddleware(object): thread_local = threading.local() def process_request(self, request): RequestMiddleware.thread_local.current_user = request.user and later in your code (specially in a signal in that topic) : thread_local = RequestMiddleware.thread_local if hasattr(thread_local, 'current_user'): user = thread_local.current_user else: user = None
For traceability add two attributes to your Model(created_by and updated_by), in "updated_by" save the last user who modified the record. Then in your signal you have the user: models.py: class Question(models.Model): question_text = models.CharField(max_length=200) pub_date = models.DateTimeField('date published') created_by = models. (max_length=100) updated_by = models. (max_length=100) views.py p = Question.objects.get(pk=1) p.question_text = 'some new text' p.updated_by = request.user p.save() signals.py #receiver(pre_save, sender=Question) def do_something(sender, instance, **kwargs): try: obj = Question.objects.get(pk=instance.pk) except sender.DoesNotExist: pass else: if not obj.user == instance.user: # Field has changed # do something print('change: user, old=%s new=%s' % (obj.user, instance.user))
You could also use django-reversion for this purpose, e.g. from reversion.signals import post_revision_commit import reversion #receiver(post_save) def post_revision_commit(sender, **kwargs): if reversion.is_active(): print(reversion.get_user()) Read more on their API https://django-reversion.readthedocs.io/en/stable/api.html#revision-api
You can do a small hack by overriding you model save() method and setting the user on the saved instance as additional parameter. To get the user I used get_current_authenticated_user() from django_currentuser.middleware.ThreadLocalUserMiddleware (see https://pypi.org/project/django-currentuser/). In your models.py: from django_currentuser.middleware import get_current_authenticated_user class YourModel(models.Model): ... ... def save(self, *args, **kwargs): # Hack to pass the user to post save signal. self.current_authenticated_user = get_current_authenticated_user() super(YourModel, self).save(*args, **kwargs) In your signals.py: #receiver(post_save, sender=YourModel) def your_model_saved(sender, instance, **kwargs): user = getattr(instance, 'current_authenticated_user', None) PS: Don't forget to add 'django_currentuser.middleware.ThreadLocalUserMiddleware' to your MIDDLEWARE_CLASSES.
I imagine you would have figured this out, but I had the same problem and I realised that all the instances I create had a reference to the user that creates them (which is what you are looking for)
it's possible i guess. in models.py class _M(models.Model): user = models.ForeignKey(...) in views.py def _f(request): _M.objects.create(user=request.user) in signals.py #receiver(post_save, sender=_M) def _p(sender, instance, created, **kwargs): user = instance.user No ?
Request object can be obtained from frame record by inspecting. import inspect request = [ frame_record[0].f_locals["request"] for frame_record in inspect.stack() if frame_record[3] == "get_response" ][0]
def get_requested_user(): import inspect for frame_record in inspect.stack(): if frame_record[3] == 'get_response': request = frame_record[0].f_locals['request'] return request.user else: return None
context_processors.py from django.core.cache import cache def global_variables(request): cache.set('user', request.user) ---------------------------------- in you model from django.db.models.signals import pre_delete from django.dispatch import receiver from django.core.cache import cache from news.models import News #receiver(pre_delete, sender=News) def news_delete(sender, instance, **kwargs): user = cache.get('user') in settings.py TEMPLATE_CONTEXT_PROCESSORS = ( 'web.context_processors.global_variables', )