A. S.
A. S.

Reputation: 153

Am I overriding the save method on the model in a wrong way in django?

I have a Profile model that extends the user model like so,

class Profile(User):
    user = models.OneToOneField(User, parent_link=True, on_delete=models.CASCADE)
    slug = models.SlugField(unique=True, blank=True)
    def save(self, *args, **kwargs):
        print('self.username')
        print(self.username)
        self.slug = self.username
        super(Profile, self).save(*args, **kwargs)

I am trying to create a slug field for my model , so I override the save method to include the slug as the username. The thing is, when I create a new user with the command createsuperuser and print out the username as you can see in the code, it doesn't show anything - it doesn't show the provided username. Could this be the reason why I am having this problem ? And if so, how can I fix it?

Upvotes: 2

Views: 596

Answers (3)

mazurekt
mazurekt

Reputation: 303

Profile cannot inherit User but instead should inherit Model. And, for the creation of User to be able to create a corresponding row in a different table (Profile) and set the slug will involve the use of signals.

Upvotes: 1

mazurekt
mazurekt

Reputation: 303

You are overriding the save method correctly. You need to do more when you use the createsuperuser command.

from django.utils.text import slugify
from django.contrib.auth.models import UserManager


class CustomUserManager(UserManager):
    def _create_user(self, username, email, password, **extra_fields):
        username_slug = slugify(username)
        extra_fields.setdefault('slug', username_slug)
        super()._create_user(username, email, password, **extra_fields)


class Profile(User):
    user = models.OneToOneField(User, parent_link=True, on_delete=models.CASCADE)
    slug = models.SlugField(unique=True, blank=True)

    def save(self, *args, **kwargs):
        print('self.username')
        print(self.username)
        self.slug = slugify(self.username)
        super().save(*args, **kwargs)

    objects = CustomUserManager()

Upvotes: 0

daragua
daragua

Reputation: 1183

If you're sure you don't want to have your user's profile data in a separate model with a OneToOneField back to Django's default User, then you should probably subclass AbstractUser and not User, as specified in the docs.

https://docs.djangoproject.com/en/2.2/topics/auth/customizing/#substituting-a-custom-user-model

Consider this part :

If you’re entirely happy with Django’s User model and you just want to add some additional profile information, you could simply subclass django.contrib.auth.models.AbstractUser and add your custom profile field [...]

(from https://docs.djangoproject.com/en/2.2/topics/auth/customizing/#extending-django-s-default-user)

Then you'd go like this:

from django.contrib.auth.models import AbstractUser
from django.contrib.auth.models import UserManager
from django.utils.text import slugify
from django.db import models


class User(AbstractUser):
    slug = models.SlugField(unique=True, blank=True)

    objects = UserManager()

    def save(self, *args, **kwargs):
        print('self.username')
        print(self.username)
        self.slug = slugify(self.username)
        super().save(*args, **kwargs)

Then, define settings.AUTH_USER_MODEL,

AUTH_USER_MODEL = "myapp.User"  # also, add 'myapp' to INSTALLED_APPS

Remember: you'll need to reference your User model like this (and this is how you should do it anyway, whether you customized that model or not):

from django.contrib.auth import get_user_model

User = get_user_model()

Upvotes: 2

Related Questions