How to convert an object serialized from a model to another object serialized to another model? - django-rest-framework

I am new to Django rest framework and vuejs and I am training by doing a CRM.
I have a model lead with leadnote and serializer and another model client with note and serializer. To convert a lead to a client, I made it with #api view in client views :
#api_view(['POST'])
def convert_lead_to_client(request):
company = Company.objects.filter(members__in=[request.user]).first()
lead_id = request.data['lead_id']
try:
lead = Lead.objects.filter(company=company).get(pk=lead_id)
except Lead.DoesNotExist:
raise Http404
client = Client.objects.create(company=company, name=lead.lead_company, contact_person=lead.contact_person, email=lead.email, phone=lead.phone, website=lead.website, created_by=request.user)
return Response()
It allow to convert the lead into client but I would like also to create note for the client that are the lead notes. Do you have any idea how I could implement that ?
Thanks
**For info : **
**Model Lead and LeadNote:**
class Lead(models.Model):
NEW = 'new'
CONTACTED = 'contacted'
INPROGRESS = 'inprogress'
LOST = 'lost'
WON = 'won'
CHOICES_STATUS = (
(NEW, 'New'),
(CONTACTED, 'Contacted'),
(INPROGRESS, 'In progress'),
(LOST, 'Lost'),
(WON, 'Won'),
)
LOW = 'low'
MEDIUM = 'medium'
HIGH = 'high'
CHOICES_PRIORITY = (
(LOW, 'Low'),
(MEDIUM, 'Medium'),
(HIGH, 'High'),
)
company = models.ForeignKey(Company, related_name='leads', on_delete=models.CASCADE)
lead_company = models.CharField(max_length=255)
contact_person = models.CharField(max_length=255)
email = models.EmailField()
phone = models.CharField(max_length=255)
website = models.CharField(max_length=255, blank=True, null=True)
confidence = models.IntegerField(blank=True, null=True)
estimated_value = models.IntegerField(blank=True, null=True)
status = models.CharField(max_length=25, choices=CHOICES_STATUS, default=NEW)
priority = models.CharField(max_length=25, choices=CHOICES_PRIORITY, default=MEDIUM)
assigned_to = models.ForeignKey(User, related_name='assignedleads', blank=True, null=True, on_delete=models.SET_NULL)
created_by = models.ForeignKey(User, related_name='leads', on_delete=models.CASCADE)
created_at = models.DateTimeField(auto_now_add=True)
modified_at = models.DateTimeField(auto_now=True)
class LeadNote(models.Model):
company = models.ForeignKey(Company, related_name='lead_notes', on_delete=models.CASCADE)
lead = models.ForeignKey(Lead, related_name='lead_notes', on_delete=models.CASCADE)
name = models.CharField(max_length=255)
body = models.TextField(blank=True, null=True)
created_by = models.ForeignKey(User, related_name='lead_notes', on_delete=models.CASCADE)
created_at = models.DateTimeField(auto_now_add=True)
modified_at = models.DateTimeField(auto_now=True)
**Model Client and Note** :
class Client(models.Model):
company = models.ForeignKey(Company, related_name='clients', on_delete=models.CASCADE)
name = models.CharField(max_length=255)
contact_person = models.CharField(max_length=255)
email = models.EmailField()
phone = models.CharField(max_length=255)
website = models.CharField(max_length=255, blank=True, null=True)
created_by = models.ForeignKey(User, related_name='clients', on_delete=models.CASCADE)
created_at = models.DateTimeField(auto_now_add=True)
modified_at = models.DateTimeField(auto_now=True)
class Note(models.Model):
company = models.ForeignKey(Company, related_name='notes', on_delete=models.CASCADE)
client = models.ForeignKey(Client, related_name='notes', on_delete=models.CASCADE)
name = models.CharField(max_length=255)
body = models.TextField(blank=True, null=True)
created_by = models.ForeignKey(User, related_name='notes', on_delete=models.CASCADE)
created_at = models.DateTimeField(auto_now_add=True)
modified_at = models.DateTimeField(auto_now=True)

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.

DRF common models and foreign key

I am trying to use some common attributes for all my objects in the DB like created_by, updated_by, created_when and updated_when.
So I created a class for the common attributes:
class CommonModel(models.Model):
"""Common fields that are shared among all models."""
created_by = models.ForeignKey(settings.AUTH_USER_MODEL,on_delete=models.PROTECT,
editable=False, related_name="+")
updated_by = models.ForeignKey(settings.AUTH_USER_MODEL,on_delete=models.PROTECT,
editable=False, related_name="+")
created_at = models.DateTimeField(auto_now_add=True,
editable=False)
updated_at = models.DateTimeField(auto_now=True,
editable=False)
Then I refer to the common model in my models:
class Tag(CommonModel):
"""Tag to be used for products"""
name = models.CharField(max_length=255)
def __str__(self):
return self.name
class Vendor(CommonModel):
"""Vendor to be used for products"""
name = models.CharField(max_length=255, unique=True)
def __str__(self):
return self.name
But when I refer to the tag or vendors in another model as foreign_key then I get an error while executing the migration.
class Product(CommonModel):
"""Model for the type of a product"""
product_id = models.CharField(max_length=255, unique=False)
description = models.CharField(max_length=255, unique=False, null=True, blank=True, default='')
vendor = models.ForeignKey(Vendor, blank=False, null=False, on_delete=models.SET_DEFAULT)
tag = models.ForeignKey(Tag, null=True, blank=True, on_delete=models.SET_NULL)
Error message:
SystemCheckError: System check identified some issues:
ERRORS:
core.Product.tag: (models.E006) The field 'tag' clashes with the field 'tag' from >model 'core.commonmodel'.
core.Product.vendor: (models.E006) The field 'vendor' clashes with the field 'vendor' from model 'core.commonmodel'.
It was working fine before I introduced the common models.
You need to set abstract in Meta, after that it should work fine.
class CommonModel(models.Model):
"""Common fields that are shared among all models."""
created_by = models.ForeignKey(settings.AUTH_USER_MODEL,on_delete=models.PROTECT,
editable=False, related_name="+")
updated_by = models.ForeignKey(settings.AUTH_USER_MODEL,on_delete=models.PROTECT,
editable=False, related_name="+")
created_at = models.DateTimeField(auto_now_add=True,
editable=False)
updated_at = models.DateTimeField(auto_now=True,
editable=False)
class Meta:
abstract = True

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

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