#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 django-updates+unsubscr...@googlegroups.com.
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