customising a model field for serialization - django-models

I am doing a project on django. I have a model EmployeeProfile with several fields along with a field education with following data - (institute, year, course, description).
in model i am storing data in form of a deliminated field.
e.g. a sample value for education - " XYZ colllege | 1994 | Btech | blabla "
But i want to serialize it along with other fields in the dict form i.e.
{ education:{ year: '1994', course: ' Btech', college: ' XYZ ', description: 'blabla'}}
and in future i would also liked to use it as an array deliminated by ';'
but that's not necessarily needed now.
I am new to django restframework...

First you can split the education field value by using split.
Then you can serialize it accordingly.
class CustomModel:
def __init__(self, year,course,college,description):
self.year = year
self.course = course
self.description = description
self.college = college
class CustomSerializer(NonNullSerializer):
year = serializers.IntegerField()
course = serializers.CharField()
description = serializers.CharField()
college = serializers.CharField()
Add this in view.py
education_value = ...
year,course,college,description = education_value.split('|')
education_obj = CustomModel(year=year,course=course,college=college,description=description)
serialized_data = CustomSerializer(education_obj)
return serialized_data.data
Hope this helps

Related

Add M2M field using create(): Django

I have a lot of doubts about managing the M2m field, I finally got a solution to add that data to a model, but there are still some issues, give me a solution to overcome this,
class CourseListSerializer(serializers.ModelSerializer):
instructors = serializers.SerializerMethodField()
image = FileField()
keyarea = CourseKeyAreaSerializer
subject = CourseSubjectsSerializer
sections = serializers.ListField(write_only=True)
beneficiaries = serializers.ListField(write_only=True)
section = CourseSectionSerializers
beneficiary = CourseBeneficiarySerializer
def create(self, validated_data):
data = validated_data
try:
new = Course.objects.create(image=data['image'], name=data['name'], description=data['description'], is_free=data['is_free'],
keyarea=data['keyarea'], subject=data['subject'])
new.save()
beneficiary_data = data['beneficiaries']
new.beneficiary.set(*[beneficiary_data])
section_data = data['sections']
new.section.set(*[section_data])
return new
except Exception as e:
e = "invalid data"
return e
here first creating the "new" object after that to set the M2M field like
"new.beneficiary.set(*[beneficiary_data])"
but is there any way to add beneficiary and section like this
"new = Course.objects.create(image=data['image'],name=data['name'], description=data['description'],is_free=data['is_free'],....)"

How can update field by overriding save method which is in another app models

I have two models Bill and Payment each with 3 fields. Here I want to update field last_price directly when user pay bill. If user pay complete amount then it would be 0. or if user not pay complete amount then remaining amount want to be save in last_price. So here I want to update amount of last_bill directly when user pay bill.
Note: Both models are in separate app
My Fields are:
BillApp/models
Bill(model.Model):
bill_no = models.IntegerField(max_length = 100,primary_key=True)
last_price = models.IntegerField()
Name = models.CharField(max_length = 20)
PaymentApp/models
Payment(model.Model):
id = models.CharField(max_length = 100,primary_key=True)
bill_no = models.ForeignKey(Bill, on_delete = SET_NULL,null=True)
total_amount = models.CharField(max_length = 10)
def save(...):
Update value of Bill.last_price
How do I update value of Bill.last_price in the save method
I tried this for update field last_price
def save(self,*args, **kwargs):
new_last_price = self.total_amount - self.bill_no.last_price
print("new_last_price : ",new_last_price)
bill_detail = Bill.objects.filter(bill_no=self.bill_no).first()
print("bill_detail : ",bill_detail)
try:
with transaction.atomic():
updated_field = bill_detail.save(update_fields = ['last_price'])
print("updated_field : ", updated_field)
super().save(*args, **kwargs)
print(Bill.objects.filter(bill_no=self.bill_no).first().last_price)
except IntegrityError:
print('Exception in save')
I getting correct output of new_last_price and bill_detail..
but updated_field display None ..
How Can I save new value in Bill?
Your save method will save the data and refresh the object instance but will not return the object instance. Use directly show last price.
bill_detail.save(update_fields = ['last_price'])
print(bill_detail.last_price)

Django models - how to think

Fellows,
As my system is becoming complex, I need help to think how to implement complex behavior. I will explain:
I have three models: Purchase, PurchaseDetails, and Stock.
The models is as follows:
class Purchase(models.Model):
def __str__(self):
return self.parceiro_pj.razao_social + ' em ' + str(self.data) + ": " + str(self.soma)
parceiro_pj = models.ForeignKey(ParceiroPJ,blank=True, null=True)
createdat = models.DateTimeField()
data = models.DateField(auto_now=True)
soma = models.DecimalField(max_digits=10, decimal_places=2, default=0.00)
class PurchaseDetails(models.Model):
def __str__(self):
return str(self.parceiro_pj_insumo.insumo.nome) + ' - ' + str(self.quantidade) + ' - ' + str(self.createdat)
purchase = models.ForeignKey(Purchase)
parceiro_pj_insumo = models.ForeignKey(ParceiroPJInsumo)
quantidade = models.IntegerField(blank=False, null=False)
createdat = models.DateField(auto_now=True)
def save(self, *args, **kwargs):
super(PurchaseDetail, self).save(*args, **kwargs) # Call the "real" save() method.
PurchaseDetail.objects.filter(Purchase=self.purchase.id).update(createdat=self.purchase.createdat.date())
itens = PurchaseDetail.objects.filter(compra=self.purchase.id)
valor = 0
for item in itens:
valor = valor + (item.parceiro_pj_insumo.preco * item.quantidade)
no_estoque = Estoque.objects.get(insumo=item.parceiro_pj_insumo.insumo.id)
unidade = Unidade.objects.get(nome=item.parceiro_pj_insumo.insumo.unidade.nome)
qt = no_estoque.quantidade + item.quantidade
volume_peso = no_estoque.volume_peso + (item.quantidade * item.parceiro_pj_insumo.insumo.volume_peso)
Stock.objects.filter(insumo=item.parceiro_pj_insumo.insumo).update(quantidade=qt, unidade=unidade, volume_peso=volume_peso, updatedat=self.purchase.createdat.date())
Purchase.objects.filter(pk=self.purchase.id).update(soma=valor)
Purchase.objects.filter(pk=self.purchase.id).update(data=self.purchase.createdat.date())
class Stock(models.Model):
def __str__(self):
return str(self.insumo.nome) + '(' + str(self.insumo.marca.nome) + ')' + ' - ' + str(self.quantidade)
insumo = models.OneToOneField(Insumo)
quantidade = models.IntegerField(blank=True, null=True)
unidade = models.ForeignKey(Unidade, blank=True, null=True)
volume_peso = models.DecimalField(max_digits=10, decimal_places=2, blank=True, null=True)
updatedat = models.DateField(auto_now=False, blank=True, null=True)
There are related:
a) One Purchase has Many PurchaseDetails; b) Every PurchaseDetail has an effect on Stock. For every PurchaseDetail operation (insert, change, delete) the Stock must be updated.
I figure it out how to make the change on Stock every time a PurchaseDetail is inserted. But for the DELETE and UPDATE, the logic seems to be much more complex.
If I edit PurchaseDetails, the way its made, if I already had an item in the database, it will be calculated again when I save the PurchaseDetails (this model is embbeded with the Purchase form at admin), causing error and updating again the Stock.
I dont know how to implement the right way of doing it.
I have to check if its a new item on PurchaseDetail, or if it is a already existent register before update Stock, I dont know how to do it. Also, I dont know hot tom implement the case when I have to delete PurchaseDetails, and decrease items on Stock.
Anyone can help, please?
You may consider exploring the functionality provided by Django signals, which will provide you with a nice way to implement this type of behavior. Signals can be sent by built-in model methods like __init__() and save(), and are useful when different areas of your application might want to use information about these types of events.
Some of Django's built-in signals include pre_save, post_save, pre_delete, post_delete, etc; it is also straightforward to define and send your own signals.
Looking at a simplified example of what you already have, lets say you wanted to update a particular Stock every time a related PurchaseDetail was saved, for some reason. You might define a method like:
def update_stock(sender, instance, **kwargs):
purchase_details_id = instance.id
# do something here, like update and save a stock
post_save.connect(update_stock, sender=PurchaseDetail)
update_stock is the receiver function which will be called after the save of the PurchaseDetail object.
For further reference:
https://docs.djangoproject.com/en/1.10/ref/signals/

Django - filter by foreign key string

main table:
class example(models.Model):
name = models.CharField('Item Name', max_length=200)
color = models.ManyToManyField(Color)
category = models.ForeignKey(Category)
image = models.ImageField('Item Image',upload_to="example/images/")
Category table:
class Category(models.Model):
catname = models.CharField('Category Name',max_length=100)
How can i query it while filtering the example table according to the category.
This didn't work out:
def list(request, cat):
c = example.object.filter(category = cat)
What should i change to make this filtering work ?
See Django's documentation on related lookups:
def list(request, cat):
c = example.objects.filter(category__catname=cat)

effective counting of objects

I have 2 models:
Category(models.Model):
name = models.CharField(max_length=30)
no_of_posts = models.IntegerField(default=0) # a denormalised field to store post count
Post(models.Model):
category = models.ForeignKey(Category)
title = models.CharField(max_length=100)
desc = models.TextField()
user = models.ForeignKey(User)
pub_date = models.DateTimeField(null=True, blank=True)
first_save = models.BooleanField()
Since I always want to show the no. of posts alongwith each category, I always count & store them every time a user creates or deletes a post this way:
## inside Post model ##
def save(self):
if not pub_date and first_save:
pub_date = datetime.datetime.now()
# counting & saving category posts when a post is 1st published
category = self.category
super(Post, self).save()
category.no_of_posts = Post.objects.filter(category=category).count()
category.save()
def delete(self):
category = self.category
super(Post, self).delete()
category.no_of_posts = Post.objects.filter(category=category).count()
category.save()
........
My question is whether, instead of counting every object, can we not use something like:
category.no_of_posts += 1 // in save() # and
category.no_of_posts -= 1 // in delete()
Or is there a better solution!
Oh, I missed that! I updated the post model to include the relationship!
Yes, a much better solution:
from django.db.models import Count
class CategoryManager(models.Manager):
def get_query_set(self, *args, **kwargs):
qs = super(CategoryManager, self).get_query_set(*args, **kwargs)
return qs.annotate(no_of_posts=Count('post'))
class Category(models.Model):
...
objects = CategoryManager()
Since you didn't show the relationship between Post and Category, I guessed on the Count('posts') part. You might have to fiddle with that.
Oh, and you'll want to get rid of the no_of_posts field from the model. It's not necessary with this. Or, you can just change the name of the annotation.
You'll still be able to get the post count with category.no_of_posts but you're making the database do the legwork for you.

Resources