How to create a subcategory in a category using generics.CreateAPIView? - django-rest-framework

I am trying to create a subcategory under my category. This is my views.py
class CreateSubCategoryViews(generics.CreateAPIView):
queryset = SubCategory.objects.all()
serializer_class = SubCategorySerializer
lookup_field = 'slug'
My urls.py
path('category/<slug:slug>/create/', views.CreateSubCategoryViews.as_view(), name='create-subcategory-views'),
My models.py
class SubCategory(models.Model):
name = models.CharField(max_length=20)
slug = models.SlugField(null=True, blank=True)
category = models.ForeignKey(Category, on_delete=models.CASCADE)
class Meta:
verbose_name_plural = 'SubCategories'
def __str__(self):
return self.name

If You are Dealing with hierarchical data then You can use django-mptt
in Models.py
from mptt.models import MPTTModel
from mptt.managers import TreeManager
class category(MPTTModel):
name = models.CharField(max_length=255, default="", blank=True)
slug = models.SlugField(null=True, blank=True)
parent = models.ForeignKey('self', null=True, blank=True, on_delete=models.SET_NULL, related_name='child')
objects = TreeManager()
class MPTTMeta:
level_attr = 'mptt_level'
order_insertion_by=['name']
in Views.py
class CategoryView(viewsets.ModelViewSet):
queryset = category.objects.all()
serializer_class = categoryTreeSerializer
in Serializers.py
from rest_framework_recursive.fields import RecursiveField
class CategoryTreeSerializer(serializers.ModelSerializer):
child = RecursiveField(many=True, read_only=True)
class Meta:
model = Location
fields = ('id', 'name','slug','parent', 'child',)

Related

Django rest framework save parent records on same model

I have model like this:
class Company(models.Model):
"""Company model"""
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
active = models.BooleanField(default=False, blank=True, null=True)
type = models.JSONField(max_length=200, blank=True, null=True)
name = models.CharField(max_length=200, blank=True, null=True)
alias = models.CharField(max_length=200, blank=True, null=True)
telecom = models.JSONField(max_length=200, blank=True, null=True)
address = models.CharField(max_length=200, blank=True, null=True)
part_of = models.ForeignKey("company.Company", on_delete=models.SET_NULL, null=True,
blank=True, related_name="parent")
created_at = models.DateTimeField(auto_now_add=True, blank=False, null=True)
updated_at = models.DateTimeField(auto_now_add=True, blank=False, null=True)
deleted_at = models.DateTimeField(default=None, blank=True, null=True)
class Meta:
db_table = 'organizations'
def __str__(self):
return self.name
And serializer:
class CompanySerializer(serializers.ModelSerializer):
class Meta:
model = Company
fields = '__all__'
read_only_fields = ("id",)
part_of = serializers.PrimaryKeyRelatedField(queryset=Company.objects.all())
def create(self, validated_data):
part_of = validated_data.pop("part_of")
if part_of:
company_id = Company.objects.create(**part_of)
validated_data['part_of'] = company_id
company = Company.objects.create(**validated_data)
return company
And view:
class CompanyViewSet(viewsets.GenericViewSet, mixins.ListModelMixin, mixins.CreateModelMixin):
serializer_class = serializers.CompanySerializer
queryset = Company.objects.all()
def get_queryset(self):
return self.queryset.all()
def perform_create(self, serializer):
serializer.save()
It is working fine with empty value of "part_of":"", but doesn't work while I pass value for part_of. part_of is basically a parent company which I am trying to create. so my expectation is create a company(part_of) first, get it's id and make that id as foreign key for another company.
Anyone implemented similar to this? Or what I am doing wrong here, suggestions, help is appreciated. Thanks in advance.
The error I am getting is:
{
"part_of": [
"“{ 'name': 'Parent of Organization', 'telecom': [{'system': 'phone', 'value': '677-7777'}, {'system': 'email', 'value': 'customerservice#abc.com'}], 'address': [{'line': ['3300 Washtenaw Avenue, Suite 227'], 'city': 'Amherst', 'state': 'MA', 'postalCode': '01002', 'country': 'USA'}]}” is not a valid UUID."
]
}
I solved this by creating a new serializer for parent company as mentioned in this post:
class ParentCompanySerializer(serializers.ModelSerializer):
class Meta:
model = Company
fields = '__all__'
class CompanySerializer(serializers.ModelSerializer):
"""Serializers for Company objects"""
class Meta:
model = Company
fields = '__all__'
read_only_fields = ("id", )
part_of = ParentCompanySerializer(many=False, read_only=False)
def create(self, validated_data):
part_of = validated_data.pop('part_of') if 'part_of' in validated_data else None
if part_of:
company_id = Company.objects.create(**part_of)
validated_data['part_of'] = company_id
company = Company.objects.create(**validated_data)
return company
Hope this will help someone who stuck in similar situation like me.
I think to make a model also a child os same model we have to do something like -
part_of = models.ForeignKey("self")
and create method should be something like -
def create(self, validated_data):
part_of = validated_data.pop("part_of") ## check if part_of exist in validated data then do this step.
company_id = Company.objects.create(validated_data) ##pop removed part_of data from validated_data so pass validated data here
if part_of:
company = Company.objects.create(part_of = company_id, **part_of)
return company
Well customize it according to your needs.

Show author link using custom user model (DRF)

I have a custom user model via AbstractBaseUser -
class CustomUser(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(_('email address'), unique=True)
is_staff = models.BooleanField(default=False)
is_active = models.BooleanField(default=True)
first_name = models.CharField(max_length=64)
last_name = models.CharField(max_length=64)
created = models.DateTimeField(default=timezone.now)
image = models.ImageField(upload_to=get_user_dir_path,
default='user_placeholder/user_image_placeholder.png')
points = models.IntegerField(default=0)
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['first_name', 'last_name']
objects = CustomUserManager()
def __str__(self):
return self.email
So, I have a second model Post, where I can see "author" filed -
author = models.ForeignKey(CustomUser, on_delete=models.CASCADE)
Then, I created PostsViewSet. Check my serializer -
class PostSerializer(serializers.HyperlinkedModelSerializer):
isFan = serializers.SerializerMethodField()
id = serializers.ReadOnlyField()
created = serializers.DateTimeField(format="%Y-%m-%d %H:%M", read_only=True)
author = serializers.HyperlinkedRelatedField(view_name='user-detail', read_only=True)
class Meta:
model = Post
read_only_fields = ('users',)
fields = '__all__'
def get_isFan(self, obj) -> bool:
user = self.context.get('request').user
if user.is_anonymous:
return None
else:
return services.isFan(obj, user)
After this, when I create a post, I take an error -
Could not resolve URL for hyperlinked relationship using view name "user-detail". You may have failed to include the related model in your API, or incorrectly configured the lookup_field attribute on this field.
How to fix it?
The serializers.HyperlinkedRelatedField try to find the URL API to which the specific author can be retrieved, according to your URL schema.
You may have wrongly config your urls.py

How to serialize model fields related through foreign key?

I want to serialize the name field from Bank Model in BranchSerializer. The id field is a foreign key in the branch model.
I have tried RelatedField :
class BankSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Bank
class BranchSerializer(serializers.HyperlinkedModelSerializer):
bank_name = serializers.RelatedField(source=Bank, read_only=True)
class Meta:
model = Branch
fields = ('ifsc', 'branch', 'address', 'city', 'district', 'state', 'bank_name')
Model:
class Bank(models.Model):
name = models.TextField()
id = models.IntegerField(unique=True, primary_key=True)
class Meta:
db_table = 'banks'
managed = False
def __str__(self):
return self.name
bank = Bank()
class Branch(models.Model):
ifsc = models.CharField(max_length=20, null=False, primary_key=True)
bank = models.ForeignKey(Bank, on_delete=models.CASCADE)
branch = models.CharField(max_length=50)
address = models.TextField()
city = models.CharField(max_length=20)
district = models.CharField(max_length=30)
state = models.CharField(max_length=20)
class Meta:
db_table = 'branches'
managed = False
def __str__(self):
return '{} {}'.format(self.branch, bank.name)
Serializer:
from rest_framework import serializers
from records.models import Bank, Branch
class BankSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Bank
class BranchSerializer(serializers.HyperlinkedModelSerializer):
bank_name = serializers.RelatedField(source=Bank, read_only=True)
class Meta:
model = Branch
fields = ('ifsc', 'branch', 'address', 'city', 'district', 'state', 'bank_name')
TypeError: argument of type 'ModelBase' is not iterable

DRF Serializer Reverse Relation with link table

I would like to find all TargetedExperiments for a given Gene, filtered by the Gene.symbol.
I am still relatively new to Python and DRF, apologies if there is an obvious solution or I did not add any crucial information.
I found a lot of examples where the tables are directly linked, but none with a linking table. I tried using "through" in the Gene table, but then got in a pickle with the order of the tables.
Model
class Gene(models.Model):
gene_id = models.AutoField(primary_key=True)
ensembl_id = models.CharField(max_length=255, null=True, blank=True)
symbol = models.CharField(max_length=255)
synonyms = models.CharField(max_length=255, blank=True, null=True)
description = models.CharField(max_length=255, blank=True, null=True)
class Meta:
managed = True
db_table = 'gene'
class TargetedExperiment(models.Model):
targeted_experiment_id = models.AutoField(primary_key=True)
study = models.ForeignKey(Study, models.DO_NOTHING)
sgrna_sequence = models.ForeignKey(SgrnaSequence, models.DO_NOTHING, blank=True, null=True)
metric = models.ForeignKey(Metric, models.DO_NOTHING)
sgrna_label = models.CharField(max_length=50, blank=True, null=True)
sgrna_efficiency = models.CharField(max_length=255, default='0%')
transgene = EnumField(choices=['Yes', 'No'],default='No')
class Meta:
managed = True
db_table = 'targeted_experiment'
class TargetedExperimentGene(models.Model):
targeted_experiment_gene_id = models.AutoField(primary_key=True)
targeted_experiment = models.ForeignKey(TargetedExperiment, models.DO_NOTHING)
gene = models.ForeignKey(Gene, models.DO_NOTHING)
reported_name = models.CharField(max_length=255)
class Meta:
managed = True
db_table = 'targeted_experiment_gene'
class GeneViewSet(viewsets.ReadOnlyModelViewSet):
queryset = Gene.objects.all()
serializer_class = GeneSerializer
Serializer
class GeneSerializer(base_serializer.ObjectSerializer):
class Meta:
model = Gene
fields = '__all__'
depth = 3
base_serializer (Overwrite NULL with '')
from rest_framework import serializers
class ObjectSerializer(serializers.ModelSerializer):
def to_representation(self, instance):
data = super().to_representation(instance)
return {key: ('' if data[key] is None else value) for key, value in data.items()}

Reverse field to serializer DRF

I have models:
class Order(models.Model):
user = models.ForeignKey('accounts.User', blank=True, null=True)
first_name = models.CharField(max_length=20)
last_name = models.CharField(max_length=20)
class Reservation(models.Model):
start = models.DateTimeField(db_index=True)
end = models.DateTimeField(db_index=True)
order = models.ForeignKey(Order, related_name='reservations')
and serializer:
class ReservationSerializer(serializers.HyperlinkedModelSerializer):
order_first_name = serializers.CharField(read_only=True)
order_last_name = serializers.CharField(read_only=True)
order_id = serializers.IntegerField(read_only=True)
class Meta:
model = Reservation
fields = ('id',
'start',
'end',
'order',
'order_first_name',
'order_last_name',
'order_id',
)
read_only_fields = ('order', 'order_first_name', 'order_last_name', 'order_id')
The problem is I can't see both order_first_name and order_last_name in API response as well as no errors.
Ok, this works
order_first_name = serializers.ReadOnlyField(source='order.first_name', read_only=True)

Resources