[英]Django REST Framework - Issues with extending the user model using signals
我是Django的新手,并且想使用OneToOne字段扩展用户模型(似乎最推荐使用它),我也有一个ManyToManyField是强制性的。 以下是我的models.py:
from django.db import models
from django.contrib.auth.models import User
from django.contrib.postgres.fields import ArrayField
from django.db.models.signals import post_save
from django.dispatch import receiver
class Config_Table(models.Model):
entity_name = models.TextField(primary_key=True)
category = models.TextField()
description = models.TextField(blank=True,default='')
class Profile(models.Model):
"The Profile of a user with details are stored in this model."
user = models.OneToOneField(User, on_delete=models.CASCADE, max_length=11)
# The default username is phone number (Ver. 1.0)
phone_number = models.TextField(max_length=11,default=user)
avatar = models.ImageField(default='../Static/1.jpeg')
GENDER_CHOICES = (
('M','Male'),
('F','Female'),
)
gender = models.CharField(max_length=1,choices=GENDER_CHOICES)
city = models.TextField(max_length=25)
description = models.TextField(max_length=2000, blank=True, default='')
interests = models.ManyToManyField(Config_Table)
date_of_birth = models.DateField(auto_now_add=True)
USER_TYPES = (
('User','Normal User'),
('Leader','Tour Leader'),
('Admin','Administrator'),
)
user_type = models.TextField(choices=USER_TYPES, default='User')
join_date = models.DateTimeField(auto_now_add=True)
official_docs = models.ImageField(default='../Static/1.jpeg')
group_name = models.TextField(blank=True,default='')
debit_card_number = models.IntegerField(blank=True, default=0)
MUSIC_CHOICES = (
('Rock','Rock Music'),
('Trad','Traditional Music'),
('Elec','Electronic Music'),
('Clas','Classical Music')
)
favorite_music = ArrayField(models.TextField(null=True,default=''),size=2)
使用shell,我可以成功创建用户并分配如下配置文件。 表“ Config_table”已填充一些初始数据:
>>> user = User.objects.create_user(username='12345678900')
>>> test = Profile.objects.create(user=user,gender='M',city='NY',user_type='User',favorite_music=['Trad'])
>>> test.save
<bound method Model.save of <Profile: <django.db.models.query_utils.DeferredAttribute object at 0x7f9f98e8a080>>>
>>> test.interests.add('Ski')
>>> test.save
<bound method Model.save of <Profile: <django.db.models.query_utils.DeferredAttribute object at 0x7f9f98e8a080>>>
现在,我想使视图更容易些。 因此,我在这里和这里所找到的东西我想使用post_save信号创建一个create_user方法,该方法用一行完成上述所有操作:
@receiver(post_save, sender=User)
def create_user_profile(sender, instance, created, **kwargs):
if created:
Profile.objects.create(user=instance,gender=instance.gender,city=instance.city,user_type=instance.user_type,
favorite_music=instance.favorite_music)
Profile.interests.add(instance.interests)
@receiver(post_save, sender=User)
def save_user_profile(sender, instance, **kwargs):
instance.profile.save()
但是当我尝试如下操作时。 我收到错误消息:
user = User.objects.create_user(username='12345678900',gender='M',city='NY',interests='Ski',user_type='User',favorite_music=['Trad'])
Traceback (most recent call last):
File "<console>", line 1, in <module>
File "/home/amir/.virtualenvs/Django/lib/python3.6/site-packages/django/contrib/auth/models.py", line 150, in create_user
return self._create_user(username, email, password, **extra_fields)
File "/home/amir/.virtualenvs/Django/lib/python3.6/site-packages/django/contrib/auth/models.py", line 142, in _create_user
user = self.model(username=username, email=email, **extra_fields)
File "/home/amir/.virtualenvs/Django/lib/python3.6/site-packages/django/db/models/base.py", line 495, in __init__
raise TypeError("'%s' is an invalid keyword argument for this function" % kwarg)
TypeError: 'gender' is an invalid keyword argument for this function
似乎我缺少了非常明显或非常愚蠢的东西。 有人可以帮忙吗? 我在Ubuntu 16.04 LTS上将Django 2.0.2与Postgres 10.1和Python 3.7一起使用。
编辑:我想做以上的原因是要使用户的主键和配置文件的主键相同,而不是像下面。 以下是我从第一个答案中得到的样本(请检查“ id”和“ user”字段):
>>> serial = ProfileSerializer(sample_profile,many=True)
>>> serial.data
[OrderedDict([('id', 13), ('first_name', ''), ('last_name', ''), ('phone_number', 'App.Profile.user'), ('avatar', '../Static/1.jpeg'), ('gender', 'M'), ('city', 'NY'), ('description', ''), ('date_of_birth', '2018-03-04'), ('user_type', 'User'), ('join_date', '2018-03-04T07:12:38.607959Z'), ('official_docs', '../Static/1.jpeg'), ('group_name', ''), ('debit_card_number', 0), ('favorite_music', ['Trad']), ('user', 18), ('interests', ['Ski'])])]
您的问题源于名为create_user_profile
的post_save
信号不正确的事实。 instance
变量是django.contrib.auth.models.User
实例。 它是具有gender
属性的Profile
模型,而不是django.contrib.auth.models.User
实例。 您基本上想做的是以下几点:
from django.contrib.auth.models import User
user = User.objects.get(pk=1)
print(user.gender) # Does not exist
您已经通过在User
模型下面创建一个profile
来扩展了User
模型,但是您试图将User
模型视为Profile
模型,而不是。
就个人而言,在我看来,最好通过扩展Django的AbstractUser
来创建自己的自定义用户模型。 当您拥有各种不同类型的个人资料(例如Facebook,Google,Employee等)时,个人资料非常有用,这些个人资料具有不同的属性。 我所看到的大多数内容应该足以在定制用户模型上使用:
from django.contrib.auth.models import AbstractUser
class User(AbstractUser):
USER = 0
LEADER = 1
ADMIN = 2
USER_TYPE_CHOICES = (
(USER, 'Normal User'),
(LEADER, 'Tour Leader'),
(ADMIN, 'Administrator'),
)
user_type = models.IntegerField(choices=USER_TYPE_CHOICES, default=User.USER)
# Your custom stuff here
我建议在开始编写用户模型之前先考虑一下数据库设计。 它将为您节省很多麻烦。
[主题]:另外,值得一提的是,我在您上面的示例模型中看到了一个主要问题。 看来您打算将借记卡号存储在数据库中。 您的应用程序/组织必须遵循PCI DSS(付款应用程序数据安全标准) 。 您不想掉以轻心 。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.