Reputation: 3465
Does Django flattening response after process_response?
I have this model (simplified version):
class Ticket(models.Model):
uuid = UUIDField(primary_key = True)
is_active = models.BooleanField(default = False)
remains = models.IntegerField(default = 2)
def __unicode__(self):
return '%s' % (self.is_active)
and middleware (simplified):
class TicketMiddleware(object):
def process_request(self, request):
# ...
try:
request.ticket = Ticket.objects.get(uuid_exact=request.GET['ticket'], is_active=True)
print '%s %d' % (request.ticket.is_active, request.ticket.remains)
# first case:
return HttpResponse(request.ticket)
# second case:
#return HttpResponse(request.ticket.is_active)
except Ticket.DoesNotExists:
return HttpResponseForbidden()
def process_response(self, request, response):
if request.ticket is not None and request.ticket.remains > 0:
request.ticket.remains -= 1
if request.ticket.remains == 0:
request.ticket.is_active = False
request.ticket.save()
return response
In first case I got forbidden page on fourth request:
RESPONSE PRINT
1: True True 2
2: False True 1
3: False True 1
4: Forbidden
In second case I got forbidden page on third request:
RESPONSE PRINT
1: True True 2
2: True True 1
3: Forbidden
And this second case is the way I want. Why I must stringify my model first for properly flow? What I misunderstood?
django.VERSION = (1, 2, 3, 'final', 0)
I found the problem. In real code I use foreign key for django.contrib.auth.models.User and unicoding my Ticket model with username of associated User:
class Ticket(models.Model):
# ...
user = models.ForeignKey(User)
def __unicode__(self):
# this works as expected
return u'%s' % (self.is_active)
# with this I have unexpected third step in first case
# but I dont understand why
#return u'%s %s' % (self.user.username, self.is_active)
Upvotes: 1
Views: 4219
Reputation: 8482
I really doubt that the first case displays two times False
. I've made a simple test with your code, and it displays for the first case:
1: True
2: False
3: Forbidden
which is the expected behavior. As long as the process_response
modifies the is_active
data and saves the ticket on the second call, I don't see how a third call can return False... Unless the ticket.remains is modified somehow. With the code shown here, I can't see how it is possible that process_response
to save the ticket with is_active=False
, and on subsequent request process_request
not to redirect to Forbidden
... Which Django version do you use? Print also ticket.remains
in the __unicode__()
to see how it changes ...
The reason that you get False
in the second call with 1st case is that you pass a model instance
return HttpResponse(request.ticket)
The ticket.__unicode__()
is being called after the process_response
is being called, during the final writing of the contents of HttpResponse()
to the client. And since in the first scenario ticket.is_active
is being modified in process_response
, when ticket.__unicode__()
is finally called, it gets the modified value of ticket.is_active
which is False
.
In the second scenario the __unicode__
is called explicitly in process_request and evaluated to 'True'.
Upvotes: 3