Sometimes, frameworks make things more complicated instead of simplifying them. I would like to serialize a join like this one
queryset = Cities.objects.raw("SELECT 1 as id, cities.name as ci, states.name as s, countries.name as co FROM cities JOIN states ON states.id = cities.state_id LEFT OUTER JOIN countries ON countries.id = states.country_id WHERE cities.name = %s", [city])
or like this one, if raw queries are not recommended
city = self.request.query_params.get("cityname")
As you can see this is a reverse join. The idea is to serialize a result set like this one
0:
name: "Guadalajara"
state: "Castilla La Mancha"
country: "Spain"
1:
name: "Guadalajara"
state: "Jalisco"
coutry: "Mexico"
Two cities having the same name but belonging to different states and countries. I need this to implement a sort of autocomplete feature. This is actually pseudocode but it gives an idea about the kind of JSON result I would like to get.
I read the documentation and I searched the internet, I found nothing clear about how to do this.
I'm new to Django and I'm completely lost, this is a simple task that would be easy to do manually, but I have no idea about how to achieve this using Django Rest Framework (or any other tool from Django).
Any help would be really appreciated.
The DRF provides generic views to serialize a collection of objects using a particular model. Let's say you have a model called City
like this:
from django.db import models
class City(models.Model):
name = models.CharField()
state = models.CharField()
country = models.CharField()
And a serializer like this one:
from rest_framework import serializers
class CitySerializer(serializers.ModelSerializer):
class Meta:
model = City
fields = ['name', 'state', 'country']
In your view you'd need to inherit from generics.ListAPIView
like so:
from rest_framwork.generics import ListAPIView
class CityList(ListAPIView):
serializer_class = CitySerializer
def get_queryset(self):
return City.objects.filter(
name=self.request.query_params.get('cityname')
)
The ListAPIView class serializes a list of City instances for you quite easily. You can find further explanations here: https://www.django-rest-framework.org/api-guide/generic-views/#listapiview
I found a solution, I don't know if it's the best solution but it worked for me and I would like to share it. If someone find a better way to do this, you are welcome to suggest changes.
My model:
""" The following 3 models deal with tables that already exist in the database """
class Countries(models.Model):
name = models.CharField(max_length=100)
iso3 = models.CharField(max_length=3, blank=True, null=True)
iso2 = models.CharField(max_length=2, blank=True, null=True)
phonecode = models.CharField(max_length=255, blank=True, null=True)
capital = models.CharField(max_length=255, blank=True, null=True)
currency = models.CharField(max_length=255, blank=True, null=True)
currency_symbol = models.CharField(max_length=255, blank=True, null=True)
tld = models.CharField(max_length=255, blank=True, null=True)
native = models.CharField(max_length=255, blank=True, null=True)
region = models.CharField(max_length=255, blank=True, null=True)
subregion = models.CharField(max_length=255, blank=True, null=True)
timezones = models.TextField(blank=True, null=True)
translations = models.TextField(blank=True, null=True)
latitude = models.DecimalField(max_digits=10, decimal_places=8, blank=True, null=True)
longitude = models.DecimalField(max_digits=11, decimal_places=8, blank=True, null=True)
emoji = models.CharField(max_length=191, blank=True, null=True)
emojiu = models.CharField(db_column='emojiU', max_length=191, blank=True, null=True) # Field name made lowercase.
created_at = models.DateTimeField(blank=True, null=True)
updated_at = models.DateTimeField()
flag = models.IntegerField()
wikidataid = models.CharField(db_column='wikiDataId', max_length=255, blank=True, null=True) # Field name made lowercase.
class Meta:
managed = False
db_table = 'countries'
class States(models.Model):
name = models.CharField(max_length=255)
country = models.ForeignKey(Countries, models.DO_NOTHING)
country_code = models.CharField(max_length=2)
fips_code = models.CharField(max_length=255, blank=True, null=True)
iso2 = models.CharField(max_length=255, blank=True, null=True)
latitude = models.DecimalField(max_digits=10, decimal_places=8, blank=True, null=True)
longitude = models.DecimalField(max_digits=11, decimal_places=8, blank=True, null=True)
created_at = models.DateTimeField(blank=True, null=True)
updated_at = models.DateTimeField()
flag = models.IntegerField()
wikidataid = models.CharField(db_column='wikiDataId', max_length=255, blank=True, null=True) # Field name made lowercase.
class Meta:
managed = False
db_table = 'states'
class Cities(models.Model):
name = models.CharField(max_length=255)
state = models.ForeignKey('States', models.DO_NOTHING)
state_code = models.CharField(max_length=255)
country = models.ForeignKey('Countries', models.DO_NOTHING)
country_code = models.CharField(max_length=2)
latitude = models.DecimalField(max_digits=10, decimal_places=8)
longitude = models.DecimalField(max_digits=11, decimal_places=8)
created_at = models.DateTimeField()
updated_at = models.DateTimeField()
flag = models.IntegerField()
wikidataid = models.CharField(db_column='wikiDataId', max_length=255, blank=True, null=True) # Field name made lowercase.
class Meta:
managed = False
db_table = 'cities'
Sure, the database comes from this project, if someone needs it https://dr5hn.github.io/countries-states-cities-database/
Here's my View
class CityViewSet(viewsets.ReadOnlyModelViewSet):
serializer_class = CitiesSerializer
def get_queryset(self):
city = self.request.query_params.get("cityname")
queryset = Cities.objects.filter(name__startswith=city)
return queryset
And finally my serializers.py
""" Fields:
'name','country','country-code','fips_code','iso2','latitude','longitude','created_at','updated_at','flag','wikidataid'
"""
class StatesSerializer(serializers.ModelSerializer):
class Meta:
model = States
fields = ['name', 'iso2']
""" Fields
'name','iso3','iso2','phonecode','capital','currency_symbol','tld','native','region','subregion','timezones','translations','latitude','longitude','emoji','emojiu','created_at','updated_at','flag','wikidataid'
"""
class CountriesSerializer(serializers.ModelSerializer):
class Meta:
model = Countries
fields = ['name', 'iso2', ]#'translations']
"""Fields:
'name','state','state_code','country','country_code','latitude','longitude','created_at','updated_at','flag','wikidataid'
"""
class CitiesSerializer(serializers.ModelSerializer):
state = StatesSerializer(many=False)
country = CountriesSerializer(many=False)
class Meta:
model = Cities
fields = ['name', 'state', 'country', 'latitude', 'longitude']
With this code I will get the right expected JSon output. Sure it must be read by a proper forntend, like JQuery, Vue or even Vanilla JavaScript, but the object of the question is fullfilled.
If you know a better way, again, don't hesitate.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.