3

I'm trying to first access the users table via the user foreign key present in userinformations models and later override the RetriveUpdateDestroy API view's destroy method to change the status of the user to inactive instead of deleting them. I can't seem to access the is-active field of the in built User database.

views.py

class UserUpdateApiView(RetrieveUpdateDestroyAPIView):
queryset = UserInformation.objects.all()
serializer_class = UserInformationUpdateSerializer
lookup_field = 'pk'
lookup_url_kwarg = 'id'

def destroy(self, request, *args, **kwargs):
    try:
        user = User.objects.get(pk=self.kwargs["id"])
        deleteStatusVal = False
        user.is_active = deleteStatusVal
        user.save()
        return Response(UserSerializer(user).data)
    except:
        return Response("Nope")

serializers.py

class UserSerializer(ModelSerializer):
password = serializers.CharField(style={'input_type': 'password'}, write_only=True)
email = serializers.EmailField(validators=[required])

class Meta:
    model = User
    fields = ['username', 'email', 'password', 'is_active']
    extra_kwargs = {'password': {'write_only': True},
                    'is_active': {'read_only': True}}

def validate(self, data):
    email = data.get('email', None)
    user = User.objects.filter(email=email).distinct()
    if user.exists():
        raise ValidationError("That email is already registered!")
    return data


class UserInformationUpdateSerializer(ModelSerializer):
user = UserSerializer(read_only=True)
class Meta:
    model = UserInformation
    fields = ['user', 'first_name', 'middle_name', 'last_name', 'phone', 'date_of_birth']

models.py

class UserInformation(BaseModel):
user = models.OneToOneField(User, related_name='user_id')
first_name = models.CharField(max_length=45)
middle_name = models.CharField(max_length=45, null=True)
last_name = models.CharField(max_length=45)
vendor = models.BooleanField(default=False)
phone = models.CharField(max_length=100, validators=[
RegexValidator(regex=r'^\+?8801?\d{9}$', message="Phone number must be entered in the format: '+8801*********'")
], blank=False, unique=True)
date_of_birth = models.DateField()
confirmation_token = models.CharField(max_length=45, null=True)
confirmation_exp = models.DateTimeField(null=True)
pw_reminder_token = models.CharField(max_length=45, null=True)
pw_reminder_exp = models.DateTimeField(null=True)
profile_pic = models.ImageField(blank=True, null=True, upload_to='profile_images/', default='Images/none/no_images.jpg')
cover_photo = models.ImageField(blank=True, null=True, upload_to='cover_images/', default='Images/none/no_images.jpg')
thumbnail_pic = models.ImageField(blank=True, null=True, upload_to='thumbnail_images/', default='Images/none/no_images.jpg')
phone_verified = models.BooleanField(default=False)
email_verified = models.BooleanField(default=False)
reward_points = models.IntegerField(null=False)
ref_code = models.CharField(null=True, max_length=10)

def __str__(self):
    return self.user.username

def delete(self, *args, **kwargs):
    self.user.delete()
    super(UserInformation, self).delete(*args, **kwargs)
Ryad Moyashir
  • 35
  • 1
  • 6

2 Answers2

3

If you want to make User as in active while keeping the UserInformation object and Userobject un-deleted in database, you can do something like this:

def destroy(self, request, *args, **kwargs):
    user = self.get_object().user
    user.is_active = False
    user.save()
    return Response(UserInformationUpdateSerializer(self.get_object()).data)
v1k45
  • 8,070
  • 2
  • 30
  • 38
  • tried this got the following error! Got AttributeError when attempting to get a value for field `username` on serializer `UserSerializer`. The serializer field might be named incorrectly and not match any attribute or key on the `UserInformation` instance. Original exception text was: 'UserInformation' object has no attribute 'username'. – Ryad Moyashir Mar 30 '17 at 12:55
  • replace the `UserSerializer` with `UserInformationUpdateSerializer`. see updated answer – v1k45 Mar 30 '17 at 13:01
  • Never mind, UserSerializer works. Could you explain to me how "self.get_object().user" works – Ryad Moyashir Apr 01 '17 at 06:53
  • DRF's view are just like Django's Generic views, it has `get_object` method which extracts the current object depending on the url and view queryset. In your case, it extracted the `UserInformation` object for the url and then used the object's `user` FK to work on the user object and de-activate it. – v1k45 Apr 01 '17 at 07:47
  • So in that case I can use this same method to access the other fields of UserInformation as well? – Ryad Moyashir Apr 01 '17 at 07:59
  • yes, you can. the same method is used to pass the object data to the serializer. – v1k45 Apr 01 '17 at 10:12
  • I'm also trying to take multiple images in a single serializer field. I'm using listfields according to the django REST documentation, but it's not working the way want it to. Any ideas as to how I can go about doing that? – Ryad Moyashir Apr 01 '17 at 10:25
  • images cannot be sent using in json object (unless you are sending a base64 string, of course). You have to send the data in multipart/form-data format to be able to upload images. Or you can simply create a separate endpoint just for uploading images. – v1k45 Apr 01 '17 at 10:28
  • Is there a stackoverflow thread that addresses this issue. I have been looking but ending up dry. – Ryad Moyashir Apr 01 '17 at 10:53
0

You have 'is_active': {'read_only': True}}.

Also,

# this seems redundant
def delete(self, *args, **kwargs):
    self.user.delete()
    super(UserInformation, self).delete(*args, **kwargs)
Özer
  • 2,059
  • 18
  • 22
  • but how do I hide that is_active field during registration? – Ryad Moyashir Mar 30 '17 at 12:34
  • Take out the try - except, so you can see what the actual error ist. It might be, that you need to use UserInformation.objects.get(id=self.kwargs["id"]).user, but with a try - except you wouldn't see the error. – Özer Mar 31 '17 at 08:30