【问题标题】:DjangoRestFramework - How to update fields in modelDjangoRestFramework - 如何更新模型中的字段
【发布时间】:2018-08-23 16:38:54
【问题描述】:

我正在使用 Django 用户模型,并且还使用我自己的配置文件模型扩展了一些其他数据。当我想更新配置文件模型中的用户数据时,它不会更新,因为所有用户 ID、用户名、电子邮件、密码位于用户模型中,而需要更新的字段位于配置文件模型中。我使用过这种方法,它所做的只是接受输入并显示响应,但在整体查看用户数据时不显示任何更改.

models.py

class Profile(models.Model):
    user = models.OneToOneField(User,related_name='profile',on_delete=models.CASCADE)
    location = models.CharField(max_length=30,blank=True)
    friends_count = models.PositiveIntegerField(default=0)
    profile_pic = models.FileField(upload_to='profile_pics/',blank=True,null=True)

    def natural_key(self):
        return (self.user.username,)

views.py

class UserCreateAPIViewSet(viewsets.ModelViewSet,mixins.UpdateModelMixin):
    """"A View which handles  Creating  and Updating User Profile"""
    serializer_class = UserProfileCreateSerializer
    queryset = User.objects.all()

    authentication_classes = (TokenAuthentication,)
    permission_classes = (permissions.UpdateOwnProfile,)

    filter_backends = (filters.SearchFilter,)
    search_fields = ('username','email',)

class UserUpdateAPI(generics.GenericAPIView,mixins.UpdateModelMixin):
    """Update User Profile Data"""
    permission_classes = (permissions.UpdateOwnProfile,)
    authentication_classes = (TokenAuthentication,)
    queryset = Profile.objects.all()
    serializer_class = ProfileUpdateSerializer

    def put(self,request,*args,**kwargs):
        return self.partial_update(request,*args,**kwargs)

urls.py

url(r'^user-update/(?P<pk>\d+)/$',views.UserUpdateAPI.as_view(),name="user-update"),
router = DefaultRouter()
router.register(r'profile',views.UserCreateAPIViewSet)

serializers.py

class UserProfileCreateSerializer(serializers.ModelSerializer):
    """"A serializer for user data request"""
    location = serializers.CharField(source='profile.location')
    friends_count = serializers.IntegerField(source='profile.friends_count',read_only=True)
    profile_pic = serializers.FileField(source='profile.profile_pic',allow_empty_file=True,allow_null=True)


    class Meta:
        model = User
        fields = (
            'pk',
            'username',
            'email',
            'password',
            'location',
            'friends_count',
            'profile_pic',
        )
        extra_kwargs = {
            'password':{'write_only':True},
            'friends_count':{'read_only':True},
        }

    def create(self, validated_data):
        """"Create and return a new User"""


        user = User(
            email = validated_data['email'],
            username = validated_data['username']
        )

        user.set_password(validated_data['password'])

        user.save()

        return user

class ProfileUpdateSerializer(serializers.ModelSerializer):
    """A serializer for updating user data"""
    class Meta:
        model = Profile
        fields = ('location','profile_pic')

【问题讨论】:

  • 您正在更新Profile 模型数据。不是User模型数据
  • 如果您想同时更新它们,请搜索内联表单集
  • 是啊!!!这取决于用户的要求,如果他想更新密码,则必须完成,如果他想编辑他的 profile_pic,则必须更新.....我将使用用户模型的视图更新问题。
  • 我正在使用 android 应用程序的 rest apis 内联表单集对此有何帮助? @亚历克斯
  • UserProfileCreateSerializer 中,您正在保存User 对象,但不保存Profile 对象。

标签: python django django-models django-rest-framework django-views


【解决方案1】:

看起来你想从 AbstractBaseUser 扩展(见下面的代码),使用它作为你的UserProfileCreateSerializer

class UserProfileCreateSerializer(serializers.ModelSerializer):
    """"A serializer for user data request"""
    location = serializers.CharField(source='profile.location')
    friends_count = serializers.IntegerField(source='profile.friends_count',read_only=True)
    profile_pic = serializers.FileField(source='profile.profile_pic',allow_empty_file=True,allow_null=True)


    class Meta:
        model = Profile
        fields = (
            'pk',
            'username',
            'email',
            'password',
            'location',
            'friends_count',
            'profile_pic',
        )
        extra_kwargs = {
            'password':{'write_only':True},
            'friends_count':{'read_only':True},
        }

    def create(self, validated_data):
         """"Create and return a new User"""


        user = Profile(
             email = validated_data['email'],
             username = validated_data['username']
        )

        user.set_password(validated_data['password'])

        user.save()

        return user

class ProfileUpdateSerializer(serializers.ModelSerializer):
    """A serializer for updating user data"""
    class Meta:
        model = Profile
        fields = ('location','profile_pic')

然后从AbstractBaseUser中扩展models.py

from __future__ import unicode_literals

from django.db import models
from django.core.mail import send_mail
from django.contrib.auth.models import PermissionsMixin
from django.contrib.auth.base_user import AbstractBaseUser
from django.utils.translation import ugettext_lazy as _

from .managers import ProfileManager

class Profile(AbstractBaseUser, PermissionsMixin):
    email = models.EmailField(_('email address'), unique=True)
    username = models.CharField(_('first name'), max_length=30, blank=True)
    first_name = models.CharField(_('first name'), max_length=30, blank=True)
    last_name = models.CharField(_('last name'), max_length=30, blank=True)
    date_joined = models.DateTimeField(_('date joined'), auto_now_add=True)
    is_active = models.BooleanField(_('active'), default=True)
    location = models.CharField(max_length=30,blank=True)
    friends_count = models.PositiveIntegerField(default=0)
    profile_pic =  models.FileField(upload_to='profile_pics/',blank=True,null=True)

    objects = UserManager()

    USERNAME_FIELD = 'username'
    REQUIRED_FIELDS = []

    class Meta:
        verbose_name = _('user')
        verbose_name_plural = _('users')

    def get_full_name(self):
        '''
        Returns the first_name plus the last_name, with a space in between.
        '''
        full_name = '%s %s' % (self.first_name, self.last_name)
        return full_name.strip()

    def get_short_name(self):
        '''
        Returns the short name for the user.
        '''
        return self.first_name

    def natural_key(self):
        return (self.username,)

    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)

然后在models.py所在的目录下创建一个名为managers.py的文件:

from django.contrib.auth.base_user import BaseUserManager

class ProfileManager(BaseUserManager):
    use_in_migrations = True

    def _create_user(self, email, password, **extra_fields):
        """
        Creates and saves a User with the given email and password.
        """
        if not email:
            raise ValueError('The given email must be set')
        email = self.normalize_email(email)
        user = self.model(email=email, **extra_fields)
        user.set_password(password)
        user.save(using=self._db)
        return user

    def create_user(self, email, password=None, **extra_fields):
        extra_fields.setdefault('is_superuser', False)
        return self._create_user(email, password, **extra_fields)

    def create_superuser(self, email, password, **extra_fields):
        extra_fields.setdefault('is_superuser', True)

        if extra_fields.get('is_superuser') is not True:
            raise ValueError('Superuser must have is_superuser=True.')

        return self._create_user(email, password, **extra_fields)

要完成所有这些,您需要将其添加到您的 settings.py 文件中:

AUTH_USER_MODEL = 'app.Profile'

并且不要忘记在使用$ python manage.py runserver之前重新运行所有数据库迁移。

【讨论】:

  • 你不能在 Profile 实例上调用 set_password 方法。
  • 请查看Profile 型号。这并不能解决任何问题,但会引发更多错误。
  • @SachinKukreja 是的 - 你说得对 - 我要为自定义用户 Model 修改这个。
  • 这对我来说很好用!!!我需要改变什么,为什么?谁能给我解释清楚。
  • @DilipKrishna Hi Dilip - 它允许您从所有 AbstractBase 用户字段进行扩展,让您可以访问 Profile.usernameProfile.password
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-07-27
  • 1970-01-01
  • 2020-09-18
相关资源
最近更新 更多