简体   繁体   中英

DjangoRestFramework - How to update fields in model

I am using Django user model and also extended with my own profile model for some other data.When i want to update user data which is in Profile Model It doesn't get updated because all the user id,username,email,password reside in user model while the fields which are needed to get updated are in profile model.I have used this approach, all it does is takes inputs and displays the response but does not show any change in User Data when viewing it as a whole.

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')

Looks like you want to extend from the AbstractBaseUser (see code below), using this as your 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')

Then extend from the AbstractBaseUser in 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)

And then create a file called managers.py in the same directory as models.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)

To wrap all this up you need to add this to your settings.py file:

AUTH_USER_MODEL = 'app.Profile'

And also don't forget to re-run all database migrations before using $ python manage.py runserver .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM