User Model Setup from Existing (Drupal) Database Table

Hello,

I’m working on a project to replace a Drupal 6 application, and am trying to figure out how to use its MySQL ‘users’ table to create my Django user models. Both apps are housed on the same server so I have easy access to the db. The Drupal ‘users’ database is still actively used for a greater application from which my project is a subset, so I am not able to restructure it, and I’m hoping to avoid requiring separate accounts for my app since it is all part of the same ecosystem.

I’ve researched AbstractUser and AbstractBaseUser, but have not found a way to assign columns from an existing table to the username and password variables. All of the custom user model solutions seem to assume that the user database is starting fresh, and takes care of assigning, storing, and saving usernames and passwords behind the scenes.

I’m considering using a standard User model, checking unrecognized usernames and passwords against the Drupal User db, and creating a new Django user on the first login if it exists. Is this my best bet? It seems cumbersome but haven’t found a better solution.

What I’d like to do (or something of the sort):

class User(AbstractBaseUser):
    uid = models.AutoField(primary_key=True)
    username = models.CharField(unique=True, max_length=60)
    password = models.CharField( max_length=32) 
    mail = models.CharField(max_length=64, blank=True, null=True)
    USERNAME_FIELD = 'username'
    class Meta:
        managed = False
        db_table = 'users'

Some other info:

I presume I’ll need to write a custom authentication backend to decode the hashed Drupal password as it is stored in the db, but I imagine this should be pretty easy once I have the model ironed out.

I’m pretty new to Django so forgive my ignorance. Thanks!

(Please highlight code on the forum using the markdown tools)

Hi!

I think this should be possible using the db_column argument of fields

class User(AbstractBaseUser):
    username = models.CharField(
        _('username'),
        db_column='the_column_drupal_uses',
        max_length=150,
        unique=True,
        help_text=_('Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.'),
        validators=[username_validator],
        error_messages={
            'unique': _("A user with that username already exists."),
        },
    )
    ...

To avoid copying all of the arguments, you can use the clone_field helper from my blog post Synchronizing Django model definitions:

class User(AbstractBaseUser):
    username = clone_field(AbstractBaseUser, 'username', db_column='the_column_drupal_uses')
    ...

Hope that helps,

Adam

Hey Adam,

Thank you! I fixed the formatting issue.

Will I be able to do the same for the password column? If so, I take it I will just have to redefine the authenticate() method to align with Drupal’s hashing methods?

Thanks,
Michael

Hopefully! You might be able to just build a custom password hasher rather than a full authentication backend. When you have solved this, it sounds like a good blog post…