#33984: Related managers cache gets stale after saving a fetched model with new 
PK
-------------------------------------+-------------------------------------
     Reporter:  joeli                |                    Owner:  Mariusz
                                     |  Felisiak
         Type:  Bug                  |                   Status:  closed
    Component:  Database layer       |                  Version:  4.1
  (models, ORM)                      |
     Severity:  Release blocker      |               Resolution:  fixed
     Keywords:                       |             Triage Stage:  Accepted
    Has patch:  1                    |      Needs documentation:  0
  Needs tests:  0                    |  Patch needs improvement:  0
Easy pickings:  0                    |                    UI/UX:  0
-------------------------------------+-------------------------------------

Comment (by Steven Mapes):

 Is this why model forms now, since Django 4.1.0 raise ValueErrors if you
 try access Related Managers within the __init__ even if you check for the
 the instance being set along with the relationship?

 I.E If you have models and a Model form like this

 {{{
 # models.py
 from django.db import models


 class Tag(models.Model):
     tag = models.SlugField(max_length=64, unique=True)


 class Thing(models.Model):
     tag = models.ForeignKey(Tag, on_delete=models.CASCADE,
 related_name="things")
     active = models.BooleanField(default=True)

 }}}

 {{{
 # forms.py
 from django import forms
 from example.models import Tag


 class TagForm(forms.ModelForm):
     class Meta:
         model = Tag
         fields = ["tag"]

     def __init__(self, *args, **kwargs):
         super(TagForm, self).__init__(*args, **kwargs)

         if self.instance and self.instance.things:
             inactive_things = self.instance.things.filter(active=False)
             # Do something with it

 }}}

 Then have the following test

 {{{
 from unittest.case import TestCase
 from example.forms import TagForm


 class TagFormCase(TestCase):
     def test_required(self):
         """Test required fields"""
         form = TagForm({})
         self.assertFalse(form.is_valid())
         self.assertEqual(
             {
                 "tag": ["This field is required."],
             },
             form.errors,
         )


 }}}

 The test would pass in all Django versions up to 4.1. From 4.1.0 onwards
 it raises a ValueError of ```ValueError: 'Tag' instance needs to have a
 primary key value before this relationship can be used.```

 In order for the test to pass you need to change the flow control to ```if
 self.instance.pk and self.instance.things```. You can't use
 ```self.instance.things.count()``` as it raises the exception.

 However if you overload the primary key on the model to use a UUID such
 as:

 {{{
 # models.py
 import uuid
 from django.db import models


 class Tag(models.Model):
     id = models.UUIDField(primary_key=True, default=uuid.uuid4,
 editable=False)
     tag = models.SlugField(max_length=64, unique=True)


 class Thing(models.Model):
     tag = models.ForeignKey(Tag, on_delete=models.CASCADE,
 related_name="things")
     active = models.BooleanField(default=True)
 }}}

 then the original test will pass as the uuid will be set prior to saving

-- 
Ticket URL: <https://code.djangoproject.com/ticket/33984#comment:18>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.

-- 
You received this message because you are subscribed to the Google Groups 
"Django updates" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-updates/01070183c65cce99-7ad7a312-165a-4542-b4d4-cf975cd7fb57-000000%40eu-central-1.amazonses.com.

Reply via email to