Opened 8 years ago
Closed 8 years ago
#28732 closed Bug (duplicate)
Deleted OneToOneRelation still referenced (not None) after refresh_from_db
| Reported by: | JeroenPeterBos | Owned by: | nobody | 
|---|---|---|---|
| Component: | Database layer (models, ORM) | Version: | 1.9 | 
| Severity: | Normal | Keywords: | Refresh Database Object Delete | 
| Cc: | jeroenbosleusden2@… | Triage Stage: | Unreviewed | 
| Has patch: | no | Needs documentation: | no | 
| Needs tests: | no | Patch needs improvement: | no | 
| Easy pickings: | no | UI/UX: | no | 
Description
Issue:
I ran into the following problem. I have a test that will retrieve an account which has a relation to ActivationCode. In the test i call a function that recieves a string with which it can find the activationcode, after that the funciton will call delete on the ActivationCode. Now the problem is, when i call refresh_from_db() on the account it will say that account still has a related Activation Code ( while it obviously hasn't ) and the problem is proved when i call on this related ActivationCode, because a DoesNotExist exception will be thrown.
In my oppinion also this deleted relation object should be reflected in account when refreshing it.
Below is the relevant code
Models
class Account(models.Model):
    user = models.OneToOneField(User)
    activated = models.BooleanField(default=False)
class ActivationCode(models.Model):
    account = models.OneToOneField(Account, unique=True)
    code = models.CharField(max_length=128)
    timestamp = models.DateTimeField(auto_now_add=True)
Controller
def confirm(confirmData: dict) -> bool:
    """
    Activates the account associated with the given code.
    :param confirmData: The data needed to confirm the account.
    :return: Whether the activation was successful.
    """
    form = forms.ConfirmForm(confirmData)
    if not form.is_valid():
        return False
    data = form.cleaned_data
    try:
        confirmObject = ActivationCode.objects.get(code=data['code'])
    except ActivationCode.DoesNotExist:
        return False
    confirmObject.account.activated = True
    confirmObject.account.save()
    confirmObject.delete()
    return True
The test that failes
class ActivateTest(TestCase):
    def setUp(self):
        controller.register(testUser)
    def testActivateSingleUser(self):
        account = User.objects.get(username=testUser['username']).account
        success = controller.confirm({'code': account.activationcode.code})
        account.refresh_from_db()
        self.assertTrue(success)
        self.assertTrue(account.activated)
        # account.activationcode.refresh_from_db() # uncommenting this line will result in a DoesNotExist exception
        self.assertFalse(hasattr(account, 'activationcode')) # This test fails.
Finally the Traceback
FAIL: testActivateSingleUser (Main.tests.ActivateTest) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\Users\Path\To\Project\Main\tests.py", line 53, in testActivateSingleUser self.assertFalse(hasattr(account, 'activationcode')) AssertionError: True is not false
Duplicate of #27846, should be fixed in Django 2.0.