Here is my serializers.py
class GetCompanySerializer(serializers.ModelSerializer):
language = serializers.CharField()
class Meta:
model = Company
fields = ('company_name','started_from','country','email','website','ip','active','language')
here is my views.py
class CompanyView(viewsets.ModelViewSet):
queryset = Company.objects.all()
serializer_class = CompanySerializer
def get_serializer_class(self):
serializer_class = self.serializer_class
if self.request.method == 'GET':
serializer_class = GetCompanySerializer
return serializer_class
Here is my models.py
class Company(models.Model):
company_id = models.BigAutoField(primary_key=True)
company_name = models.CharField(max_length=255)
started_from = models.DateTimeField(auto_now=True)
country = models.CharField(max_length=255)
email = models.EmailField(max_length=254)
website = models.URLField()
ip = models.GenericIPAddressField(default=get_ip(),null=True,blank=True)
active = models.BooleanField(default=True)
def __str__(self):
return self.company_name
class Language(models.Model):
language_id = models.BigAutoField(primary_key=True)
language_name = models.CharField(max_length=255)
language_logo = models.FileField()
created_on = models.DateTimeField(auto_now=True)
latest_build_on = models.DateTimeField(auto_now_add=True)
latest_version = models.DecimalField(max_digits=5, decimal_places=2)
company = models.ForeignKey('Company',on_delete=models.CASCADE,related_name='language')
def __str__(self):
return self.language_name
giving api:
[
{
"company_name": "Guido van dom rossum",
"started_from": "2018-10-03T04:58:54.889132Z",
"country": "Netherland",
"email": "help#python.com",
"website": "https://python.org",
"ip": "127.0.0.1",
"active": true,
"language": "serializers.Language.None"
}
]
it should give the language name for language field bit it is giving "serializers.Language.None" instead.
please have a look into this..
Since language is a reverse relation it shouldn't be a CharField. So you have to define a LanguageSerializer() and map it in your GetCompanySerializer as below,
class LanguageSerializer(serializers.ModelSerializer):
class Meta:
fields = '__all__'
model = Language
class GetCompanySerializer(serializers.ModelSerializer):
language = LanguageSerializer(many=True)
class Meta:
model = Company
fields = ('company_name', 'started_from', 'country', 'email', 'website', 'ip', 'active', 'language')
If you wish to get the __str__() reprwesentation of Language model, use StringRelatedField() instead of CharField()class GetCompanySerializer(serializers.ModelSerializer):
language = serializers.StringRelatedField(many=True)
class Meta:
model = Company
fields = ('company_name', 'started_from', 'country', 'email', 'website', 'ip', 'active', 'language')</code></pre>
Related
I have seen many tutorials about nested serializer, but unfortunately I can`t solve this task. Please, give me some tips.
I need to create this JSON
{
"external_id": "11",
"details": [
{
"amount": 7,
"price": "12.00",
"product": {
"name": "Car"
}
}
]
}
My models consist the next relative:
from django.db import models
class Order(models.Model):
NEW = 'new'
ACCEPTED = 'accepted'
FAILED = 'failed'
order_status = [
(NEW, 'new'),
(ACCEPTED, 'accepted'),
(FAILED, 'failed'),
]
status = models.CharField(max_length=12, choices=order_status, default='new', blank=False)
created_at = models.DateTimeField(auto_now_add=True)
external_id = models.CharField(max_length=128)
def __str__(self):
return f'Order № {self.external_id}'
class Product(models.Model):
name = models.CharField(max_length=64)
def __str__(self):
return self.name
class OrderDetail(models.Model):
order = models.ForeignKey(Order, on_delete=models.CASCADE,
related_name='details',
null=True, blank=True)
amount = models.IntegerField(null=True, blank=True)
product = models.ForeignKey(Product, on_delete=models.CASCADE,
related_name='product',
null=True)
price = models.DecimalField(decimal_places=2, max_digits=6, null=True, blank=True)
def __str__(self):
return f'Detail for {self.order}, detail for product {self.product}'
My view
class ProductViewSet(ModelViewSet):
queryset = Product.objects.all()
serializer_class = ProductSerializer
class OrderViewSet(ModelViewSet):
queryset = Order.objects.all()
serializer_class = OrderSerializer
pagination_class = ContentRangeHeaderPagination
class OrderDetailViewSet(ModelViewSet):
queryset = OrderDetail.objects.all()
serializer_class = OrderDetailSerializer
My serializer
class OrderDetailSerializer(serializers.ModelSerializer):
class Meta:
model = OrderDetail
fields = ['id', 'amount', 'price']
depth = 1
class ProductSerializer(serializers.ModelSerializer):
product = OrderDetailSerializer(many=True)
class Meta:
model = Product
fields = ['id', 'name', 'product']
class OrderSerializer(serializers.ModelSerializer):
details = OrderDetailSerializer(many=True)
class Meta:
model = Order
fields = ['id', 'status', 'created_at', 'external_id', 'details']
depth = 2
def create(self, validated_data): # works for first nesting
print(validated_data)
details_data = validated_data.pop('details')
request = Order.objects.create(**validated_data)
for detail_data in details_data: #
products_data = detail_data.pop('product')
request_detail = OrderDetail.objects.create(order=request, **detail_data)
for product_data in products_data:
Product.objects.create(product=request_detail, **product_data)
return request
I have errors when I try to send POST request. => KeyError 'products'
I wanted to get product fields using a loop. But I can't get this field, because I didn't identified it.
My question is: how to receive this field in OrderSerializer.
Thanks for your answers.
The Company table has the basic contact information of the company, and the Address contains the address and geolocation of the company. These two tables are connected with a foreign key named "company_name," which is neither a primary key of both tables. I inserted some mock data of a company named "FF2" into the company table, it went great. However, when I attempted to insert "FF2" with its mock address into the Address table, I failed and received this:
company_name: ["Incorrect type. Expected pk value, received str."]
I tried every solution I found online, but none of them worked. Please help and be specific as possible, thank you so much!!
model.py:
class Address(models.Model):
city = models.CharField(max_length=200)
state = models.CharField(max_length=200)
zip = models.CharField(max_length=20)
address1 = models.CharField(max_length=200)
address2 = models.CharField(max_length=200, blank=True, null=True)
company_name = models.ForeignKey('Company', models.DO_NOTHING, db_column='company_name')
lat = models.DecimalField(max_digits=50, decimal_places=6)
long = models.DecimalField(max_digits=50, decimal_places=6)
class Meta:
managed = False
db_table = 'address'
class Company(models.Model):
company_name = models.CharField(unique=True, max_length=200)
contact_name = models.CharField(max_length=100)
phone = models.CharField(max_length=100)
email = models.CharField(max_length=100)
website = models.TextField()
class Meta:
managed = False
db_table = 'company'
views.py:
class AddressView(APIView):
serializer_class = AddressSerializer
def get(self, request):
address = [ {"city": address.city, "state": address.state, "zip": address.zip, "address1": address.address1, "address2": address.address2, "company_name": address.company_name, "lat": address.lat, "long": address.long}
for address in Address.objects.all()]
return Response(address)
def post(self, request):
serializer = AddressSerializer(data=request.data)
if serializer.is_valid(raise_exception=True):
serializer.save()
return Response(serializer.data)
class CompanyView(APIView):
serializer_class = CompanySerializer
def get(self, request):
company = [ {"company_name": company.company_name, "contact_name": company.contact_name, "phone": company.phone, "email": company.email, "website": company.website}
for company in Company.objects.all()]
return Response(company)
def post(self, request):
serializer = CompanySerializer(data=request.data)
if serializer.is_valid(raise_exception=True):
serializer.save()
return Response(serializer.data)
serializer.py:
class AddressSerializer(serializers.ModelSerializer):
class Meta:
model = Address
fields = ['city', 'state', 'zip', 'address1', 'address2', 'company_name', 'lat', 'long']
class CompanySerializer(serializers.ModelSerializer):
class Meta:
model = Company
fields = ['company_name', 'contact_name', 'phone', 'email', 'website']
I cannot save multiple values for the Foreignkey field when adding instances to the database. I don't understand exactly what the problem is: in my code or in the format of the JSON object being passed.
models.py
class VendorContacts(models.Model):
contact_id = models.AutoField(primary_key=True)
vendor = models.OneToOneField('Vendors', on_delete=models.CASCADE)
contact_name = models.CharField(max_length=45, blank=True)
phone = models.CharField(max_length=45, blank=True)
email = models.CharField(max_length=80, blank=True, unique=True)
class Meta:
db_table = 'vendor_contacts'
class VendorModuleNames(models.Model):
vendor = models.OneToOneField('Vendors', on_delete=models.CASCADE, primary_key=True)
module = models.ForeignKey(Modules, models.DO_NOTHING)
timestamp = models.DateTimeField(auto_now=True)
class Meta:
db_table = 'vendor_module_names'
unique_together = (('vendor', 'module'),)
class Vendors(models.Model):
COUNTRY_CHOICES = tuple(COUNTRIES)
vendorid = models.AutoField(primary_key=True)
vendor_name = models.CharField(max_length=45, unique=True)
country = models.CharField(max_length=45, choices=COUNTRY_CHOICES)
nda = models.DateField(blank=True, null=True)
user_id = models.ForeignKey('c_users.CustomUser', on_delete=models.PROTECT)
timestamp = models.DateTimeField(auto_now_add=True)
class Meta:
db_table = 'vendors'
unique_together = (('vendorid', 'timestamp'),)
serializers.py
class VendorsSerializer(serializers.ModelSerializer):
class Meta:
model = Vendors
fields = ('vendor_name',
'country',
'nda',
'parent_vendor',)
class VendorContactSerializer(serializers.ModelSerializer):
class Meta:
model = VendorContacts
fields = (
'contact_name',
'phone',
'email',)
class VendorModulSerializer(serializers.ModelSerializer):
class Meta:
model = VendorModuleNames
fields = ('module',)
views.py
class VendorsCreateView(APIView):
"""Create new vendor instances from form"""
serializer_class = (VendorsSerializer)
def post(self, request, *args, **kwargs):
vendor_serializer = VendorsSerializer(data=request.data)
vendor_contact_serializer = VendorContactSerializer(data=request.data)
vendor_modules_serializer = VendorModulSerializer(data=request.data)
try:
vendor_serializer.is_valid(raise_exception=True) \
and vendor_contact_serializer.is_valid(raise_exception=True) \
and vendor_modules_serializer.is_valid(raise_exception=True) \
vendor = vendor_serializer.save(user_id=request.user)
vendor_contact_serializer.save(vendor=vendor)
vendor_modules_serializer.save(module= maybe something here?????, vendor=vendor)
except ValidationError:
return Response({"errors": (vendor_serializer.errors,
vendor_contact_serializer.errors,
vendor_modules_serializer.errors
)},
status=status.HTTP_400_BAD_REQUEST)
else:
return Response(request.data, status=status.HTTP_200_OK)
JSON body
{
"vendor_name": "Awrazofgsxsdsxjwszsslsasdjegdzasas",
"country": "Canada",
"module": [
1,
2
],
"NDA date": "",
"contact_name": "Tim",
"email": "teaszt#tesstd.gmail",
"phone": "+3464784594940",
"parent_vendor": "23"
}
When I send JSON, I get the response
{
"module": [
"Incorrect type. Expected pk value, received list."
]
}
Looks like I'm finally confused about multiple saving
Your ForeignKey should be set on the related class Modules.
I have a model Album and a model Photo, which references the first one through a FireignKey field. I want the ModelSerializer for model Album to return a list of hyperlinks to relate entries in model Photo through a lookup field, but I only get it to return a list of ids.
These are my models:
class Album(models.Model):
name = models.CharField(max_length=200, verbose_name=_("Name"))
description = models.TextField(null=True, blank=True, verbose_name=_("Description"))
company = models.ForeignKey(Company, on_delete=models.PROTECT, related_name='albums', verbose_name=_("Company"))
access_code = models.CharField(max_length=30, default=_create_access_code, verbose_name=_("Internal Use"))
class Meta:
verbose_name = _("Album")
verbose_name_plural = _("Albums")
def __str__(self):
return "[{}] {} ({})".format(self.pk, self.name, self.company.id)
class Photo(models.Model):
name = models.CharField(max_length=100, null=True, blank=True, verbose_name=_("Name"))
album = models.ForeignKey(Album, on_delete=models.PROTECT, related_name='photos', verbose_name=_("Album"))
photo = models.ImageField(verbose_name=_("Photo"))
class Meta:
verbose_name = _("Photo")
verbose_name_plural =_("Photos")
def __str__(self):
return "[{}] {}".format(self.pk, self.name)
And this is my serializer:
class AlbumSerializer(serializers.ModelSerializer):
class Meta:
model = proxies.AlbumProxy
fields = ('id', 'name', 'description', 'company', 'access_code', 'photos')
I want the field photos to return a list of hyperlinks, but I get a list of ids:
"id": 1,
"name": "Navidad 2018",
"description": "La primera",
"company": 1,
"access_code": "xxxxxxxxxx",
"photos": [
11,
10,
7,
6
]
I think you need a HyperlinkedRelatedField, something like this:
class AlbumSerializer(serializers.ModelSerializer):
class Meta:
model = proxies.AlbumProxy
fields = (
'id',
'name',
'description',
'company',
'access_code',
'photos'
)
photos = serializers.HyperlinkedRelatedField(
many=True,
view_name='<your-photos-view-name>',
read_only=True
)
If you want your photos full urls you can declare a Serializer Method Field to do something like this:
class AlbumSerializer(serializers.ModelSerializer):
photos_url = serializers.SerializerMethodField()
class Meta:
model = proxies.AlbumProxy
fields = ('id', 'name', 'description', 'company', 'access_code')
def get_photos_url(self, obj):
urls = []
request = self.context.get('request')
for photo in obj.photos:
urls.append(request.build_absolute_uri(photo.url))
return urls
I'm facing a problem using python2.7 with django rest-framework. When I serialize my JSON data, a field is omitted by the serializer and I don't understand why. Here is some details.
The missing field is "country". When I'm doing POST or PUT requests on /campaigns/:id
class CampaignSerializer(serializers.HyperlinkedModelSerializer):
created_by = UserFullSerializer(read_only=True)
country = CountrySerializer(read_only=True)
class Meta:
model = Campaign
fields = ('id', 'created_by', 'name', 'media', 'status', 'begin', 'end', 'country')
class CampaignFullSerializer(serializers.HyperlinkedModelSerializer):
client = ClientSerializer(read_only=True)
collection = CollectionSerializer(read_only=True)
created_by = UserFullSerializer(read_only=True)
updated_by = UserFullSerializer(read_only=True)
channels = ChannelSerializer(read_only=True, many=True)
country = CountrySerializer(read_only=True)
class Meta:
model = Campaign
fields = ('id',
'client',
'name',
'media',
'status',
'begin',
'end',
'created_at',
'created_by',
'updated_at',
'updated_by',
'collection',
'channels',
'country')
class CountrySerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Country
fields = ('id', 'name', 'code')
class Country(models.Model):
name = models.CharField(max_length=255)
code = models.CharField(max_length=255)
class Campaign(models.Model):
name = models.CharField(max_length=255)
media = models.IntegerField(choices=constant.MEDIA_CHOICES, default=0)
status = models.IntegerField(choices=constant.STATUS_CHOICES, default=2)
created_at = models.DateTimeField(auto_now_add=True)
created_by = models.ForeignKey(User, blank=True, null=True, related_name="created_by")
updated_at = models.DateTimeField(auto_now_add=True, blank=True, null=True)
updated_by = models.ForeignKey(User, blank=True, null=True, related_name="updated_by")
client = models.ForeignKey(client.Client)
begin = models.DateField(blank=True, null=True)
end = models.DateField(blank=True, null=True)
collection = models.ForeignKey(collection.Collection, blank=True, null=True)
country = models.ForeignKey(country.Country, blank=True, null=True)
mediaplan = models.ForeignKey(mediaplan.Mediaplan, blank=True, null=True, default=None)
channels = models.ManyToManyField(channel.Channel)
When I'm doing POST on /campaign/id with the following JSON, everything works except the country field.
{
...
"channels": [],
"country": {
"id": 74,
"name": "France",
"code": "FR"
}
On the controller side when I print the request.data I got all the fields. I'm not overriding the create method of the controller.
{
...
u'country': {u'code': u'AL', u'id': 3, u'name': u'Albania'}
}
My controller looks like:
class CampaignViewSet(viewsets.ModelViewSet):
queryset = Campaign.objects.all()
serializer_class = CampaignSerializer
def create(self, request):
logger.info(request.data)
return super(CampaignViewSet, self).create(request, *args, **kwargs)
I tried to override the create method of my CountrySerializer and when I print the content of validated_data, the country field is missing in the OrderedDict..
class CountrySerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Country
fields = ('id', 'name', 'code')
def create(self, validated_data):
logger.info(validated_data)
I'm really lost, I can't find my mistake, maybe you will. Thanks for your time.
Your CountrySerializer is read only as a nested serializer by default (per http://www.django-rest-framework.org/api-guide/relations/#nested-relationships) so you have to override the create/update method of the Campaign serializer for POST/PUT. You've tried to override it on the Country serializer instead.