Opened 2 years ago

Last modified 2 years 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

Description

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 Changed 2 years ago by Tim Graham

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 Changed 2 years ago by Denis Cornehl

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 Changed 2 years ago by Denis Cornehl

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

comment:4 Changed 2 years ago by Tim Graham

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 Changed 2 years ago by Tim Graham

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 Changed 2 years ago by felixxm

Cc: felisiak.mariusz@… added

comment:7 Changed 2 years ago by Tim Graham

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