I have data models like:
from django.db import models
class Student(models.Model):
first_name = models.CharField(max_length=50)
last_name = models.CharField(max_length=50)
email = models.EmailField()
def __str__(self):
return self.first_name + ' ' + self.last_name
class Course(models.Model):
name = models.CharField(max_length=255)
description = models.TextField()
start_date = models.DateField(null=True)
end_date = models.DateField(null=True)
def __str__(self):
return self.name
class CourseParticipant(models.Model):
course = models.ForeignKey(Course, related_name='courses', on_delete=None)
student = models.ForeignKey(Student, related_name='students', on_delete=None)
completed = models.BooleanField(null=True, default=False)
def __str__(self):
return self.course
I have some serializer like:
class CourseSerializer(serializers.ModelSerializer):
class Meta:
model = Course
fields = ('name', 'end_date', 'start_date')
I need return data in json like:
{
"courses": [
{
"name": "Math",
"end_date": "2019-06-26",
"start_date": "2019-06-26",
"participant_students_count: 10
}
]
}
How I can get "participant_students_count" and return its data in json with other fields.
Thanks for help!
You can use SerializerMethodField of DRF serializer field. Also, see about how to follow Backward access of Foreign key relationship.
from rest_framework import serializers
class CourseSerializer(serializers.ModelSerializer):
participant_students_count = serializers.SerializerMethodField()
class Meta:
model = Course
fields = ('name', 'end_date', 'start_date', 'participant_students_count')
def get_participant_students_count(self, obj):
return obj.courseparticipant_set.count()
class CourseSerializer(serializers.ModelSerializer):
participant_students_count = serializers.SerializerMethodField()
def get_participant_students_count(self, obj):
return CourseParticipant.objects.filter(course=obj).count()
class Meta:
model = Course
fields = ('name', 'end_date', 'start_date', 'participant_students_count')
Related
I need to pass data from EmployeeSerializer to VacationSerializer as nested json. This is my serializer.py:
class EmployeeSerializer(serializers.ModelSerializer):
class Meta:
model = Employee
fields = ('pk', 'first_name', 'surname', 'patronymic', 'birthday', 'email', 'position', 'phone_number')
class VacationSerializer(serializers.ModelSerializer):
class Meta:
model = Vacation
fields = ('pk', 'start_date', 'end_date', 'employee_id', 'employee')
and my models.py:
class Employee(models.Model):
first_name = models.CharField("Name", max_length=50)
surname = models.CharField("surname", max_length=50)
patronymic = models.CharField("patronymic", max_length=50)
birthday = models.DateField()
email = models.EmailField()
position = models.CharField("position", max_length=128)
phone_number = models.CharField("phone", max_length=12, null=True)
is_deleted = models.BooleanField(default=False)
def __str__(self):
return f'{self.surname} {self.first_name} {self.patronymic}'
class Vacation(models.Model):
start_date = models.DateField()
end_date = models.DateField()
employee_id = models.ForeignKey(Employee, related_name='employee', on_delete=models.PROTECT, default=-1)
def __str__(self):
return f'{self.start_date} - {self.end_date}'
#property
def date_diff(self):
return (self.end_date - self.start_date).days
in views.py I have this:
#api_view(['GET', 'POST'])
def vacations_list(request):
if request.method == 'GET':
data = Vacation.objects.all()
serializer = VacationSerializer(data, context={'request': request}, many=True)
return Response(serializer.data)
I've tried this:
class VacationSerializer(serializers.ModelSerializer):
employee = EmployeeSerializer(read_only=True, many=True)
class Meta:
model = Vacation
fields = ('pk', 'start_date', 'end_date', 'employee_id', 'employee')
but it doesn't show me even empty nested json, it shows me only VacationSerializer data.
I easily can access VacationSerializer from EmployeeSerializer using PrimaryKeySerializer or any other serializer and get nested json where VacationSerializer data is nested in EmployeeSerializer data. But I want it opposite - nested json of employee related to this vacation. How to achieve this?
That is because of the naming on your model. You need to serialize the 'employee_id' field:
class VacationSerializer(serializers.ModelSerializer):
employee_id = EmployeeSerializer()
class Meta:
model = Vacation
fields = ('pk', 'start_date', 'end_date', 'employee_id')
I am working just for my experience and I stacked with the following problem. There are three models: Book, Chapter, and Publisher. Each model is related to one another with the foreign key.
class Book(models.Model):
name = models.CharField(max_length=64)
publisher = models.ForeignKey('Publisher', on_delete=models.CASCADE, null=True, blank=True)
def __str__(self):
return self.name
class Chapter(models.Model):
name = models.CharField(max_length=128)
book = models.ForeignKey(Book, related_name='books', on_delete=models.CASCADE)
class Publisher(models.Model):
title = models.CharField(max_length=128)
description = models.TextField()
def __str__(self):
return self.title
class Meta:
ordering = ['title']
I want to serialize the data in PublisherDetailSerializer which should show their books and all chapters related to their books.
Here are my serializers:
class BookSerializer(serializers.ModelSerializer):
class Meta:
model = Book
fields = ('id', 'name', 'publisher')
def to_representation(self, instance):
ret = super().to_representation(instance)
return ret
class ChapterSerializer(serializers.ModelSerializer):
id = serializers.IntegerField()
name = serializers.CharField(required=False)
location = serializers.SerializerMethodField()
class Meta:
model = Chapter
fields = ('id', 'name', 'location')
def get_location(self, instance):
serializer = BookSerializer(instance.author, context=self.context)
return serializer.data
class PublisherSerializer(serializers.HyperlinkedModelSerializer):
books = BookSerializer(many=True, read_only=True)
class Meta:
model = Publisher
fields = ('id', 'title', 'description', 'books')
class PublisherDetailSerializer(PublisherSerializer):
chapters = serializers.SerializerMethodField()
class Meta:
model = Publisher
fields = ('id', 'title', 'description', 'books', 'chapters')
def get_chapters(self, instance):
serializer = ChapterSerializer(Chapter.objects.filter(location=instance.books.name), many=True, context=self.context)
return serializer.data
def to_representation(self, instance):
ret = super().to_representation(instance)
return ret
Here is my view for Publisher:
class PublisherViewSet(MultiSerializerViewSetMixin, viewsets.ReadOnlyModelViewSet):
queryset = Publisher.objects.all()
serializer_class = PublisherSerializer
serializer_action_classes = {
'list': PublisherSerializer,
'retrieve': PublisherDetailSerializer,
}
Showing publishers and their books shows the right information in the browsable API, but I don't know how to get chapters through books. How should I approach it?
Notes:
the related_name in a models.ForeignKey is not what you thing it is. it is the attribute name to be used on the otherside of the relationship, see the below code
you can just nest the serializers as shown below
Models
class Publisher(models.Model):
title = models.CharField(max_length=128)
description = models.TextField()
class Book(models.Model):
name = models.CharField(max_length=128)
publisher = models.ForeignKey(Publisher, related_name='books', on_delete=models.CASCADE)
class Chapter(models.Model):
name = models.CharField(max_length=128)
book = models.ForeignKey(Book, related_name='chapters', on_delete=models.CASCADE)
Serializers
class ChapterSerializer(serializers.ModelSerializer):
id = serializers.IntegerField()
name = serializers.CharField(required=False)
class Meta:
model = Chapter
fields = ('id', 'name')
class BookSerializer(serializers.ModelSerializer):
chapters = ChapterSerializer(many=True, read_only=True)
class Meta:
model = Book
fields = ('id', 'name', 'chapters')
class PublisherSerializer(serializers.HyperlinkedModelSerializer):
books = BookSerializer(many=True, read_only=True)
class Meta:
model = Publisher
fields = ('id', 'title', 'description', 'books')
I have seen some related posts, but I am not sure what I need to do.
I have set up a view to serialize my test model which has nested models. I have set up the serializers, but I get the error "Got AttributeError when attempting to get a value for field Question on serializer TestSerializer.\nThe serializer field might be named incorrectly".
My Serializers:
class AnswerSerializer(serializers.ModelSerializer):
class Meta:
model = Answer
fields = ('id', 'number', 'text', 'iscorrect')
class QuestionSerializer(serializers.ModelSerializer):
answer = AnswerSerializer()
class Meta:
model = Question
fields = ('id', 'number', 'text', 'answer')
related_object = 'answer'
class TestSerializer(serializers.ModelSerializer):
question = QuestionSerializer()
class Meta:
model = Test
fields = ('id', 'name', 'question')
related_object = 'question'
My Models:
class Test(models.Model):
user = models.ForeignKey(User, on_delete=models.PROTECT)
name = models.CharField(max_length=255,default='',blank=False)
datecreated = models.DateTimeField(auto_now=True)
def __str__(self):
return self.name
class Question(models.Model):
test = models.ForeignKey(Test, on_delete=models.CASCADE)
text = models.CharField(max_length=255,default='',blank=False)
number = models.IntegerField()
def __str__(self):
return self.text
class Answer(models.Model):
question = models.ForeignKey(Question, on_delete=models.CASCADE)
text = models.CharField(max_length=255,default='',blank=False)
number = models.IntegerField()
iscorrect = models.BooleanField(default=False)
def __str__(self):
return self.text
The call from the view:
serializer = TestSerializer(test, many=True)
You have set the related_name in the foreign key other wise default related name is {model_name}_set.
class Question(models.Model):
test = models.ForeignKey(Test, on_delete=models.CASCADE, related_name='questions')
text = models.CharField(max_length=255,default='',blank=False)
number = models.IntegerField()
def __str__(self):
return self.text
in serializer you can access that fields
class TestSerializer(serializers.ModelSerializer):
questions = QuestionSerializer(many=True)
class Meta:
model = Test
fields = ('id', 'name', 'question')
related_object = 'question'
I imported a project from Django builder, managed to install the dependencies, and start the admin, but I have an issue.
All of the fields in admin are not editable! None of them.
Here's a screenshot of the issue:
Here's the relevant files:
Admin.py
from django.contrib import admin
from django import forms
from .models import Tours, Locations, Photos, PlaceLocations, Information
class ToursAdminForm(forms.ModelForm):
class Meta:
model = Tours
fields = '__all__'
class ToursAdmin(admin.ModelAdmin):
form = ToursAdminForm
list_display = ['name', 'slug', 'created', 'last_updated', 'Tags', 'Photo', 'Description', 'Duration']
readonly_fields = ['name', 'slug', 'created', 'last_updated', 'Tags', 'Photo', 'Description', 'Duration']
admin.site.register(Tours, ToursAdmin)
class LocationsAdminForm(forms.ModelForm):
class Meta:
model = Locations
fields = '__all__'
class LocationsAdmin(admin.ModelAdmin):
form = LocationsAdminForm
list_display = ['name', 'slug', 'created', 'last_updated', 'Photo', 'MainLocLat', 'MainLocLon', 'MainLocRad', 'Audio', 'Description']
readonly_fields = ['name', 'slug', 'created', 'last_updated', 'Photo', 'MainLocLat', 'MainLocLon', 'MainLocRad', 'Audio', 'Description']
admin.site.register(Locations, LocationsAdmin)
class PhotosAdminForm(forms.ModelForm):
class Meta:
model = Photos
fields = '__all__'
class PhotosAdmin(admin.ModelAdmin):
form = PhotosAdminForm
list_display = ['name', 'slug', 'created', 'last_updated', 'Photo']
readonly_fields = ['name', 'slug', 'created', 'last_updated', 'Photo']
admin.site.register(Photos, PhotosAdmin)
class PlaceLocationsAdminForm(forms.ModelForm):
class Meta:
model = PlaceLocations
fields = '__all__'
class PlaceLocationsAdmin(admin.ModelAdmin):
form = PlaceLocationsAdminForm
list_display = ['name', 'slug', 'created', 'last_updated', 'Latitude', 'Longitude', 'Radius']
readonly_fields = ['name', 'slug', 'created', 'last_updated', 'Latitude', 'Longitude', 'Radius']
admin.site.register(PlaceLocations, PlaceLocationsAdmin)
class InformationAdminForm(forms.ModelForm):
class Meta:
model = Information
fields = '__all__'
class InformationAdmin(admin.ModelAdmin):
form = InformationAdminForm
list_display = ['name', 'slug', 'created', 'last_updated', 'Photo', 'Description']
readonly_fields = ['name', 'slug', 'created', 'last_updated', 'Photo', 'Description']
admin.site.register(Information, InformationAdmin)
models.py
from django.core.urlresolvers import reverse
from django_extensions.db.fields import AutoSlugField
from django.db.models import *
from django.conf import settings
from django.contrib.contenttypes.fields import GenericForeignKey
from django.contrib.contenttypes.models import ContentType
from django.contrib.auth import get_user_model
from django.contrib.auth import models as auth_models
from django.db import models as models
from django_extensions.db import fields as extension_fields
from smartfields import fields
from smartfields.dependencies import FileDependency
from smartfields.processors import ImageProcessor
class Tours(models.Model):
# Fields
name = models.CharField(max_length=255)
slug = extension_fields.AutoSlugField(populate_from='name', blank=True)
created = models.DateTimeField(auto_now_add=True, editable=False)
last_updated = models.DateTimeField(auto_now=True, editable=False)
Tags = models.TextField(max_length=100)
Photo = models.ImageField(upload_to="/upload/images/")
Description = models.TextField(max_length=2000)
Duration = models.IntegerField()
class Meta:
ordering = ('-created',)
def __unicode__(self):
return u'%s' % self.slug
def get_absolute_url(self):
return reverse('app_name_tours_detail', args=(self.slug,))
def get_update_url(self):
return reverse('app_name_tours_update', args=(self.slug,))
class Locations(models.Model):
# Fields
name = models.CharField(max_length=255)
slug = extension_fields.AutoSlugField(populate_from='name', blank=True)
created = models.DateTimeField(auto_now_add=True, editable=False)
last_updated = models.DateTimeField(auto_now=True, editable=False)
Photo = models.ImageField(upload_to="/upload/images/")
MainLocLat = models.TextField(max_length=100)
MainLocLon = models.TextField(max_length=100)
MainLocRad = models.TextField(max_length=100)
Audio = models.FileField(upload_to="/upload/files/")
Description = models.TextField(max_length=2000)
# Relationship Fields
Photos = models.ForeignKey('app_name.Photos', )
PlaceLocations = models.ForeignKey('app_name.PlaceLocations', )
class Meta:
ordering = ('-created',)
def __unicode__(self):
return u'%s' % self.slug
def get_absolute_url(self):
return reverse('app_name_locations_detail', args=(self.slug,))
def get_update_url(self):
return reverse('app_name_locations_update', args=(self.slug,))
class Photos(models.Model):
# Fields
name = models.CharField(max_length=255)
slug = extension_fields.AutoSlugField(populate_from='name', blank=True)
created = models.DateTimeField(auto_now_add=True, editable=False)
last_updated = models.DateTimeField(auto_now=True, editable=False)
Photo = models.ImageField(upload_to="/upload/images/")
class Meta:
ordering = ('-created',)
def __unicode__(self):
return u'%s' % self.slug
def get_absolute_url(self):
return reverse('app_name_photos_detail', args=(self.slug,))
def get_update_url(self):
return reverse('app_name_photos_update', args=(self.slug,))
class PlaceLocations(models.Model):
# Fields
name = models.CharField(max_length=255)
slug = extension_fields.AutoSlugField(populate_from='name', blank=True)
created = models.DateTimeField(auto_now_add=True, editable=False)
last_updated = models.DateTimeField(auto_now=True, editable=False)
Latitude = models.TextField(max_length=100)
Longitude = models.TextField(max_length=100)
Radius = models.IntegerField()
class Meta:
ordering = ('-created',)
def __unicode__(self):
return u'%s' % self.slug
def get_absolute_url(self):
return reverse('app_name_placelocations_detail', args=(self.slug,))
def get_update_url(self):
return reverse('app_name_placelocations_update', args=(self.slug,))
class Information(models.Model):
# Fields
name = models.CharField(max_length=255)
slug = extension_fields.AutoSlugField(populate_from='name', blank=True)
created = models.DateTimeField(auto_now_add=True, editable=False)
last_updated = models.DateTimeField(auto_now=True, editable=False)
Photo = models.ImageField(upload_to="/upload/images/")
Description = models.TextField(max_length=2000)
class Meta:
ordering = ('-created',)
def __unicode__(self):
return u'%s' % self.slug
def get_absolute_url(self):
return reverse('app_name_information_detail', args=(self.slug,))
def get_update_url(self):
return reverse('app_name_information_update', args=(self.slug,))
You should better remove the readonly_fields attribute on each ModelAdmin class. Doing that, the fields, in the admin panel, will not be read-only!
I have the following admin.py
class AInlineAdmin(admin.TabularInline):
model = A
class BAdmin(admin.ModelAdmin):
fields = ['name']
list_display = ['name']
ordering = ['name']
inlines = [AInlineAdmin]
admin.site.register(B, BAdmin)
class AAdmin(admin.ModelAdmin):
fields = ['identifier']
list_display = ['identifier']
ordering = ['identifier']
admin.site.register(A, AAdmin)
And the following models.py:
class B(models.Model):
name = models.CharField(max_length=100)
def get_A(self):
return "\n".join([i.identifier for i in self.a.all()])
def __unicode__(self):
return self.name
class A(models.Model):
identifier = models.CharField(max_length=200, blank=False, default="")
c = models.ForeignKey(B, related_name='a', default=0)
def __unicode__(self):
return self.identifier
And the following views.py:
class BCreate(CreateView):
model = B
fields = ['name', 'a']
But it is not working with 'a' inside "fields = ['name', 'a']", as 'a' is not found.
How can I get inlines into the view so I could edit/delete/create A inside B view?
The CreateView does not support this. You could use django-extra-views, which comes with CreateWithInlinesView and UpdateWithInlinesView views.