Opened 8 years ago

Last modified 19 months ago

#25600 new Bug

Template `if` tag behavior change with 1.8, OneToOneField, RelatedObjectDoesNotExist is True?

Reported by: Denis Cornehl Owned by: nobody
Component: Template system Version: 1.8
Severity: Normal Keywords:
Cc: felisiak.mariusz@… Triage Stage: Accepted
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no


We discovered a strange behavior change when upgrading from Django 1.7 to 1.8.

Let's assume we have a OneToOneField like here:

class Customer(models.Model):
    name = models.CharField(max_length=100)

class Project(models.Model):
    customer = models.OneToOneField(Customer)
    title = models.CharField(max_length=100)

the template gets the Customer instance, without a project, in the context.

{% if customer.project %}
    {# on 1.8 we get here #}
{% else %}
    {# on 1.7 we get here #}
{% endif %}

when debugging and trying to access customer.project in a django shell, we get a RelatedObjectDoesNotExist in both versions, so this does not seem to have changed.

So to us it looks like the behavior of the if tag in templates changed.

I'm happy to provide more info as needed, or test stuff. Or even write a PR / Fix if someone points me to possible places where this could have been changed / broken.

Change History (7)

comment:1 by Tim Graham, 8 years ago

I can't reproduce that -- I'm always seeing the else branch on master and stable/1.8.x. Maybe you could provide a failing test case for Django's test suite?

comment:2 by Denis Cornehl, 8 years ago

wanted to play around a little to find the point where it stopped working (in our codebase).

I starts happening when we set TEMPLATE_STRING_IF_INVALID to any value (with %s or without)

Out of curiosity I tried if it's related to the old (TEMPLATE_STRING_IF_INVALID or the new (string_if_invalid option in the TEMPLATES config, but it happens always.

comment:3 by Denis Cornehl, 8 years ago

I can still try do write a failing testcase if it helps

comment:4 by Tim Graham, 8 years ago

Severity: NormalRelease blocker
Triage Stage: UnreviewedAccepted

Okay, making that setting a non-empty value is the piece I was missing to reproduce. Bisected the change to 0dd05c9e66ebb5cb97136f84373f43582783e1a6. It's not immediately obvious to me what the resolution should be, but at least some documentation could be added if we decide not to change the behavior.

comment:5 by Tim Graham, 8 years ago

The RelatedObjectDoesNotExist exception is a subclass of AttributeError -- that's why it's hitting that logic added in the commit noted in the previous comment. We end up checking {% if <string_if_invalid> %} which passes for a non-empty string_if_invalid. I'm not sure we should add special handling of RelatedObjectDoesNotExist in the template engine to restore the old behavior (and I'm not sure how to since RelatedObjectDoesNotExist is a dynamically generated exception based on the related descriptors).

I think the usage of string_if_invalid is somewhat unreliable/unpredictable anyway and therefore discouraged but I'm not too sure as I haven't used it myself.

comment:6 by Mariusz Felisiak, 8 years ago

Cc: felisiak.mariusz@… added

comment:7 by Tim Graham, 8 years ago

Severity: Release blockerNormal

Per discussion on django-developers, demoting from a release blocker since string_if_invalid is only intended for debugging. Inconsistencies in how the {% if %} tag silences exceptions (#17664) may be related.

Note: See TracTickets for help on using tickets.
Back to Top