5

I have migrated to a Django custom user model (CustomUser) which is into which several other models have foreign key and M2M relationships. CustomUser is also subclassed by Zinnia's author model (Author) - Zinnia is an excellent third party blogging app.

My issue is that when I access CustomUser via a relationship e.g OtherModel.customuser it returns an instance of CustomUser, but in my views when I access request.User it is an instance of Author. Since the attributes of Author and CustomUser are identical this in general doesn't make much difference but if I want to test equivalence of user objects in my Views I have to user request.user.id rather than request.user and I instinctively don't like the ambiguity over which model I am dealing with.

Possibly I am better getting over it and leaving things as they are since everything works after a few minor code changes in my views. In a perfect world, though, I would be referring consistently to the same User model but am uncertain how best to progress. Any ideas?

settings.py

AUTH_USER_MODEL = 'profiles.CustomUser'

models.py (in profiles app)

class CustomUser(AbstractUser):

    visits = models.PositiveIntegerField(
        _('visits'),
        default=0,
        blank=True
    )

    def __unicode__(self):
        return self.username

class OtherModel(models.Model):

    author = models.ForeignKey(CustomUser)

I know the recommendation in the documentation is to make the relationship with settings.AUTH_USER_MODEL rather than directly with the custom user model. I plan to change that but want to understand what I am doing before launching again into the pain of a migration

author.py (in zinnia app)

from django.contrib.auth import get_user_model


@python_2_unicode_compatible
class Author(get_user_model()):
    """
    Proxy model around :class:`django.contrib.auth.models.get_user_model`.
    """

    objects = get_user_model()._default_manager
    published = EntryRelatedPublishedManager()

In the console get_user_model() returns the profiles.models.CustomUser class

santiago
  • 53
  • 3

1 Answers1

0

I think I get your problem.

By default, Django does not downcast model instances. For exemple, take the following example:

from django.db import models

class Parent(models.Model):
    name = models.CharField()

class Child(Parent):
    pass

Parent(name="parent").save()
Child(name="child").save()

Parent.objects.all() # will return Parent instances
Child.objects.all() # will return Child instances

In your situation, well, you have Zinnia working with Author instances, and the rest of your project with CustomUser instance. So basically you could downcast every CustomUser instance. You can achieve this using an existing django application, such as django-polymorphic (which, in my opinion, is a must have when working with concrete inheritance). However, if all your users are not authors, you're screwed

You can also compromise, and implement a manual upcast as follows:

from django.contrib.auth import get_user_model

class CustomUser(AbstractUser):

   # your logic...

    def as_custom_user(self):
        return super(get_user_model(), self)

Usage:

assert request.user.as_custom_user() == article.author.as_custom_user()
Agate
  • 3,152
  • 1
  • 19
  • 30