Opened 7 years ago

Closed 7 years ago

Last modified 5 years ago

#10953 closed (fixed)

Proxy model of a proxy model is of incorrect type.

Reported by: Tai Lee Owned by: Jacob
Component: Database layer (models, ORM) Version: master
Severity: Keywords: proxy type foreign key
Cc: Triage Stage: Accepted
Has patch: yes Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: UI/UX:

Description

If you proxy a model that is already a proxy, it will be of the same type as the first proxy. If the second proxy is used in a foreign key, you will not be able to create any model objects which have a value for that foreign key because they will fail the type check validation.

This means we can only ever proxy actual models, and cannot create a base proxy model to subclass as necessary.

# models.

from django.contrib.auth import models as auth_models
from django.db import models

class User1(auth_models.User):
	class Meta:
		proxy = True

class User2(User1):
	class Meta:
		proxy = True

class Something(models.Model):
	user = models.ForeignKey(User2)

# interactive shell.

>>> from myapp.models import User1, User2, Something

>>> type(User1.objects.get(username='admin'))
<class 'myapp.models.User1'>

>>> type(User2.objects.get(username='admin'))
<class 'myapp.models.User1'>

>>> Something.objects.create(user=User2.objects.get(username='admin'))
Traceback (most recent call last):
  File "<console>", line 1, in ?
  File "/path/to/django/db/models/manager.py", line 126, in create
    return self.get_query_set().create(**kwargs)
  File "/path/to/django/db/models/query.py", line 283, in create
    obj = self.model(**kwargs)
  File "/path/to/django/db/models/base.py", line 308, in __init__
    setattr(self, field.name, rel_obj)
  File "/path/to/django/db/models/fields/related.py", line 270, in __set__
    raise ValueError('Cannot assign "%r": "%s.%s" must be a "%s" instance.' %
ValueError: Cannot assign "<User1: admin>": "Something.user" must be a "User2" instance.

Attachments (2)

proxy-proxy.diff (1.8 KB) - added by Alex Gaynor 7 years ago.
proxy-proxy.2.diff (3.2 KB) - added by Alex Gaynor 7 years ago.

Download all attachments as: .zip

Change History (8)

comment:1 Changed 7 years ago by Tai Lee

Needs documentation: unset
Needs tests: unset
Patch needs improvement: unset

Looks like the incorrect model is being assigned to the manager (or simply being copied unchanged from the base proxy class). This causes any querysets from the manager to create model objects of the wrong type.

>>> User1.objects.model
<class 'myapp.models.User1'>
>>> User2.objects.model
<class 'myapp.models.User1'>

Changed 7 years ago by Alex Gaynor

Attachment: proxy-proxy.diff added

comment:2 Changed 7 years ago by Alex Gaynor

Has patch: set
milestone: 1.1
Triage Stage: UnreviewedAccepted

Changed 7 years ago by Alex Gaynor

Attachment: proxy-proxy.2.diff added

comment:3 Changed 7 years ago by Armin Ronacher

Owner: changed from nobody to Armin Ronacher

The fix for this ticket, including the one for #10955 which is related is attached to my github repo: http://github.com/mitsuhiko/django/tree/ticket-10953

comment:4 Changed 7 years ago by Jacob

Owner: changed from Armin Ronacher to Jacob
Status: newassigned

comment:5 Changed 7 years ago by Jacob

Resolution: fixed
Status: assignedclosed

(In [10738]) Fixed #10953, #10955: proxies of proxies now work correctly, though I still don't quite understand why you'd want to do such a thing. Thanks, Armin Ronacher.

comment:6 Changed 5 years ago by Jacob

milestone: 1.1

Milestone 1.1 deleted

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