Reputation: 2378
I need to filter the results of a ManyToManyField before serializing it.
Example:
A user should see details on a record only if 'expiration_date' hasn't passed for 'Authorized Program' on file for the 'Individual' who is the subject of the record.
My model and serializer currently show a list of ALL related Authorized Program records.
Question:
How can I filter that list to only non-expired records before returning as a list in the parent 'individual' record?
Note: This is not a question about filtering the parent queryset based on the M2M field. It's about filtering the contents of the M2M field before returning the parent.
Currently, the serializer simply skips the 'active_authorized_program_list' field.
class Individual(models.Model):
name = models.CharField(max_length=128, blank=True, default='')
dob = models.DateField(null=True)
authorized_program_list = models.ManyToManyField(
'Program',
related_name='individual_authorized_program_list',
through='ReleaseAuthorization',
blank=True
)
@property
def current_age(self):
if self.dob:
today = datetime.date.today()
return (today.year - self.dob.year) - int(
(today.month, today.day) <
(self.dob.month, self.dob.day))
else:
return 'Unknown'
@property
def active_authorized_program_list(self):
return (
self
.authorized_program_list
.get_queryset()
.filter(expiration_date__lte=datetime.Date())
)
class Program(models.Model):
name = models.CharField(max_length=128, blank=True, default='')
individual_list = models.ManyToManyField(
'individual.Individual',
related_name='program_individual_list',
through='hub_program.ReleaseAuthorization',
blank=True
)
active = models.BooleanField(default=True)
class ReleaseAuthorization(models.Model):
individual = models.ForeignKey(
Individual,
related_name="release_authorization_individual",
on_delete=models.CASCADE
)
program = models.ForeignKey(
Program,
related_name="release_authorization_program",
on_delete=models.CASCADE
)
expiration_date = models.DateField()
class IndividualSerializer(serializers.ModelSerializer):
class Meta:
model = Individual
fields = (
'name',
'dob',
'current_age',
'authorized_program_list',
'active_authorized_program_list',
)
Serialized Result is missing the last line for 'active_authorized_program_list':
{
"name": "Individual One",
"dob": "1974-10-11",
"current_age": 43,
"authorized_program_list": [1,2,3]
}
Should also have:
"active_authorized_program_list": [1,2]
Upvotes: 0
Views: 69
Reputation: 47364
Try to specify type of field in serializer as PrimaryKeyRelatedField
:
class IndividualSerializer(serializers.ModelSerializer):
active_authorized_program_list = serializers.PrimaryKeyRelatedField(many=True, read_only=True)
class Meta:
model = Individual
fields = (
'name',
'dob',
'current_age',
'authorized_program_list',
'active_authorized_program_list',
)
Also you can generate list in serializer directly using SerializerMethodField
:
class IndividualSerializer(serializers.ModelSerializer):
active_authorized_program_list = SerializerMethodField()
class Meta:
model = Individual
fields = (
'name',
'dob',
'current_age',
'authorized_program_list',
'active_authorized_program_list',
)
def get_active_authorized_program_list(self, obj):
return (
self
.authorized_program_list
.filter(expiration_date__lte=datetime.Date()).values_list('id', flat=True)
)
Upvotes: 1