django中使用Profile擴展User模塊(基於django 1.10版本下)


版本:Django 1.10.1(其他版本可能有不同的實現好解決辦法)

參考官方文檔:https://docs.djangoproject.com/en/1.10/topics/auth/customizing/

在開發過程中,Django的用戶管理模塊能夠給我們帶來非常大的便利,但是Django的User模塊所提供的字段太少,所以對User模塊的擴展是必須的,下面結合我自己的開發過程中,使用Profile擴展User模塊時遇到的問題以及解決的方法進行記錄。

先看一段我根據官方文檔最先開發完成的代碼:

admin.py

from django.contrib import admin
from django.contrib.auth.models import User
from django.contrib.auth.admin import UserAdmin as BaseUserAdmin

from models import *

class AccountInline(admin.StackedInline):
    model = Account
    can_delete = False
    verbose_name_plural = 'account'
    

class UserAdmin(BaseUserAdmin):
    inlines = (AccountInline, )


admin.site.unregister(User)
admin.site.register(User, UserAdmin)

model.py:

from __future__ import unicode_literals

from mysite import settings
from django.db import models
from django.contrib.auth.models import User
from django.db.models.signals import post_save


class Account(models.Model):
    """
    Registered users
    """
    SEX_CHOICES = {
        1: 'boy',
        2: 'girl',
    }
    
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    sex = models.SmallIntegerField(default=1, choices=SEX_CHOICES.items())
    birth = models.DateField(blank=True, null=True)
    age = models.SmallIntegerField(blank=True,null=True)
    contact_number = models.CharField(max_length=128, blank=True, null=True)
    personalized_signature = models.CharField(max_length=128, blank=True, null=True)
    picture = models.ImageField(upload_to="Image/", blank=True,null=True)
    openid = models.CharField(max_length=128, blank=True, null=True)
        
    def __unicode__(self):
        return self.user.username
    
    class Meta:
        db_table = 'Account'

def create_user_profile(sender, instance, created, **kwargs):
    if created:
        profile = Account()
        profile.user = instance
        profile.save()
        
post_save.connect(create_user_profile, sender=User)

settings.py:

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'rest_framework',
    'Blog'
]
AUTH_PROFILE_MODULE = 'Blog.Account'

這段是官方文檔給出的參考方法:可以很好的讓你自己的model跟User模塊進行一對一的外鍵映射。

我們可以通過admin頁面進行用戶的創建,可以看到我們的Account模型很好的嵌入了User模塊,然后可以對User模塊進行字段的擴張。

但是此時,當你保存的時候,出現了問題,請看截圖:

這個問題告訴我(僅僅是我的理解,如果有錯誤希望留言提出),當django創建完User表中的用戶時,通過Userprofile去創建第二個實例(Account)的時候,執行save操作的時候,執行了倆次,從而導致上面的user_id已經存在無法完成操作,這個原因在於:上面model中調用post_save發生了倆次(django自己的save一次,然后通過信號post_save一次,導致第二個調用save的時候發現已經存在了相同的主鍵ID)

所以我們需要做的就是對model.py文件中的save進行重寫,重寫之后的model.py文件為:

class Account(models.Model):
    """
    Registered users
    """
    SEX_CHOICES = {
        1: 'boy',
        2: 'girl',
    }
    
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    sex = models.SmallIntegerField(default=1, choices=SEX_CHOICES.items())
    birth = models.DateField(blank=True, null=True)
    age = models.SmallIntegerField(blank=True,null=True)
    contact_number = models.CharField(max_length=128, blank=True, null=True)
    personalized_signature = models.CharField(max_length=128, blank=True, null=True)
    picture = models.ImageField(upload_to="Image/", blank=True,null=True)
    openid = models.CharField(max_length=128, blank=True, null=True)
        
    def __unicode__(self):
        return self.user.username
    
    class Meta:
        db_table = 'Account'

    def save(self, *args, **kwargs):
        if not self.pk:
            try:
                p = Account.objects.get(user=self.user)
                self.pk = p.pk
            except Account.DoesNotExist:
                pass

        super(Account, self).save(*args, **kwargs)


def create_user_profile(sender, instance, created, **kwargs):
    if created:
        profile = Account()
        profile.user = instance
        profile.save()
        
post_save.connect(create_user_profile, sender=User)

這樣就會在save創建的時候,對主鍵pk進行檢測然后保存。

因為我在開發的時候用到了django-rest-framework,所以含有serializer序列化文件,在這里一並給出:

serializers.py:

class UserSerializer(serializers.ModelSerializer):
    class Meta:
        model = User
        fields = ("id", "username", "password", "email", "last_login", "date_joined")


class AccountSerializer(serializers.ModelSerializer):
    class Meta:
        model = Account
        fields = ("user_id", "user", "sex", "age", "birth", "picture", "contact_number", "personalized_signature", "openid")

  

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM