Django rest framework auto-populate filed with user.id/username - python

I'm trying to link 'owner' field of my model to an AbstractUser. I need it to be done automatically, the only think i'm able to do by myself is to allow user logged in to choice between every existing user with, what's not what i want. I would like to not have a field to manipulate, but a outcome serializer with id or username of User that added the model. I'm trying to find solutions for a few days, I've tried already combine ForeignKey, PrimaryKeys, OneToOneField, HiddenField, get_user, perform_create, but I'm for sure doing something wrong, and i'm almost lost with it. The last thing i tried is to def_perform in views like DRF QuickStart tutorial say, but without results.
I add some code sample to be more understandable:
There is my AbstractUser model:
from django.db import models
from django.contrib.auth.models import AbstractUser
class UserProfile(AbstractUser):
username = models.CharField(max_length=20, unique=True)
...
i added it to AUTH_USER_MODEL = in the settings.
And there is other model which i want to link with User:
from django.db import models
from users.models.user import UserProfile
class MyPhoto(models.Model):
owner = models.ForeignKey(UserProfile, related_name='photos', on_delete=models.CASCADE, null=True)
image = models.ImageField(upload_to='Images')
serializer.py
class MyPhotoSerializer(serializers.ModelSerializer):
owner = serializers.ReadOnlyField(source='owner.username')
class Meta:
model = MyPhoto
fields = ('pk', 'image', 'owner')
def create(self, validated_data):
photo = MyPhoto.objects.create(
image=validated_data['image']
)
photo.save()
return photo
views.py
class UpdateMyPhotoViewSet(viewsets.ModelViewSet):
queryset = MyPhoto.objects.all()
serializer_class = MyPhotoSerializer
permission_classes = (IsAuthenticated,)
def perform_create(self, serializer):
serializer.save(created_by=self.request.user)
and for now i can't see the owner field results.
Thanks in advance.

Related

Edit multiple Models using one form or view in Django

I am using the default User model in Django and a OneToOneField in a Profile model where extra info such as user bio is stored.
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
bio = models.TextField(max_length=500, blank=True)
I am able to create basic forms for the two models independently
from django.contrib.auth.models import User
class UserForm(ModelForm):
class Meta:
model = User
fields = ['username', 'email']
class ProfileForm(ModelForm):
class Meta:
model = Profile
fields = ['bio']
What is the best method to create a page where a user can edit fields of either model?
So a User can edit Username,Email or Bio on the same page?
You can put the 2 forms in one template and Django will manage filling forms with the right fields (only exception is the same field name in 2 forms)
def view(request):
if request.method == "GET":
context["userform"]=UserForm()
context["profileform"] =ProfileForm()
else:
userform = UserForm(request.POST)
profileform=ProfileForm(request.POST)

How to get value of model method in Django Rest Framework?

So basically I have a django model that has a ManyToManyField of friends and two methods that run on it. Here are my files:
Models.py:
from django.db import models
from django.contrib.auth.models import User
class Profile(models.Model):
first_name = models.CharField(max_length=50, blank=True)
last_name = models.CharField(max_length=50, blank=True)
user = models.OneToOneField(User, on_delete=models.CASCADE)
friends = models.ManyToManyField(User, blank=True, related_name='friends')
def friends_list(self):
return self.friends.all()
def number_of_friends(self):
return self.friends.all().count()
Serialzers.py:
from rest_framework import serializers
from .models import Profile
class ProfileSerializer(serializers.ModelSerializer):
class Meta:
model = Profile
fields = '__all__'
Views.py:
from rest_framework import viewsets, permissions
from .models import Profile
from .serializers import ProfileSerializer
class ProfileViewSet(viewsets.ModelViewSet):
queryset = Profile.objects.all()
permission_classes = [
permissions.AllowAny
]
serializer_class = ProfileSerializer
The issue is that in the Api, the return values of the method aren't there. The friends_list method for example is supposed to return a list of friends you have and even though this does work in a traditional django project, the Django Rest Framework is not showing any value for this method. How can I fix this and get the return values for both methods to show up in the api?
Since the model serializer picks up only model fields for the serializer fields, you won't automatically get any methods copied over.
You can still send this read only data over the API by explicitly adding the two fields with reference to the model methods
class ProfileSerializer(serializers.ModelSerializer):
class Meta:
model = Profile
fields = [
# need to explicitly define all fields I believe
'friends_list',
'number_of_friends',
]
Now that the two fields (matching the method name are declared, DRF should create SerializerMethodField or ReadOnly field (not sure which one, but they are similar) for each of them.
It works coz it sets the source for those fields to be the same name, and if finds some attribute (in this case the methods) on the model.
If that doesn't work, you can
class ProfileSerializer(serializers.ModelSerializer):
friends_list = serializers.SerializerMethodField()
number_of_friends = serializers.SerializerMethodField()
class Meta:
model = Profile
fields = [
# need to explicitly define all fields I believe
'friends_list',
'number_of_friends',
]
def get_friends_list(self, instance):
return instance.friends_list()
def get_number_of_friends(self, instance):
return instance.number_of_friends()
when you use __all__ it call fields only you have to call fields with methods using list like that
`fileds = ["first_name","last_name","user",
"friends","friends_list","number_of_friends"
]`

Django RF, field level validation to check if requesting user is Admin

My Django Rest Framework project have models field where any authenticated users can create model instance.
However I wanted to make sure that only Django Admin can change the accepted field value.
What is the best way to prevent other users from changing the accepted field ?
Pls note that I want to keep permission for authenticated users to create model instance keeping default accepted field.
MODELS.PY
class PO(models.Model):
name = models.CharField(max_length=100)
accepted=models.BooleanField(default=False) # I want this field to be changed only by admin user
VIEWS.PY
class POcreate(generics.CreateAPIView):
queryset = PO.objects.all()
serializer_class = POserializer
permission_classes = [permissions.IsAuthenticated]
SERIALIZER.PY
class POserializer(serializers.ModelSerializer):
class Meta:
model=PO
fields='__all__'
changed view layer and serializer
def get_serializer_class(self):
if self.request.user.is_staff:
return POAdminserializer
return POserializer
class POAdminserializer(serializers.ModelSerializer):
class Meta:
model=PO
fields='__all__'
class POserializer(serializers.ModelSerializer):
class Meta:
model=PO
exclude=('created','accepted','delivered','rejected','rejected_reason')

UserProfile missing the User object

I'm using a custom sign up form with django-allauth.
settings.py
ACCOUNT_SIGNUP_FORM_CLASS = 'project.userprofile.form.UserSignupForm'
form.py
from django import forms
from models import UserProfile
class UserSignupForm(forms.ModelForm):
class Meta:
model = UserProfile
fields = ('mobile_number',)
models.py
from django.db import models
from django.contrib.auth.models import User
class UserProfile(models.Model):
user = models.ForeignKey(User, unique=True)
mobile_number = models.CharField(max_length=30, blank=True, null=True)
User.profile = property(lambda u: UserProfile.objects.get_or_create(user=u)[0])
The User and the UserProfile objects are created, however the UserProfile isn't associated with any User object. It's late and I'm probably missing something silly, right?
UPDATE: As Kevin pointed out, the solution was to add the save method in the form.py. This is how it looks now:
from django import forms
from django.contrib.auth.models import User
from models import UserProfile
class UserSignupForm(forms.ModelForm):
class Meta:
model = UserProfile
fields = ('mobile_number',)
def save(self, user):
profile = UserProfile(user=user)
profile.mobile_number = self.cleaned_data['mobile_number']
profile.save()
The documentation says:
[ACCOUNT_SIGNUP_FORM_CLASS] should implement a ‘save’ method, accepting the newly signed up user as its only parameter.
It looks like you haven't provided such a method, so the user never gets connected to the profile. And I think you're not seeing an error because ModelForm has a save(commit=True) method that happens to match this signature, even though it doesn't do what you want.

How can I fill a field in Django with the username?

I have a model, configuration, in Django and wish to fill the author field with get_username
Can this be done within the model or must it be done from the form? If it must be on the form, how can I change the standard admin page to have this functionality?
At present, the model reads thus:
class Configuration(models.Model):
title = models.CharField(max_length=100,unique=True,blank=False)
author = models.CharField(max_length=50,blank=False)
created = models.DateTimeField("date created",auto_now_add=True)
modified = models.DateTimeField("date modified",auto_now=True)
description = models.CharField(max_length=512)
drawing = models.ForeignKey(Drawing)
instruments = models.ManyToManyField(Instrument)
def __unicode__(self):
return self.title
Use models.ForeignKey:
#models.py
from django.contrib.auth.models import User
class Configuration(models.Model):
author = models.ForeignKey(User)
...
#admin.py:
class Configuration_admin(admin.ModelAdmin):
fields = ('title', 'author',....)
something like that:
from django.contrib.auth.models import User
class ...
...
username = models.ForeignKey(User)
If you want to make some relationship between your model and default User model then you can extends the User model into your own custom model , like this:
models.py
from django.contrib.auth.models import User
class Configuration(models.Model):
author = models.OneToOneField(User)
..
..

Categories

Resources