Django REST Framework Создание пользовательского пользователя
Я новичок в области Django, но вижу, что там много "волшебства". Я использую Django REST Framework и создаю приложение, которое позволит бесплатную регистрацию пользователя. Моему пользователю нужны дополнительные поля, недоступные пользователю Django. Таким образом, я googled для расширения пользователя. Существует идея, что это нужно сделать, создав что-то вроде этого
class MyUser(models.Model):
user = models.ForeignKey(User, unique=True)
city = models.CharField(max_length=50, blank=True, default='')
Это нормально, но у меня есть этот сериализатор
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = MyUser
fields = ('id', 'username', 'password', 'first_name', 'last_name', 'email', 'city')
Таким образом, проблема в том, что этот сериализатор выполняет некоторую "магию" здесь. Он пытается выяснить, какое поле должно иметь модель...
Я хочу иметь пользователя с полями, указанными здесь, и это поля в User, а "city" - это новое настраиваемое поле. Сериализатор не понимает, что он должен заглянуть в модель пользователя.
Что мне здесь не хватает? Как сказать этому сериализатору, что я хочу, чтобы некоторые поля внутри Пользователя? Мне также нужно быть в состоянии создать пользователя.
Ответы
Ответ 1
Поэтому, видимо, у меня недостаточно репутации, чтобы опубликовать комментарий в ответ. Но чтобы уточнить, что Кевин Стоун описал, если вы моделируете что-то вроде следующего:
class AppUser(models.Model):
user = models.OneToOneField(User)
ban_status = models.BooleanField(default=False)
Вы можете сделать что-то подобное, чтобы создать пользовательский пользователь и пользователь django:
class AppUserSerializer(serializers.ModelSerializer):
username = serializers.CharField(source='user.username')
email = serializers.CharField(source='user.email')
password = serializers.CharField(source='user.password')
ban_status = serializers.Field(source='ban_status')
class Meta:
model = AppUser
fields = ('id', 'username', 'email', 'password', 'ban_status')
def restore_object(self, attrs, instance=None):
"""
Given a dictionary of deserialized field values, either update
an existing model instance, or create a new model instance.
"""
if instance is not None:
instance.user.email = attrs.get('user.email', instance.user.email)
instance.ban_status = attrs.get('ban_status', instance.ban_status)
instance.user.password = attrs.get('user.password', instance.user.password)
return instance
user = User.objects.create_user(username=attrs.get('user.username'), email= attrs.get('user.email'), password=attrs.get('user.password'))
return AppUser(user=user)
Ответ 2
Хорошо, пару вещей. Вы хотите создать OneToOneField
для расширения вашей модели пользователя.
class MyUser(models.Model):
user = models.OneToOneField(User)
city = models.CharField(max_length=50, blank=True, default='')
Теперь, сила Django Rest Framework, вы можете построить свой сериализатор, чтобы взять данные из обеих этих моделей при сериализации.
class UserSerializer(serializers.ModelSerializer):
city = serializers.CharField(source='myuser.city')
class Meta:
model = User
fields = ('id', 'username', 'password', 'first_name', 'last_name', 'email', 'city')
Наконец, мы создаем пользователя, так как вы используете настраиваемые поля, вам нужно реализовать свой собственный restore_object()
, который создает обе модели из входных данных.
Кроме того, создание пользователей в Django немного отличается, вам нужно вызвать create_user()
и предоставить пароль, который хэшируется, поэтому его не так просто, как хранить поля из сериализатора.
Ответ 3
Если вы используете django 1.5 или более, используйте пользовательскую модель пользователя, таким образом, модель пользователя будет иметь свою собственную выделенную таблицу и сериализатор затем правильно подбирают поля.
Ответ 4
При использовании Django Rest Framework вы должны быть осторожны. Любая пользовательская модель не может использовать встроенную аутентификацию по токенам. Пока вы не сможете это сделать, я бы предложил использовать OneToOneField с пользователем в вашей пользовательской модели. Ваша пользовательская модель будет содержать дополнительные поля, которые вы хотите сохранить. Один к одному дает вам доступ к пользователю от пользовательского пользователя и пользовательского пользователя от пользователя.
Ответ 5
Я предпочитаю использовать модуль django signals, который посылает сигналы в приложение, когда что-то происходит, и, среди прочего, позволит вы вызываете функцию самостоятельно до/после других функций. Мой ответ аналогичен ответу Стюарта, но сохраняет все коды, относящиеся к вашему новому классу расширения, в одном месте (если вы хотите удалить профиль позже или изменить его имя, вам больше не нужно искать нигде).
В следующем коде представлена модель расширенного класса, в этом случае профиль пользователя, а затем создается пустой экземпляр при создании пользовательской модели, а затем сохраняется экземпляр с новой информацией (которую вы должны добавить сами), сохраняя родительский пользовательский экземпляр ie - user.save()
models.py
from django.db.models.signals import post_save
from django.db import models
from django.contrib.auth.models import User
class Profile(models.Model): #This extends the user class to add profile information
user = models.OneToOneField(User, on_delete=models.CASCADE)
#add your extra traits here: is_nice, is_shwifty, address, etc.
is_nice = models.BooleanField(default=True, blank=True)
# a user model was just created! This now creates your extended user (a profile):
@receiver(post_save, sender=User)
def create_user_profile(sender, instance, created, **kwargs):
if created:
# instance is the user model being saved.
Profile.objects.create(user=instance)
# a user model was just saved! This now saves your extended user (a profile):
@receiver(post_save, sender=User)
def save_user_profile(sender, instance, **kwargs):
instance.profile.save()
Если у вас нет ProfileSerializer: serializers.py
#use hyperlinkedmodelserializer for easy api browsing + clicking
class ProfileSerializer(serializers.HyperlinkedModelSerializer):
user = UserSerializer()
class Meta:
model = Profile
fields = ('url', 'user', 'is_nice')
После создания пользователя и сохранения пользователя у вас будет пустой файл user.profile для добавления информации. Например, после запуска python manage.py shell
попробуйте:
from backend.models import User, Profile
#create your user
user=User(username="GravyBoat")
user.save()
#now update your user profile
user.profile.is_nice=False
#that one mean gravy boat
user.save()
user.profile.is_nice
#False
Ответ 6
Было бы хорошо, если бы этот вариант использования был легче найти в документах. Как отметил @jamod, в DRF 3 вы можете найти здесь:
class UserSerializer(serializers.ModelSerializer):
profile = ProfileSerializer()
class Meta:
model = User
fields = ('username', 'email', 'profile')
def create(self, validated_data):
profile_data = validated_data.pop('profile')
user = User.objects.create(**validated_data)
Profile.objects.create(user=user, **profile_data)
return user