Django-rest: show non-primary key field - django

Likely this will be a duplicate, but I can't seem to find anything as there's a no useful keywords.
manufacturer is a foreign key in car:
class manufacturer(models.Models):
id = models.AutoField(primary_key=True)
name = models.CharField(unique=True, max_length=64)
class cars(models.Model):
id = models.AutoField(primary_key=True)
name = models.CharField(unique=True, max_length=64)
manufacturer = models.ForeignKey('Manufacturer')
Right now, I have a car api serialized to all fields it contains (id, name, manufacturer). However, the "manufacturer" field shows the ID of the Manufacturer class.
Question: How do I show the name of the manufacturer in the API for car and not the ID of the manufacturer?

I don't have a lot of experience with django-rest-framework but it looks like you need to create a serializer which will customize the converting of your object to JSON ready to return to the user so that the relationship is taken into account.
Put this in manufacture_app/serializers.py:
from rest_framework import serializers
class CarsSerializer(serializers.ModelSerializer):
manufacturer_name = serializers.RelatedField(source='manufacturer')
class Meta:
model = Cars
fields = ('id', 'name', 'manufacturer_name')
and make sure your __unicode__ function returns the correct name:
class Manufacturer(models.Models):
....
def __unicode__(self):
return self.name

Related

How to combine two different models on the basis of user and send a single response- Django Rest Framework

I have two different models in my project. The StudentDetail model has an one-to-one connection with the student-user and the EnrollmentList has a foreign key connection with the student user. I want to combine information from both the models for that specific student-user and send them as as a single response rather than sending different responses. Below are the models and their serializers
StudentDetail/models.py
class StudentDetail(models.Model):
id = models.UUIDField(primary_key=True, editable=False, default=uuid.uuid4)
user = models.OneToOneField(CustomUser, on_delete=models.CASCADE)
name = models.CharField(max_length=100, null=True, blank=True)
StudentDetailSerializer
class StudentDetailSerializer(serializers.ModelSerializer):
class Meta:
model = StudentDetail
fields = "__all__"
Enrollment/models.py
class EnrollmentList(models.Model):
id = models.UUIDField(primary_key=True, editable=False, default=uuid.uuid4)
student = models.ForeignKey(CustomUser, on_delete=models.CASCADE, related_name='student')
EnrollSerializer
class AllReqs(serializers.ModelSerializer):
class Meta:
model = EnrollmentList
fields = ['id','student_name', 'student_parent_name', 'standard', 'applying_for_standard', "board", 'home_tuition', 'address']
Now suppose a request is made, I want to combine the information from the StudentDetail and EnrollmentList for that specific student user to get a serialized data which may look like below example and send this as a single response
{
"student_name": name, #from StudentDetail
"home_tuition": home_tuition #from EnrollmentList
}
Please suggest to me the correct way to do it
Define your serializer like that:
class AllReqs(serializers.ModelSerializer):
student_name = serializers.CharField(source='student.user.name')
class Meta:
model = EnrollmentList
fields = ['id','student_name', 'home_tuition']
additional StudentDetail serializer:
class StudentDetailSerializer(serializers.ModelSerializer):
student_name = serializers.CharField(source='user.name')
home_tuition = serializers.SerializerMethodField()
class Meta:
model = StudentDetail
fields = ['id','student_name', 'home_tuition']
def get_home_tuition(self, obj):
for enrollment in obj.user.students.all():
return enrollment.home_tuition
I kindly ask the questioner to refer to the Django-Rest-Framework documentation. https://www.django-rest-framework.org/

Need to get the Foreign key value instead of ID in the database table using Django

model
class Project(models.Model):
project_name = models.CharField(max_length=20)
client= models.ForeignKey(Client,on_delete=CASCADE,related_name="Client1",default=None)
user=models.ManyToManyField(Default_User,related_name='users',default=None)
description=models.TextField()
type=models.TextField() #dropdown
start_date = models.DateTimeField(max_length=10)
end_date=models.DateTimeField(max_length=10)
technical_contact_name = models.CharField(max_length=30)
email=models.EmailField(max_length=254,default=None)
phone = PhoneField(blank=True)
delivery_head_contact_name=models.CharField(max_length=30)
class Meta:
db_table ='Project'
def __str__(self):
return self.project_name
model
class Job(models.Model):
job_name=models.CharField(max_length=50)
user= models.ForeignKey(Default_User,on_delete=CASCADE)
project = ChainedForeignKey(Project,chained_field="user", chained_model_field="user",related_name='projects',show_all=False, auto_choose=True, sort=True)
date = models.DateField(max_length=10,default=None)
class Meta:
db_table ='Job'
def __str__(self):
return '{}'.format(self.job_name)
serializers
class ProjectSerializers(serializers.ModelSerializer):
class Meta:
model= Project
fields= '__all__'
class Job_Serializers(serializers.ModelSerializer):
job = serializers.StringRelatedField()
class Meta:
model= Job
fields= ('id','job_name','user','project','date','job',)
I need to get the foreign key value displayed in the database table of Job model but as per the above code it is displaying the Foreign key ID. For example I linked the project model in the Job model and in the db table it is showing the Project_id as(1,2,3) but i need to return the values of that id as(app, learning etc). Please help me to get the values of the foreign key value instead of ID in the database table.
The database will by default take the unique field from the model and django provide id as unique key for models. It is for data consistency. So you can let that happen and in job serializera use SerializerMethodField to retrieve the value of project name based on instance of job objects.
Depends on what you want to achieve with it. If it is just to return another field value from project, then you can add it to the serializer as in below example. I am returning project_name as well.
class JobSerializers(serializers.ModelSerializer):
job = serializers.StringRelatedField()
project_name = serializers.SerializerMethodField()
class Meta:
model= Job
fields= ('id','job_name','user','project','date','job', 'project_name')
def get_project_name(self, job):
return job.project.project_name
If you want to return the whole project object then you have to include
project = ProjectSerializers()

Django RestFramework - parent-child model serializer with DB views?

I am trying to implement a serializer that returns a parent record with its children embedded in the response json object.
My model for the parent and child are both based on database views:
class ProductContributorView(models.Model): # its a model of a view
id = models.IntegerField(primary_key=True)
product_id = models.ForeignKey('ProductTitleView', on_delete=models.DO_NOTHING, related_name='contributors')
sequenceNumber = models.IntegerField()
name = models.CharField(max_length=180)
role = models.CharField(max_length=8, null=True)
description = models.CharField(max_length=1408)
class Meta:
managed = False
ordering = ['sequenceNumber',]
class ProductTitleView(models.Model):
id = models.IntegerField(primary_key=True)
isbn = models.CharField(max_length=80)
titleText = models.CharField(max_length=300)
class Meta:
managed = False
ordering = ['titleText', 'isbn',]
Here are the serializers:
class ProductContributorViewSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = ProductContributorView
fields = ('id', 'product_id', 'sequenceNumber', 'name', 'role', 'description')
def create(self, validated_data):
contributor = ProductContributorView.objects.create(
id=validated_data['id'],
product_id=validated_data['product_id'],
sequenceNumber=validated_data['sequenceNumber'],
name=validated_data['name'],
role=validated_data['role'],
description=validated_data['description'])
return contributor
class ProductTitleViewSerializer(serializers.HyperlinkedModelSerializer):
contributors = serializers.PrimaryKeyRelatedField(many=True, read_only=True)
class Meta:
model = ProductTitleView
fields = ('id', 'isbn', 'titleText', 'contributors')
Here are the views:
class ProductTitleViewList(generics.ListAPIView):
queryset = ProductTitleView.objects.all()
serializer_class = ProductTitleViewSerializer
class ProductContributorViewList(generics.ListAPIView):
queryset = ProductContributorView.objects.all()
serializer_class = ProductContributorViewSerializer
The basic idea is to have the contributors - author, illustrator, etc - returned with the book title based on the FK in the ProductContributorView view matching the id in the ProductTitleView.
When I run this, however, I get the following error:
1054, "Unknown column 'jester_productcontributorview.product_id_id' in 'field list'"
I didn't specify product_id_id in the field list, and I've also tried referring to the field as just product in the field list, but it still repeats the _id_id suffix. Hoping someone will point me to documentation where the FK naming conventions are explained or tell me what to change in the field list. Thanks!
You may just want to try renaming that product_id ForeignKey to just product.
This hints to why it may be broken, I suspect it's breaking somewhere in the serializers inspection of your models regarding the naming of the product_id field on the model.
When you define a ForeignKey on a model there are two properties available for that field. One is the property you define, the ForeignKey object, and you should use this to get the related model. Behind the scenes Django also creates another property which appends _id to the the foreign key's name, this property represents the IntegerField on the database which stores the relation. If you were to view the table in psql you will see the _id columns (and in your case, _id_id).

form with manytomany object creation

I'm trying to make own form adding object Announcement
models.py:
class Announcement(models.Model):
person = models.ForeignKey('Person')
source = models.CharField(max_length=30)
date = models.DateField(default=datetime.now())
valid_date = models.DateField(null=True,blank=True)
class Person(models.Model):
names = models.ManyToManyField('Name')
birth_date = models.DateField(null=True, blank=True)
class Name(models.Model):
first_name = models.CharField(max_length=50,blank=True)
middle_name = models.CharField(max_length=50, blank=True)
last_name = models.CharField(max_length=50, blank=True)
(It maybe loos weird, but in my concept each Person can have more than one Name, and also the same Name can be assigned to different Persons)
forms.py
from django import forms
from backoffice.models import Announcement
class AnnouncementForm(forms.ModelForm):
class Meta:
model = Announcement
fields = ('person','signature','organisation','source', 'date')
And everything works perfectly but I have to choose Person from selectbox. And it is expected behaviour.
But in my case i'm definetely sure, that person doesn't exists in base (all announcements are for different person for very long time - so i want to change person select box to three fields, and create new person (with new names) everytime I save the announcement.
I think I know how to save many to many, that's why i don't put the views.py, but I don't know how to set the forms.py to get fields.
I tried
class AnnouncementForm(forms.ModelForm):
class Meta:
model = Announcement
fields = ('person__names__first_name','signature','organisation','source', 'date')
but got Unknown field(s) (person__names__first_name) specified for Announcement
person__name__first_name will not really work in the forms, that only works for the django admin
you have to create a custom field for the first name and then create a logic for saving on either
def clean(self):
// logic here
or
def save(self, commit=True):
// put clean data here
announcement_form = super(AnnouncementForm, self).save(commit=False)
announcement_form.save()

ManyToManyField Serializer throws "This field must be unique" error

I am trying to create a Many-To-Many relationship between two models- Author and Book. My use-case is that I should be able to add a new book to the database with an author that already exists in the database.
models.py
class Author(models.Model):
author_id = models.CharField(max_length=20, primary_key=True)
name = models.CharField(blank=True, null=True)
def __unicode__(self):
return self.name
class Meta:
ordering = ('author_id',)
class Book(models.Model):
title = models.CharField(max_length=50, primary_key=True)
authors = models.ManyToManyField(Author)
def __unicode__(self):
return self.title
class Meta:
ordering = ('title',)
serializers.py
class AuthorSerializer(serializers.ModelSerializer):
class Meta:
model = Author
fields = ('author_id', 'name')
class BookSerializer(serializers.ModelSerializer):
authors = AuthorSerializer(many=True)
class Meta:
model = Book
fields = ('title', 'authors')
def create(self, validated_data):
book = Book.objects.create(name=validated_data['title'])
for item in validated_data['authors']:
author = Author.objects.get(author_id=item['author_id'])
book.authors.add(author)
return book
Let's say my Author table already has an Author:
1, George RR Martin
Now if I want to add a new book with an existing author, this is the request I send using httpie:
http -j POST http://localhost/books title="The Winds of Winter" authors:='[{"author_id":"1"}]'
and when I do, I get this error:
Output Error
{
"authors": [
{
"author_id": [
"This field must be unique."
]
}
]
}
It seems like the AuthorSerializer is being called which checks the provided author_id against the ones in the database already and throws this error.
Any help on this would be appreciated.
Is there a specific reason you have to use a custom PK field?
Django automatically creates primary key fields for you. If you simply delete that field from your model and your serializer (and create/run a migration on your database), you won't have to specify the pk in your POST call from your frontend, and Django will create an AutoField that auto-increments your model's id:
class Author(models.Model):
# Remove this line and run makemigrations.
# author_id = models.CharField(max_length=20, primary_key=True)
name = models.CharField(blank=True, null=True)
def __unicode__(self):
return self.name
class Meta:
ordering = ('author_id',)
If not, consider using an models.AutoField rather than models.CharField for your primary key field, and again, don't include this in your POST call.
Note, that if you already have a big database created, you might have to do some intricate work in your migration, a la this answer: