In my model, I have two tables named: Vtable and Vdata. Each virtual table (in Vtable) has entries of virtual data stored in Vdata.
I'm trying to make a view that would show the list of Vdata corresponding to each Vtable
My serializer isn't working and I think it's because I'm doing it backwards.
I think the problem is in this line:
table_id = serializers.RelatedField(many=True)
For reference, I get this error: 'Vtable' object is not iterable
Here is my models.py:
from django.db import models
from django.contrib.auth.models import User
class Vtable(models.Model):
user = models.ForeignKey(User)
table_name = models.CharField(max_length=200)
added_date = models.DateTimeField('date added')
def __unicode__(self):
return self.table_name
class Vdata(models.Model):
table_id = models.ForeignKey(Vtable)
table_pk = models.IntegerField()
column_1 = models.CharField(max_length=200)
column_2 = models.CharField(max_length=200)
added_date = models.DateTimeField('date added')
def __unicode__(self):
return str(self.added_date)
Here is my serializers.py:
from django.contrib.auth.models import User, Group
from rest_framework import serializers
from vtables.models import Vtable, Vdata
class TableSerializer(serializers.HyperlinkedModelSerializer):
user = serializers.Field(source='user.username')
class Meta:
model = Vtable
fields = ('table_name', 'added_date', 'user')
class EntrySerializer(serializers.HyperlinkedModelSerializer):
table_id = serializers.RelatedField(many=True)
class Meta:
model = Vdata
fields = ('table_id', 'table_pk', 'column_1', 'column_2', 'added_date')
Here is the view that calls it:
class EntryList(APIView):
def get(self, request, format=None):
entries = Vdata.objects.all()
serializer = EntrySerializer(entries, many=True)
return Response(serializer.data
class Meta:
model = Vdata
fields = ('table_id', 'table_pk', 'column_1', 'column_2', 'added_date')
Here is an example of how you might do this:
class TableSerializer(serializers.HyperlinkedModelSerializer):
user = serializers.Field(source='user.username')
entries = EntrySerializer(many=True)
class Meta:
model = Vtable
fields = ('table_name', 'added_date', 'user', 'entries')
class EntrySerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Vdata
fields = ('table_id', 'table_pk', 'column_1', 'column_2', 'added_date')
And for the view:
class EntryList(GenericAPIView):
queryset = Vtable.objects.all()
serializer_class = TableSerializer
Do not forget about:
setting related_name='entries' in your model foreign key field definition.
Related
I have a few different models with a fact table of scenarios and 6 dimension tables that relate to it below as examples:
class fScenario(models.Model):
#Variables
scenarioId = models.IntegerField(primary_key=True)
description = models.CharField(max_length=100)
def __str__(self):
return str(self.scenarioId)
def get_absolute_url(self):
return reverse('scenario-detail', args=[str(self.scenarioId)])
class Meta:
ordering = ['scenarioId']
class dADA(models.Model):
#Variables
scenarioId = models.ForeignKey(fScenario, on_delete=models.CASCADE)
dateTimeId = models.DateTimeField('ADA Time/Date')
latitutde = models.FloatField(default=0)
longitude = models.FloatField(default=0)
instanceType = models.CharField(max_length=50, default='ADA')
def __str__(self):
return f'{self.scenarioId}, {self.instanceType}'
class Meta:
ordering = ['dateTimeId']
serializers.py
class fScenarioSerializer(serializers.ModelSerializer):
class Meta:
model = fScenario
fields = ['scenarioId', 'description']
class dADASerializer(serializers.ModelSerializer):
scenarioId = fScenarioSerializer(read_only=True)
class Meta:
model = dADA
fields = ['scenarioId', 'dateTimeId', 'latitutde', 'longitude', 'instanceType']
urls.py
router = routers.DefaultRouter()
router.register(r'fScenario', views.fScenarioViewSet)
router.register(r'dADA', views.dADAViewSet)
urlpatterns = [
path('', include(router.urls)),
views.py
class fScenarioViewSet(viewsets.ModelViewSet):
queryset = fScenario.objects.all()
serializer_class = fScenarioSerializer
class dADAViewSet(viewsets.ModelViewSet):
queryset = dADA.objects.all()
serializer_class = dADASerializer
I'm using rest framework view sets and I currently can see in my API separate fScenario and dADA views but cant figure out how to link the dADA to the fScenario view on one page.
You can use SerializerMethodField and Django many-to-one backward relation to retrieve related objects:
serializers.py
class fScenarioSerializer(serializers.ModelSerializer):
dADA_list = serializers.SerializerMethodField()
class Meta:
model = fScenario
fields = ['scenarioId', 'description', 'dADA_list']
def get_dADA_list(self, obj):
return obj.dada_set.all().values()
I am joining two tables than I would like to do keyword searching. I need to create a single SQL and add a WHERE with argument(s). I am using django-rest-framework.
models.py
from django.db import models
class Paper(models.Model):
title = models.TextField()
paper_lan = models.CharField(max_length=2)
nb_authors = models.SmallIntegerField()
class Meta:
managed = False
def __str__(self):
return str(self.title)
class Abstract(models.Model):
paper = models.OneToOneField(Paper,
related_name='abstracts',
on_delete=models.CASCADE,
primary_key=True)
abstract = models.TextField()
class Meta:
managed = False
def __str__(self):
return str(self.abstract)
serializers.py
from rest_framework import serializers
from .models import Paper, Abstract
class PaperAbstractSerializer(serializers.ModelSerializer):
class Meta:
model = Paper
#fields = '__all__'
fields = ['title', 'paper_lan', 'nb_authors', 'abstracts']
depth = 1
class PaperSerializer(serializers.ModelSerializer):
class Meta:
model = Paper
fields = ('title', 'paper_lan', 'nb_authors')
class AbstractSerializer(serializers.ModelSerializer):
class Meta:
model = Abstract
fields = ['abstract']
filters.py
from django.db.models import Q
from django_filters.rest_framework import CharFilter, FilterSet
from .models import Paper, Abstract
class PaperAbstractFilterSet(FilterSet):
query = CharFilter(method='qfilter')
class Meta:
model = Paper
fields = ['query']
def qfilter(self, queryset, name, value):
squery = Q(abstracts__icontains=value)
return queryset.filter(squery)
class PaperFilterSet(FilterSet):
query = CharFilter(method='qfilter')
class Meta:
model = Paper
fields = ['query']
def qfilter(self, queryset, name, value):
squery = Q(title__icontains=value)
return queryset.filter(squery)
class AbstractFilterSet(FilterSet):
query = CharFilter(method='qfilter')
class Meta:
model = Abstract
fields = ['query']
def qfilter(self, queryset, name, value):
squery = Q(abstract__icontains=value)
return queryset.filter(squery)
views.py
from rest_framework.generics import ListAPIView
from .models import Paper, Abstract
from .serializers import PaperAbstractSerializer, PaperSerializer, AbstractSerializer
from .filters import PaperAbstractFilterSet, PaperFilterSet, AbstractFilterSet
class PaperAbstractView(ListAPIView):
queryset = Paper.objects.all()
serializer_class = PaperAbstractSerializer
filterset_class = PaperAbstractFilterSet
class PaperView(ListAPIView):
queryset = Paper.objects.all()
serializer_class = PaperSerializer
filterset_class = PaperFilterSet
class AbstractView(ListAPIView):
queryset = Abstract.objects.all()
serializer_class = AbstractSerializer
filterset_class = AbstractFilterSet
urls.py
from django.urls import path
from .views import PaperAbstractView, PaperView, AbstractView
urlpatterns = [
path('paperabs/', PaperAbstractView.as_view()),
path('paper/', PaperView.as_view()),
path('abstract/', AbstractView.as_view()),
]
When I run the followings, searching is made on a single table, everything is fine. There is only a single SQL which is produced.
curl "http://localhost:8003/api/v1/appln/abstract/?query=<keyword_searching>"
curl "http://localhost:8003/api/v1/appln/paper/?query=<keyword_searching>"
But, when I run the following request, I cannot make any keyword search. If I comment the filterset_class = PaperAbstractFilterSet ligne in PaperAbstractView, there is one SQL and then relatedly there are n other SQL produced for the second table.
curl "http://localhost:8003/api/v1/appln/paperabs/?query=<keyword_searching>"
How can I create a single SQL with the complementary WHERE to conduct any search on title and/or abstract?
To answer my own question; to join two tables in a single SQL I use select_related and correct the serializers.py by adding the LEFT JOINed table's serializer, AbstractSerializer into PaperAbstractSerializer.
# serializers.py
class PaperAbstractSerializer(serializers.ModelSerializer):
abstracts = AbstractSerializer(read_only=True)
class Meta:
model = Paper
fields = ['title', 'paper_lan', 'nb_authors', 'abstracts']
# views.py
class PaperAbstractView(ListAPIView):
queryset = Paper.objects.select_related('abstracts').all()
serializer_class = PaperAbstractSerializer
filterset_class = PaperAbstractFilterSet
I have models (one user can has multiple employees):
from django.db import models
class User(models.Model):
username = ...
first_name = ...
last_name = ...
class OrgUnit(models.Model):
name = ....
address = ...
class Employee(models.Model):
personnel_no = ...
user = models.ForeignKey(User, related_name='employees'...)
orgunit = models.ForeignKey(OrgUnit, ...)
Serializers and views:
class EmployeeSerializer(serializers.ModelSerializer):
orgunit = serializers.CharField(source='orgunit.name') <==== one orgunit - one query to DB
class Meta:
model = Employee
fields = '__all__'
class CustomUserSerializer(serializers.ModelSerializer):
employees = EmployeeSerializer(many=True)
class Meta:
model = User
fields = '__all__'
class UsersViewSet(ViewSet):
def me(self, request):
serializer = CustomUserSerializer(request.user)
return Response(serializer.data)
When serializing orgunit.name per one orgunit one query to DB is being performed. How to avoid this? How to prefetch employees related_name and its orgunits?
In this case you can use Prefetch..[Django-doc] and prefetch_related_objects..[Django-doc] to fetch all related employees with orgunit selected as well:
from django.db.models import Prefetch, prefetch_related_objects
class UsersViewSet(ViewSet):
def me(self, request):
prefetch_related_objects(
[request.user],
Prefetch(
"employees",
queryset=Employee.objects.select_related("orgunit"),
),
)
serializer = CustomUserSerializer(request.user)
return Response(serializer.data)
I am creating a todo list API(backend) in django rest framework. I have two models List and Task
#models.py
from django.db import models
# Create your models here.
class List(models.Model):
list_name = models.CharField(max_length=200)
def __str__(self):
return self.list_name
class Meta:
db_table = 'list'
class Task(models.Model):
todo_list = models.ForeignKey(List, on_delete=models.CASCADE)
task_name = models.CharField(max_length=500)
due_date = models.DateField()
done = models.BooleanField(default=False)
def __str__(self):
return self.task_name
class Meta:
db_table = 'task'
The serializers file,
#serializers.py
from rest_framework import serializers
from rest_framework_serializer_extensions.serializers import SerializerExtensionsMixin
from .models import List, Task
class ListSerializer(SerializerExtensionsMixin, serializers.ModelSerializer):
class Meta:
model = List
fields = "__all__"
class TaskSerializer(SerializerExtensionsMixin, serializers.ModelSerializer):
class Meta:
model = Task
fields = "__all__"
expandable_fields = dict(
todolist=ListSerializer
)
My todo list app will have multiple lists and each list have multiple tasks. Each task will have a due date and can be marked as done. I am trying to add the number of pending tasks to my List json. How do I go about doing that?
You can add a new field using SerializerMethodField:
class ListSerializer(SerializerExtensionsMixin, serializers.ModelSerializer):
pending_count = serializers.SerializerMethodField()
class Meta:
model = List
fields = "__all__"
def get_pending_count(self, obj):
return obj.task_set.filter(done=False).count()
I have two models which is related to a forignkey.
class BikeModel(models.Model):
City = models.ForeignKey(CityForBike, on_delete=models.CASCADE)
BikeModels = models.CharField(default='', max_length=50)
Image = models.ImageField(upload_to='bike_images', blank=True, null=True, default='https://www.urbandrive.co.in/Admin/API/UploadedFiles/CarImage/44b150b3-f61a-41b5-afd8-34ded18fa980.png')
class Meta:
verbose_name_plural = 'BikeModels'
def __str__(self):
return self.BikeModels
class CityForBike(models.Model):
CityForCars = models.CharField(default="",max_length=50)
class Meta:
verbose_name_plural = 'CityForBikes'
def __str__(self):
return self.CityForCars
and i want to insert data to BikeModel. but it gives me error.
AssertionError: You cannot call `.save()` on a serializer with invalid data.
I want to know how to insert data to forign key field.
if request.method == 'POST':
import pdb;
pdb.set_trace()
input_data = json.loads(request.read().decode('utf-8'))
print(input_data)
serializer = serializers.BikeModelSerializer(data=input_data)
if serializer.is_valid():
serializer.save()
return render(request, "bike_model_add.html", {'car_city': car_city}, status=200)
And this is the data i am sending.
{'City': 'testo', 'BikeModels': 'ds'}
this is my serializers
class CityForBikeSerializer(serializers.ModelSerializer):
class Meta:
model = models.CityForBike
fields = '__all__'
class BikeModelSerializer(serializers.ModelSerializer):
class Meta:
model = models.BikeModel
fields = '__all__'
If you want to identify cities by their name in the bike serializer, you need to use SlugRelatedField.
class BikeModelSerializer(serializers.ModelSerializer):
City = serializers.SlugRelatedField(slug_field='CityForCars')
class Meta:
model = models.BikeModel
fields = '__all__'