Search code examples
pythondjangodjango-modelsdjango-users

Migrating existing models to Django built-in User Models


I am running a Django 1.4.2 project. I have a database of class User(models.Model), and would now like to change this so that I used the built in model User from django.contrib.auth.models. Can I simply use my existing code and simply make my own custon User model a subclass of Django's built in one? Here is the model now.

class User(models.Model):
    u_id = models.AutoField(primary_key=True)
    #password = models.CharField(max_length=765)
    old_password = models.CharField(max_length=765, null=True, blank=True)
    birthday = models.DateField(null=True, blank=True)
    school_year = models.CharField(max_length=765, blank=True)
    gender = models.CharField(max_length=18, blank=True)
    #email = models.CharField(max_length=765, blank=True)
    profile_pic = models.CharField(max_length=765, blank=True)
    is_cloudinary_pic = models.BooleanField(default=False)
    fb_id = models.CharField(max_length=765, blank=True)
    phone_num = models.CharField(max_length=765, blank=True)
    name = models.CharField(max_length=765, blank=True)
    confirmcode = models.CharField(max_length=765, blank=True)
    status = models.CharField(max_length=765, blank=True)
    netid = models.CharField(max_length=765, blank=True)
    favorites = models.ManyToManyField('listings.Listing', blank=True, related_name='favorites')
    stripe = models.CharField(max_length=765, blank=True)
    rating = models.IntegerField(null=True, blank=True)
    preferences = models.CharField(max_length=765, blank=True)
    b_notification = models.CharField(max_length=765, blank=True)
    l_notification = models.CharField(max_length=765, blank=True)
    address = models.CharField(max_length=765, blank=True)
    city = models.CharField(max_length=765, blank=True)
    state = models.CharField(max_length=6, blank=True)
    zip = models.CharField(max_length=15, blank=True)
    emailprefs = models.CharField(max_length=30, blank=True)
    exp_month = models.CharField(max_length=6, blank=True)
    exp_year = models.CharField(max_length=12, blank=True)
    last4 = models.CharField(max_length=12, blank=True)
    c_type = models.CharField(max_length=765, blank=True)
    user_type = models.CharField(max_length=10, blank=True)
    contract = models.ForeignKey('contracts.Contract', null=True,blank=True, default=None, on_delete=models.SET_NULL)
    last_listing_booked = models.ForeignKey('listings.Listing', null=True,blank=True, default=None, on_delete=models.SET_NULL, related_name='last_listing_booked')
    last_locked_on = models.IntegerField(null=True, blank=True)
    waitlist_number = models.IntegerField(null=True, blank=True)
    waitlist_listing = models.ForeignKey('listings.Listing', null=True, blank=True, on_delete=models.SET_NULL, related_name='waitlist_listing')
    uploaded_contract = models.FileField(upload_to=contract_file_name, max_length=765, null=True, blank=True, default=None, storage=FileSystemStorage(location=os.path.join(MEDIA_ROOT, 'contracts')))

When I try to migrate using Django South after making my model a subclass of the Django User model, I am asked to set a value for user_ptr, a field about which I have been unsuccessful finding any information.

In general, is it unsafe to simply subclass in this fashion? I cannot afford to lose all the user data I already have and start over. Note that the password and email fields are commented out because they clash with Django's version of those fields.


Solution

  • If upgrading to Django 1.5 is an option, you can simply use your own User model, so long as it supplies all the required fields.

    user_ptr is an implicit OneToOne model that associates your object with the class you're deriving from. The easiest way to do this would probably be to create the migration manually in these steps:

    1. Add the user_ptr field WITH null=True

    2. Iterate over all the User objects and create the corresponding auth.User objects. If you are unsure of how to do this, you can read the section on data migrations in the South documentation.

    3. Disallow null user_ptr fields

    Another thing you might need to do is implement your own password hasher if the hashing scheme you used isn't compatible with Django's built in methods. This is not very hard to do, and is addressed in another question.