I've been struggling to understand how one would update a M2M-field in the django rest framework that is between a custom user and some random field. I should mention I'm using Djoser as authentication.
Lets say I have a custom user
Models:
class CustomUser(AbstractUser):
username = None
email = models.EmailField(_('email address'), unique=True)
paying_user = models.BooleanField(default=False)
subscribed_companies = models.ManyToManyField('myapp.Company')
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = []
objects = UserAccountManager()
def __str__(self):
return f"{self.email}' account"
class Company(models.Model):
name = models.CharField(max_length=150)
def __str__(self):
return self.name
class Meta:
ordering = ['name']
My serializers
Imports - serializers.py:
from django.contrib.auth import get_user_model
from djoser.serializers import UserCreateSerializer
from rest_framework import serializers
from apartments.models.company_model import Company
User = get_user_model()
class UserCreateSerializer(UserCreateSerializer):
class Meta(UserCreateSerializer.Meta):
model = User
fields = ('email','password', 'paying_user', 'subscribed_companies')
class UserCompanyListSerializer(serializers.ModelSerializer):
#Is this a reasonable way to serialize a M2M-field?
subscribed_company_ids = serializers.PrimaryKeyRelatedField(many=True, read_only=False,
queryset=Company.objects.all(), source='subscribed_companies')
class Meta:
model = User
fields = [
'subscribed_company_ids'
]
class CompanySerializer(serializers.ModelSerializer):
class Meta:
model = Company
fields = ('name',)
As you can see, I've attached a M2M-field on the custom user itself, instead of using a OneToOne-field where I store custom data. I'm not sure this is the best way to do it.
The idea is that a user should be able to, on the front end, have a list of companies it wants to subscribe to once they are logged in. That means I'll have many users that can subscribe to many companies.
Where I'm really doubting myself is how I handled the class based views. Since I can retrieve the ID from request.user.id and since I want to replace the entire list of companies, I don't need the PK which identifies a specific company. Therefore, in the put method, I removed the PK parameter. This works.
So my question is - Is there a more clean way to do it? Looking at posts at stackoverflow I couldn't find a decent answer that involved authentication. Am I approaching it wrong?
class UserCompanies(APIView):
permission_classes = [permissions.IsAuthenticatedOrReadOnly]
def get(self, request):
user_id = request.user.id
instance = CustomUser.objects.get(id=user_id)
serializer = UserCompanyListSerializer(instance)
return Response(serializer.data)
def put(self, request, format=None):
user_id = request.user.id
instance = CustomUser.objects.get(id=user_id)
serializer = UserCompanyListSerializer(instance, data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
How a GET request response would look to localhost:8000/usercompanies/:
{
"subscribed_company_ids": [
2,
1,
3
]
}
How a PUT request response would look to localhost:8000/usercompanies/:
{
"subscribed_company_ids": [
2,
1,
3,
5,
4,
]
}
Feedback would be much appreciated, I'm a total DRF newbie.