I'm new to Django and have just started to learn the basics. I have some questions about how to structure the code, how relationships should be written, and where the business logic should live.
I have written a simple app that should do the following:
- Store Group and Member entities in a database.
- Maintain a many-to-many relationship between groups and members, as well as member role specific to each group.
To create or update a group it should be possible send a request with the json structure shown below.
{ "name": "My group 1", "members": [ { "id": 1, "role": "Leader" }, { "id": 2, "role": "Regular" } ] }
Questions about the code
- Am I re-inventing the wheel with the custom update/create code in the GroupSerializer? Does what I'm trying to do already exist in Django and I have just not found the right approach?
- Is the update/create logic in the GroupSerializers misplaced? Should this be in the views.py file?
- In serializers.py, line 23, is there a better way than using "source=groupmember_set". I feel dirty hardcoding this string. In additional comments are of course welcome.
I appreciate any feedback that can improve the code and my knowledge further!
models.py
from __future__ import unicode_literals
from django.db import models
class Member(models.Model):
name = models.CharField(max_length=50)
def __unicode__(self):
return self.name
class Group(models.Model):
name = models.CharField(max_length=50)
members = models.ManyToManyField(Member, blank=True, related_name='groups', through="GroupMember")
def __unicode__(self):
return self.name
class GroupMember(models.Model):
member = models.ForeignKey(Member, on_delete=models.CASCADE)
group = models.ForeignKey(Group, on_delete=models.CASCADE)
role = models.CharField(max_length=40)
def __unicode__(self):
return self.member.name + " " + self.group.name + " - " + self.role
serializers.py
from rest_framework import serializers
from models import Group, Member, GroupMember
from django.db import transaction
class MemberSerializer(serializers.ModelSerializer):
class Meta:
model = Member
fields = ('id', 'name', 'groups')
class GroupMemberSerializer(serializers.ModelSerializer):
id = serializers.ReadOnlyField(source='member.id')
name = serializers.ReadOnlyField(source='member.name')
class Meta:
model = GroupMember
fields = ('id', 'name', 'role')
class GroupSerializer(serializers.ModelSerializer):
members = GroupMemberSerializer(source="groupmember_set", many=True, read_only=True)
class Meta:
model = Project
fields = '__all__'
depth = 1
@transaction.atomic
def update(self, instance, validated_data):
# Ignore the fact that i delete and replace. Will diff in the future
GroupMember.objects.filter(group=instance).delete()
members = self.initial_data.get("members")
for member in members:
id = member.get("id")
role = member.get("role")
new_member = Member.objects.get(pk=id)
GroupMember(group=instance, member=new_member, role=role).save()
instance.__dict__.update(**validated_data)
instance.save()
return instance
@transaction.atomic
def create(self, validated_data):
group = Group.objects.create(**validated_data)
if "members" in self.initial_data:
members = self.initial_data.get("members")
for member in members:
id = member.get("id")
role = member.get("role")
member_instance = Member.objects.get(pk=id)
GroupMember(group=group, member=member_instance, role=role).save()
group.save()
return project
views.py
from rest_framework import viewsets
from models import Group, Member
from serializers import GroupSerializer, MemberSerializer
class GroupViewSet(viewsets.ModelViewSet):
queryset = Group.objects.all()
serializer_class = GroupSerializer
class MemberViewSet(viewsets.ModelViewSet):
queryset = Member.objects.all()
serializer_class = MemberSerializer