How to display not id but another value in ForeignKey - python

This is my code for the hotel website
models.py
class Rooms(models.Model):
room = models.BigIntegerField(verbose_name='Комната', unique=True)
category = models.ForeignKey(Category, on_delete=models.CASCADE, verbose_name='Категория', related_name='wer')
room_bool = models.BooleanField(verbose_name='Статус', default=True)
price = models.BigIntegerField(verbose_name='Цена', null=True,blank=True)
class Registrations(models.Model):
room_num = models.ForeignKey(Rooms, on_delete=models.CASCADE, verbose_name='Номер', related_name='ertgdb',
limit_choices_to={'room_bool': True})
first_name = models.CharField(max_length=250, verbose_name='Имя')
last_name = models.CharField(max_length=250, verbose_name='Фамилия')
tel_num = models.BigIntegerField(verbose_name='Номер телефона')
img = models.FileField(verbose_name='Паспорт', null=True, blank=True)
visit_date = models.DateField(default=now, verbose_name='Дата прибытия')
leave_date = models.DateField(blank=True, null=True, help_text='Дата отбытия')
guest_count = models.IntegerField(default=1, verbose_name='Кол-во людей')
room_relevant = models.BooleanField(default=False, verbose_name='Статус')
price = models.BigIntegerField(verbose_name='Цена', default=100)
serializers.py
class RegistrationSer(serializers.ModelSerializer):
class Meta:
model = Registrations
fields = ('id', 'room_num', 'first_name', 'last_name', 'tel_num', 'img',
'visit_date', 'guest_count', 'room_relevant')
I need the room_num field (in the picture) to have not Id but room_num as in the Input form
SlugRelatedField doesn't work because I can't make POST PUT requests later

You can do the following:
class RegistrationSer(serializers.ModelSerializer):
room = serializers.CharField(source="room_num.room")
class Meta:
model = Registrations
fields = ('id', 'room', 'first_name', 'last_name', 'tel_num', 'img',
'visit_date', 'guest_count', 'room_relevant')

Related

How to set Serializer for displaying parent and children as a list DRF?

I'm making an app which is about News
News have an attribute called Category which can be nested
For example:
Human:
--BodyOrgans:
----Hand
Just to make the issue more clear
We need to prepare a way so when making news when we choose Human category,we can access the child which is "BodyOrgan" and when choosing this, accessing "Hand" or other children it might have
This is my models file:
```
class News(models.Model):
PUBLISH_STATUS = (
('P', 'Published'),
('W', 'Waiting for approval'),
('D', 'Draft'),
)
title = models.CharField(max_length=255)
slug = models.SlugField(null=True, blank=True)
sign_image = models.ImageField(upload_to='images', null=True, blank=True)
summary = models.TextField(null=True, blank=True)
description = models.TextField()
created = models.DateTimeField(auto_now_add=True)
modified = models.DateTimeField(auto_now=True)
publish_status = models.CharField(max_length=1, choices=PUBLISH_STATUS, default='D')
publish_time = models.TimeField(null=True, blank=True, default=None)
publish_date = models.DateTimeField(null=True, blank=True, default=None)
author = models.ForeignKey(get_user_model(), on_delete=models.CASCADE)
category = models.ManyToManyField('Category')
tag = models.ManyToManyField('Tag')
def __str__(self):
return self.title
class Category(models.Model):
PUBLISH_CHOICES = (
('A', 'Active'),
('I', 'Inactive'),
)
parent = models.ForeignKey('Category', on_delete=models.PROTECT, null=True, blank=True)
name = models.CharField(max_length=50, null=True)
publish_status = models.CharField(max_length=1, choices=PUBLISH_CHOICES, default='A')
description = models.TextField(null=True, blank=True)
tag = models.ManyToManyField('Tag')
def __str__(self):
return self.name
```
And also Serializer:
class CategorySerializer(ModelSerializer):
class Meta:
model = Category
fields = ['name', 'parent']
list = ListSerializer(
fields=['name', 'parent'],
source='get_parent'
)
#staticmethod
def get_parent(obj):
return obj.parent.name
class NewsSerializer(ModelSerializer):
#staticmethod
def get_title_slug(instance):
return slugify(instance.title)
#staticmethod
def get_user(obj):
return obj.author.username
slug = SerializerMethodField(method_name='get_title_slug', read_only=True)
author = SerializerMethodField(method_name='get_user')
class Meta:
model = News
fields = '__all__'
category = CategorySerializer()
read_only_fields = ['author', 'publish_date', 'publish_time']
I'd be greatful if you could help me out _/_
If you are trying to get categories with their children, first use related_name to access children easier:
parent = models.ForeignKey('Category', on_delete=models.PROTECT, null=True, blank=True, related_name="children")
Then you can access a category children via children key.
Now just use a nested serializer:
class CategoryChildrenSerializer(serializer.ModelSerializer):
class Meta:
model = Category
fields = [...]
class CategorySerializer(ModelSerializer):
children = CategoryChildrenSerializer(many=True)
class Meta:
model = Category
fields = [..., "children"]

Django search_field

How to solve this error? cause
whenever I search the student user I received an error,
error
admin.py
#admin.register(StudentsEnrollmentRecord)
class StudentsEnrollmentRecordAdmin(admin.ModelAdmin):
#inlines = [InLineSubject]
list_display = ('lrn', 'Student_Users', 'Education_Levels', 'Courses', 'Section', 'Payment_Type', 'Discount_Type' ,'School_Year')
#list_select_related = ('Student_Users')
ordering = ('Education_Levels','Student_Users__lrn')
list_filter = ('Student_Users','Education_Levels','Section','Payment_Type')
search_fields = ('Student_Users',)
def lrn(self, obj):
return obj.Student_Users.lrn
my models.py
class StudentsEnrollmentRecord(models.Model):
Student_Users = models.ForeignKey(StudentProfile, related_name='students', on_delete=models.CASCADE,null=True)
School_Year = models.ForeignKey(SchoolYear, related_name='+', on_delete=models.CASCADE, null=True, blank=True)
Courses = models.ForeignKey(Course, related_name='+', on_delete=models.CASCADE, null=True, blank=True)
Section = models.ForeignKey(Section, related_name='+', on_delete=models.CASCADE, null=True,blank=True)
Payment_Type = models.ForeignKey(PaymentType, related_name='+', on_delete=models.CASCADE, null=True)
Discount_Type = models.ForeignKey(Discount, related_name='+', on_delete=models.CASCADE, null=True,blank=True)
Education_Levels = models.ForeignKey(EducationLevel, related_name='+', on_delete=models.CASCADE,blank=True,null=True)
UPDATE models
class StudentProfile(models.Model):
lrn = models.CharField(max_length=500,null=True)
Firstname = models.CharField(max_length=500,null=True,blank=True)
Middle_Initial = models.CharField(max_length=500,null=True,blank=True)
Lastname = models.CharField(max_length=500,null=True,blank=True)
Education_Levels= models.ForeignKey(EducationLevel, on_delete=models.CASCADE,blank=True,null=True)
You need to provide a specific field from StudentProfile - currently your search field is
search_fields = ('Student_Users',)
which means only the model itself. You didn't post a schema of your StudentProfile, but for example if it contains a Lastname field, you should use it like this:
search_fields = ('Student_Users__Lastname',)
To include multiple fields you can do
search_fields = ('Student_Users__Lastname', 'Student_Users__Firstname',)
You could also do
search_fields = ('=Student_Users__Lastname',)
to match the last name "exactly", previous example checks whether the field contains the query string

What determines what fields can be updated in DjangoRestFramework

I currently have a serializer with the following fields
class Meta:
model = Asset
fields = ('id', 'uuid', 'asset_category', 'asset_sub_category',
'make_label',
'asset_code', 'serial_number', 'model_number',
'checkin_status', 'created_at',
'last_modified', 'current_status', 'asset_type',
'allocation_history', 'specs', 'purchase_date',
'notes', 'assigned_to', 'asset_location'
)
Serializer
class AssetSerializer(serializers.ModelSerializer):
checkin_status = serializers.SerializerMethodField()
allocation_history = serializers.SerializerMethodField()
assigned_to = UserSerializer(read_only=True)
asset_category = serializers.SerializerMethodField()
asset_sub_category = serializers.SerializerMethodField()
make_label = serializers.SerializerMethodField()
asset_type = serializers.SerializerMethodField()
model_number = serializers.SlugRelatedField(
queryset=AssetModelNumber.objects.all(),
slug_field="model_number"
)
class Meta:
model = Asset
fields = ('id', 'uuid', 'asset_category', 'asset_sub_category',
'make_label',
'asset_code', 'serial_number', 'model_number',
'checkin_status', 'created_at',
'last_modified', 'current_status', 'asset_type',
'allocation_history', 'specs', 'purchase_date',
'notes', 'assigned_to', 'asset_location'
)
depth = 1
read_only_fields = ("uuid",)
View
class ManageAssetViewSet(ModelViewSet):
serializer_class = AssetSerializer
queryset = Asset.objects.all()
# permission_classes = [IsAuthenticated, IsAdminUser]
# authentication_classes = (FirebaseTokenAuthentication,)
http_method_names = ['get', 'post', 'put', 'delete']
filter_backends = (filters.DjangoFilterBackend,)
filterset_class = AssetFilter
def get_object(self):
queryset = Asset.objects.all()
obj = get_object_or_404(queryset, uuid=self.kwargs['pk'])
return obj
Model
Asset Model. Some fields have been ommited
class Asset(models.Model):
"""Stores all assets"""
uuid = models.UUIDField(unique=True, default=uuid.uuid4, editable=False)
asset_code = models.CharField(
unique=True, null=True, blank=True, max_length=50)
serial_number = models.CharField(
unique=True, null=True, blank=True, max_length=50)
created_at = models.DateTimeField(auto_now_add=True, editable=False)
asset_location = models.ForeignKey('AndelaCentre', blank=True, editable=True, null=True,
on_delete=models.PROTECT)
purchase_date = models.DateField(
validators=[validate_date],
null=True, blank=True)
last_modified = models.DateTimeField(auto_now=True, editable=False)
assigned_to = models.ForeignKey('AssetAssignee',
blank=True,
editable=False,
null=True,
on_delete=models.PROTECT)
model_number = models.ForeignKey(AssetModelNumber,
null=True,
on_delete=models.PROTECT)
current_status = models.CharField(editable=False, max_length=50)
notes = models.TextField(editable=False, default=" ", )
However, on the browsable Api, only 4 fields are showing on the UPDATE/PUT form as shown in the diagram below
What could be the reason some of the other fields are not appearing here. What determines which fields are updatable??
Well, the problem is when you set depth = 1 ModelSerializer tries to generate a NestedSerializer field for any foreignkey related field which you have not explicitly mentioned. And that NestedSerializer field is a read only field. That's why Assest Location is not being displayed. Remove that depth = 1 line and DRF will map the said field with the default mapping i.e. PrimaryKeyRelatedFiel and you will see that the said field is displayed.
In your model, you make editable=False for many fields. That fields won't display. If you want to display and edit that field remove that option.
For more info refer question

nested serialization dont now create a forignkey it requires a new Object instead of 'id'

here is my model, serializer and output but when i want to create a new page it ask me to add a whole new user as its just a foreign-key it need to be a number like 1 (user id) and same in the case of categories how can i solve it.... help me please
serializers.py
class TeamMembersSerializer(serializers.ModelSerializer):
class Meta:
model = TeamMembers
fields = [
'user',
'page',
]
depth = 1
class SocialAccountsSerializer(serializers.ModelSerializer):
social = SocialCatSerializer()
class Meta:
model = SocialAccounts
fields = [
'page',
'social',
'link'
]
depth = 1
class PageImageSerializer(serializers.ModelSerializer):
class Meta:
model = PageImages
fields = [
'page',
'image',
]
depth = 1
class PageSerializer(serializers.ModelSerializer):
owner = UserSerializer()
catagory = BusinessCatSerializers()
business_type = BusinessTypeSerializer()
TeamMembers = TeamMembersSerializer(read_only=True)
social_accounts = SocialAccountsSerializer(read_only=True)
images = PageImageSerializer(read_only=True)
class Meta:
model =Page
fields = [
'id',
'owner',
'catagory',
'name',
'username',
'images',
'start_date',
'business_type',
'contect_number',
'email_address',
'website',
'TeamMembers',
'social_accounts',
'about',
'impression',
'Awards',
'Product',
'privacy_policy',
'is_active',
]
Models.py
class Page(models.Model):
owner = models.ForeignKey(User, on_delete=models.CASCADE)
catagory = models.ForeignKey(BusinessCatagories, on_delete=models.CASCADE, null=True, blank=True, default=None)
name = models.CharField(max_length=254, unique=True ,default=None, blank=True)
username = models.CharField(max_length=254, unique=True, blank=True)
start_date = models.DateTimeField(auto_now_add=True)
business_type = models.ForeignKey(BusinessType, on_delete=models.CASCADE, null=True, blank=True, default=None)
contect_number = models.CharField(max_length=254, default=None, blank=True)
email_address = models.EmailField(default=None, blank=True)
website = models.URLField(default=None, blank=True)
about = models.TextField(default=None, blank=True)
impression = models.TextField(default=None, blank=True)
Awards = models.CharField(max_length=254, default=None, blank=True)
Product = models.CharField(max_length=254, default=None, blank=True)
privacy_policy = models.URLField(default=None, blank=True)
is_active = models.BooleanField(default=True)
def __str__(self):
return self.name
class TeamMembers(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE, default=None, blank=True)
page = models.ForeignKey(Page, on_delete=models.CASCADE, default=None, blank=True)
def __str__(self):
return self.user.name
class SocialAccounts(models.Model):
page = models.ForeignKey(Page, on_delete=models.CASCADE, default=None, blank=True)
social = models.ForeignKey(SocialCats, on_delete=models.CASCADE, default=None, blank=True)
link = models.URLField(default=None, blank=True)
def __str__(self):
return self.link
class PageImages(models.Model):
page = models.ForeignKey(Page, on_delete=models.CASCADE, default=None, blank=True)
image = models.ImageField(default=None, blank=True, upload_to=settings.MEDIA_ROOT)
def __str__(self):
return self.page.name
output is this but i need images field TeamMember field in it but its not appearing plus it want me to add a new user instead of asking for Foreignkey "id"
What you want is to use Primary key related field. It helps you to represent the target of the relationship using its primary key.
It should look somewhat like this.
Note: Mind the typo for any name
class PageSerializer(serializers.ModelSerializer):
owner = serializers.PrimaryKeyRelatedField(queryset = User.objects.all())
catagory = serializers.PrimaryKeyRelatedField(queryset = BuisnessCat.objects.all())
business_type = BusinessTypeSerializer()
TeamMembers = TeamMembersSerializer(read_only=True)
social_accounts = SocialAccountsSerializer(read_only=True)
images = PageImageSerializer(read_only=True)
You can read more about PrimaryKeyRelatedField here.
Now whenever creating any Page, all you need to supply are primary key for owner and category.
You are looking for Writable Nested Serializer.
In short you have to override create() method of PageSerializer
class PageSerializer(serializers.ModelSerializer):
....
....
your code
def create(self, validated_data):
# pop data of every related fields like "owner", "cateagory" etc from validated_data
owner = validated_data.pop("owner")
owner = User.objects.create(**owner)
category = validated_data.pop("category")
# create or retrieve category instance ,as above
...
...
...
# finally
return Page.objects.create(**validated_data,owner=owner,category=category, and other related instances)

DRF use another model related fields in serializer

I have 3 model Product - Peyment - ProductDiscountControll
Peyment and ProductDiscountControll have relation to column "product" to Product table
I want to have related ProductDiscountControll data like discount and discount_code_precent in peyment serilizer at get request.
In quest to do that, I tried following code in my Serializer Class
def get_product_discount(self, obj):
return obj.product.product_discount.discount
but server says :
Field name `product_discount` is not valid for model `Peyment`.
I also tried like this way:
product_discount = ProductDiscountControllSerializer(many=True,read_only=True)
but product_discount not available in result
my view is look like this
class PeymentAPIView(APIView, mixins.DestroyModelMixin):
permission_classes = [IsSafeGuard]
def get(self, request):
pay = Peyment.objects.filter(
email=request.user.email,
status=0,
)
serializer = PeymentSerializer(instance=pay, many=True)
return Response(serializer.data)
this is related Serializer class for get request:
class PeymentSerializer(ModelSerializer):
producttitle = serializers.SerializerMethodField()
def get_producttitle(self, obj):
return obj.product.title
productprice = serializers.SerializerMethodField()
def get_productprice(self, obj):
return obj.product.price
def get_discount(self, obj):
return obj.product_discount.discount
#product_discount = ProductDiscountControllSerializer(many=True,read_only=True)
class Meta:
model = Peyment
fields = [
'product',
'id',
'producttitle',
'productprice',
'discount',
'status',
'user',
'email',
'transfer_id',
'created_date',
'updated_date',
]
read_only_fields = ['email', 'user', 'producttitle', 'productprice']
this is Product model:
class Product(models.Model):
product_id = models.AutoField(primary_key=True)
author = models.ForeignKey(User, on_delete=models.CASCADE, db_index=True)
title = models.CharField(max_length=200)
video_length = models.CharField(max_length=20, null=True, blank=True)
mini_description = models.CharField(max_length=1000, null=True, blank=True)
full_description = models.TextField(null=True, blank=True)
you_need = models.CharField(max_length=1000, null=True)
you_learn = models.CharField(max_length=2000, null=True)
price = models.CharField(max_length=50, null=True, blank=True)
video_level = models.CharField(max_length=100, null=True, blank=True)
created_date = models.DateTimeField(auto_now_add=True)
updated_date = models.DateTimeField(auto_now=True)
image = models.FileField(upload_to=upload_to_custom_p,null=True,blank=True)
Peyment model:
class Peyment(models.Model):
product = models.ForeignKey(Product, on_delete=models.CASCADE, to_field='product_id',
related_name='product_peyment')
status = models.CharField(max_length=30, null=True)
user = models.ForeignKey(User, on_delete=models.DO_NOTHING)
transfer_id = models.CharField(max_length=100, null=True, blank=True)
email = models.EmailField()
created_date = models.DateTimeField(auto_now_add=True)
updated_date = models.DateTimeField(auto_now=True)
and discount model:
class ProductDiscountControll(models.Model):
product = models.OneToOneField(Product, on_delete=models.CASCADE, to_field='product_id',
related_name='product_discount')
discount = models.IntegerField(max_length=50, null=True, blank=True)
discount_code = models.CharField(max_length=50, null=True, blank=True)
discount_code_precent = models.CharField(max_length=80, null=True, blank=True)
updated_date = models.DateTimeField(auto_now=True)
updated :
# product peyment
class PeymentSerializer(ModelSerializer):
producttitle = serializers.SerializerMethodField()
def get_producttitle(self, obj):
return obj.product.title
productprice = serializers.SerializerMethodField()
def get_productprice(self, obj):
return obj.product.price
def get_discount(self, obj):
serializer = ProductDiscountControllSerializer(obj.product.product_discount)
return serializer.data
class Meta:
model = Peyment
fields = [
'product',
'id',
'producttitle',
'productprice',
'discount',
'status',
'user',
'email',
'transfer_id',
'created_date',
'updated_date',
]
read_only_fields = ['email', 'user', 'producttitle', 'productprice']
You can just use product.product_discount field name in serializer's method. To return serialized data you should pass this value to ProductDiscountControllSerializer and return serializer.data:
def get_discount(self, obj):
discount = getattr(obj.product, 'product_discount', None)
if discount:
serializer = ProductDiscountControllSerializer(discount)
return serializer.data
return None
UPD
You should explicitly declare discount field in serializer with SerializerMethodField to use it in fileds list:
class PeymentSerializer(ModelSerializer):
discount = serializers.SerializerMethodField()

Categories

Resources