Подтвердить что ты не робот

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" - это новое настраиваемое поле. Сериализатор не понимает, что он должен заглянуть в модель пользователя.

Что мне здесь не хватает? Как сказать этому сериализатору, что я хочу, чтобы некоторые поля внутри Пользователя? Мне также нужно быть в состоянии создать пользователя.

4b9b3361

Ответ 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