2017-11-11 216 views
2

我正在嘗試解決如何擴展Django用戶模型以向用戶添加信息。我似乎無法得到它的工作。我究竟做錯了什麼? 可以在我正在擴展到的同一模型中使用外鍵嗎?你如何創建一個超級用戶,還是你必須通過python manage.py shell手動完成?擴展Django 1.11用戶模型

這裏是我到目前爲止的代碼:

class PersonModel(models.Model): 
    user = models.OneToOneField(User, on_delete=models.CASCADE) 
    firstName = models.CharField(max_length=50) 
    lastName = models.CharField(max_length=50) 
    company = models.ForeignKey(CompanyModel, on_delete=models.CASCADE, null=True) 
    phone = models.ForeignKey(PhoneModel, on_delete=models.CASCADE, null=True) 
    email = models.EmailField(blank=True) 

    def __str__(self): 
     return '%s %s - %s - %s, %s' % (self.firstName, self.lastName, 
             self.company, self.phone, self.email 
             ) 

    class Meta: 
     ordering = ['firstName'] 
     verbose_name = "Customer Contact Information" 
     #verbose_name_plural = "Contacts" 

@receiver(post_save, sender=User) 
def create_user_profile(sender, instance, created, **kwargs): 
    if created: 
     PersonModel.objects.create(user=instance) 

@receiver(post_save, sender=User) 
def save_user_profile(sender, instance, **kwargs): 
    instance.profile.save() 

UPDATE(決賽): 隨着raratiru的幫助下,我已經能夠得到大部分他同去的腳本。由於我的外鍵要求,我仍然很難創建一個超級用戶。

from django.contrib.auth.models import (
    AbstractBaseUser, 
    PermissionsMixin, 
    BaseUserManager, 
) 
from django.core.mail import send_mail 
from django.db import models 
from django.utils.translation import ugettext_lazy as _ 
from customers import models as customers_models 

class TravelModel(models.Model): 
    mileageRate = models.DecimalField(max_digits=4, decimal_places=3) 

    def __str__(self): 
     return '%s' % (self.mileageRate) 

    class Meta: 
     verbose_name = "Current Federal Milage Rate" 
     #verbose_name_plural = "Milage" 


class UserManager(BaseUserManager): 
    def create_user(self, email, firstName, lastName, company, phone, password=None, **kwargs): 
     email = self.normalize_email(email) 
     user = self.model(email=email, **kwargs) 
     user.firstName = firstName 
     user.lastName = lastName 
     user.company = company 
     user.phone = phone 
     user.set_password(password) 
     user.save(using=self._db) 
     return user 

    def create_superuser(self, email, firstName, lastName, password=None, **kwargs): 
     #user = self.create_user(**kwargs) 
     email = self.normalize_email(email) 
     user = self.model(email=email, **kwargs) 
     user.firstName = firstName 
     user.lastName = lastName 
     user.set_password(password) 
     user.is_superuser = True 
     user.is_staff = True 
     user.save(using=self._db) 
     return user 


class AliasField(models.Field): 
    def contribute_to_class(self, cls, name, virtual_only=False): 
     super().contribute_to_class(cls, name, virtual_only=True) 
     setattr(cls, name, self) 

    def __get__(self, instance, instance_type=None): 
     return getattr(instance, self.db_column) 


class MyUser(AbstractBaseUser, PermissionsMixin): 
     firstName = models.CharField(max_length=50, blank=False, null=False) 
     lastName = models.CharField(max_length=50, blank=False, null=False) 
     company = models.ForeignKey(customers_models.CompanyModel, on_delete=models.PROTECT, null=False) 
     phone = models.ForeignKey(customers_models.PhoneModel, on_delete=models.PROTECT, null=False) 

     email = models.EmailField(_('email address'), max_length=255, unique=True) 

     is_staff = models.BooleanField(
      _('staff status'), 
      default=False, 
      help_text=_(
        'Designates whether the user can log into this admin ' 
        'site.' 
      ) 
    ) 
     is_active = models.BooleanField(
      _('active'), 
      default=True, 
      help_text=_(
        'Designates whether this user should be treated as ' 
        'active. Unselect this instead of deleting accounts.' 
      ) 
    ) 
     username = AliasField(db_column='email') 

     objects = UserManager() 

     USERNAME_FIELD = 'email' 
     REQUIRED_FIELDS = ['firstName','lastName',] 

     class Meta(object): 
      ordering = ['firstName'] 
      verbose_name = _('Contact') 
      verbose_name_plural = _('Contacts') 

     def __str__(self): 
      return '%s - %s %s - %s - %s' % (self.company, self.firstName, self.lastName, self.email, self.phone) 

     def get_full_name(self): 
      return self.email 

     def get_short_name(self): 
      return self.email 

     def email_user(self, subject, message, from_email=None, **kwargs): 
      """ 
      Sends an email to this User. 
      """ 
      send_mail(subject, message, from_email, [self.email], **kwargs) 

規避外鍵的鬥爭中,最簡單的方法是創建超級用戶之前刪除空=假需求 - 公司和電話後分配 - 並設置空回假之後。

回答

1

這就是我擴展我的用戶模型的方法。以下代碼也將用戶名替換爲電子郵件字段。我發佈它是因爲它引起了核心變化,因此它清楚了背後的邏輯。

基本想法可以在this post找到並解釋。一個非常好的帖子也可以找到here

在這種情況下,AliasField會將字段username作爲email的別名。儘管django已經記錄了proper way找到用戶模型及其相關字段,但這並不是必需的。

from django.contrib.auth.models import (
    AbstractBaseUser, 
    PermissionsMixin, 
    BaseUserManager, 
) 
from django.core.mail import send_mail 
from django.db import models 
from django.utils.translation import ugettext_lazy as _ 


class UserManager(BaseUserManager): 
    def create_user(self, email, password=None, **kwargs): 
     email = self.normalize_email(email) 
     user = self.model(email=email, **kwargs) 
     user.set_password(password) 
     user.save(using=self._db) 
     return user 

    def create_superuser(self, **kwargs): 
     user = self.create_user(**kwargs) 
     user.is_superuser = True 
     user.is_staff = True 
     user.save(using=self._db) 
     return user 


class AliasField(models.Field): 
    def contribute_to_class(self, cls, name, private_only=False): 
     super().contribute_to_class(cls, name, private_only=True) 
     setattr(cls, name, self) 

    def __get__(self, instance, instance_type=None): 
     return getattr(instance, self.db_column) 


class MyUser(AbstractBaseUser, PermissionsMixin): 
    custom_field = models.ForeignKey(
     'app.Model', 
     on_delete=models.PROTECT, 
    ) 

    email = models.EmailField(_('email address'), max_length=255, unique=True) 

    is_staff = models.BooleanField(
     _('staff status'), 
     default=False, 
     help_text=_(
      'Designates whether the user can log into this admin ' 
      'site.' 
     ) 
    ) 
    is_active = models.BooleanField(
     _('active'), 
     default=True, 
     help_text=_(
      'Designates whether this user should be treated as ' 
      'active. Unselect this instead of deleting accounts.' 
     ) 
    ) 
    username = AliasField(db_column='email') 

    objects = UserManager() 

    USERNAME_FIELD = 'email' 
    REQUIRED_FIELDS = ['user_branch_key', ] 

    class Meta(object): 
     ordering = ['email'] 
     verbose_name = _('My User') 
     verbose_name_plural = _('My User') 

    def __str__(self): 
     return 'id: {0} - {1}, {2}'.format(self.id, self.email, self.user_branch_key) 

    def get_full_name(self): 
     return self.email 

    def get_short_name(self): 
     return self.email 

    def email_user(self, subject, message, from_email=None, **kwargs): 
     """ 
     Sends an email to this User. 
     """ 
     send_mail(subject, message, from_email, [self.email], **kwargs) 

一旦將文件./the_user/models.py在名爲the_user延長您的用戶模型,例如應用程序中,你必須做出的settings.py文件中的一些變化:

  • 註冊在INSTALLED_APPS應用
  • ./manage.py makemigrations & & ./manage.py migrate
  • 設置AUTH_USER_MODEL = 'the_user.MyUserthe docs

這樣描述的,在另一個模型,你可以添加一個外鍵如下:

from the_user.models import MyUser 
from django.conf import settings 
from django.db import models 

class AModel(models.Model) 
    user = models.ForeignKey(
     settings.AUTH_USER_MODEL, 
     on_delete=models.PROTECT, 
     related_name='%(app_label)s_%(class)s_user' 
    ) 
+0

好像而不是擴展,你重寫Django的用戶模型。這是一個比這個問題上的Django文檔更詳細的地獄:( – Jaberwocky

+0

@Jaberwocky的確。我正在尋找代碼來進行核心更改(使用電子郵件而不是用戶名),上面說明了用戶模型背後的邏輯 – raratiru

+0

我很感謝你的貢獻,我覺得這個問題不能完全回答我的問題,如果是的話,你會如何配合外鍵關係給用戶? 更精細的是,如果我想存儲什麼我在'PersonModel'中,如何使用你的方法完成這項工作? – Jaberwocky