how to deleting extra OrderItems in Orders admin panel? - django

this is my order admin. when a customer reserve a product it goes to order item section in the down. but there are some extra order items that they are empty. i want to when a customer adds a product just that product be in the admin panel. how i can remove that empty order items???
model:
class Order(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL,
on_delete=models.CASCADE, related_name='orders')
ref_code = models.CharField(max_length=20, blank=True, null=True)
# products = models.ManyToManyField(OrderItem)
address = models.ForeignKey(Address, on_delete=models.SET_NULL, null=True, blank=True, related_name='addresses')
created_date = models.DateTimeField(auto_now_add=True)
ordered_date = models.DateTimeField(null=True, blank=True)
ordered = models.BooleanField(default=False)
def __str__(self):
return self.user.full_name
class OrderItem(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL,
on_delete=models.CASCADE)
order = models.ForeignKey(Order, on_delete=models.CASCADE, related_name='products')
ordered = models.BooleanField(default=False)
product = models.ForeignKey(Product, on_delete=models.CASCADE)
quantity = models.PositiveSmallIntegerField(default=1)
def __str__(self):
return f"{self.quantity} of {self.product.name}"
serializer:
class OrderItemSerializer(serializers.ModelSerializer):
product = serializers.SerializerMethodField()
final_price = serializers.SerializerMethodField()
class Meta:
model = OrderItem
fields = (
'id',
'product',
'quantity',
'final_price'
)
def get_product(self, obj):
return ProductSerializer(obj.product).data
def get_final_price(self, obj):
return obj.get_final_price()
class OrderSerializer(serializers.ModelSerializer):
order_items = serializers.SerializerMethodField()
total = serializers.SerializerMethodField()
class Meta:
model = Order
fields = (
'id',
'order_items',
'total',
)
def get_order_items(self, obj):
return OrderItemSerializer(obj.products.all(), many=True).data
def get_total(self, obj):
return obj.total_price()

You need to change the TabularInline at admin.py file not serializers. extra = 0
class OrderItemInline(admin.TabularInline):
model = OrderItem
extra = 0
#admin.register(Order)
class OrderAdmin(admin.ModelAdmin):
inlines = [OrderItemInline]

Related

Django select_related doesn't optimize query

I have a problem with select_related. I don't know what I'm doing wrong but it doesn't work..
models.py
class OrganizerUser(models.Model):
"""This user manage Agents"""
user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
def __str__(self):
return self.user.username
class Agent(models.Model):
user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
organizer = models.ForeignKey(OrganizerUser, blank=True, null=True,
on_delete=models.CASCADE)
def __str__(self):
return self.user.username
class Lead(models.Model):
first_name = models.CharField(max_length=20)
last_name = models.CharField(max_length=20)
age = models.IntegerField(default=0)
organizer = models.ForeignKey(OrganizerUser, on_delete=models.CASCADE)
agent = models.ForeignKey(Agent, null=True, blank=True, on_delete=models.SET_NULL)
category = models.ForeignKey(
Category, related_name="categories", null=True, blank=True, on_delete=models.SET_NULL
)
description = models.TextField()
date_added = models.DateTimeField(auto_now_add=True)
phone_number = models.CharField(max_length=20)
email = models.EmailField()
converted_date = models.DateTimeField(null=True, blank=True)
def __str__(self):
return f"{self.first_name} {self.last_name}"
views.py
class LeadsApiView(generics.ListCreateAPIView):
serializer_class = LeadSerializer
permission_classes = [IsAuthenticated, IsAdminOrOrganizer]
def get_queryset(self):
user = self.request.user
#if user.is_staff:
#return Lead.objects.select_related('organizer', 'agent').all()
if user.is_organizer:
return Lead.objects.select_related('organizer').filter(
organizer=user.organizeruser)
else:
return Lead.objects.select_related('agent').filter(agent=user.agent)
serializers.py
class LeadSerializer(serializers.ModelSerializer):
class Meta:
model = Lead
fields = ['id', 'first_name', 'last_name', 'age',
'organizer', 'agent', 'category', 'description', 'date_added',
'phone_number', 'email', 'converted_date'
]
for agents everything is fine. Django makes 3 queries but for other users, it makes extra queries for each existing user.
This solution solved the problem
How to always prefetch_related for a specific django model
class UsersManager(models.Manager):
def get_queryset(self):
return super().get_queryset().select_related('user')
class OrganizerUser(models.Model):
"""This user manage Agents"""
user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
objects = UsersManager()
def __str__(self):
return self.user.username
class Agent(models.Model):
user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
organizer = models.ForeignKey(OrganizerUser, blank=True, null=True,
on_delete=models.CASCADE)
objects = UsersManager()
def __str__(self):
return self.user.username

(1048, "Column 'brand_id' cannot be null") in django rest framework

I am trying to create an api where a user can add their products. I am sending raw json data from postman but it is giving this error.
IntegrityError at /api/addproducts
(1048, "Column 'brand_id' cannot be null")
I am sending brand id in the data. I am not sure what is happening.
Here I am sending merchant_id as well as categories ids but why brand field is creating an error I am not sure.
My models:
class Category(models.Model):
name = models.CharField(max_length=100, unique=True)
image = models.ImageField(null=True, blank=True)
class Meta:
verbose_name_plural = "Categories"
def __str__(self):
return self.name
class Brand(models.Model):
brand_category = models.ForeignKey(Category,on_delete=models.CASCADE,blank=True,null=True)
name = models.CharField(max_length=100, unique=True)
image = models.ImageField(null=True, blank=True)
class Meta:
verbose_name_plural = "Brands"
def __str__(self):
return self.name
class Collection(models.Model):
name = models.CharField(max_length=100, unique=True)
image = models.ImageField(null=True, blank=True)
class Meta:
verbose_name_plural = "Collections"
def __str__(self):
return self.name
class Variants(models.Model):
SIZE = (
('not applicable', 'not applicable',),
('S', 'Small',),
('M', 'Medium',),
('L', 'Large',),
('XL', 'Extra Large',),
)
AVAILABILITY = (
('available', 'Available',),
('not_available', 'Not Available',),
)
product_id = models.CharField(max_length=70,default='OAXWRTZ_12C',blank=True)
price = models.DecimalField(decimal_places=2, max_digits=20,default=500)
size = models.CharField(max_length=50, choices=SIZE, default='not applicable',blank=True,null=True)
color = models.CharField(max_length=70, default="not applicable",blank=True,null=True)
variant_image = models.ImageField(upload_to="products/images", blank=True)
thumbnail = ImageSpecField(source='variant_image',
processors=[ResizeToFill(100, 50)],
format='JPEG',
options={'quality': 60})
quantity = models.IntegerField(default=10,blank=True,null=True) # available quantity of given product
variant_availability = models.CharField(max_length=70, choices=AVAILABILITY, default='available')
class Meta:
verbose_name_plural = "Variants"
def __str__(self):
return self.product_id
class Product(models.Model):
merchant = models.ForeignKey(Seller,on_delete=models.CASCADE,blank=True,null=True)
category = models.ManyToManyField(Category, blank=False)
brand = models.ForeignKey(Brand, on_delete=models.CASCADE)
collection = models.ForeignKey(Collection, on_delete=models.CASCADE)
featured = models.BooleanField(default=False) # is product featured?
best_seller = models.BooleanField(default=False)
top_rated = models.BooleanField(default=False)
My serializers:
class BrandSerializer(serializers.ModelSerializer):
# id = serializers.IntegerField()
class Meta:
model = Brand
fields = '__all__'
class AddProductSerializer(serializers.ModelSerializer):
merchant = serializers.PrimaryKeyRelatedField(read_only=True)
class Meta:
model = Product
fields = ['id','merchant','category','brand', 'collection','featured', 'top_rated',
'name','description', 'picture','main_product_image','best_seller',
'rating','availability','warranty','services','variants']
# depth = 1
def create(self, validated_data):
product = Product.objects.create()
return product
My views:
class ProductAddAPIView(CreateAPIView):
permission_classes = [AllowAny]
queryset = Product.objects.all()
serializer_class = AddProductSerializer
i think the problem is in the create function in serializer
class AddProductSerializer(serializers.ModelSerializer):
merchant = serializers.PrimaryKeyRelatedField(read_only=True)
class Meta:
model = Product
fields = ['id','merchant','category','brand', 'collection','featured', 'top_rated',
'name','description', 'picture','main_product_image','best_seller',
'rating','availability','warranty','services','variants']
# depth = 1
def create(self, validated_data):
product = Product.objects.create()
return product
as you didn't pass the validated data so it create an empty object use this instead
def create(self, validated_data):
return Product.objects.create(**validated_data)

Django: ModelForm get ManyToMany Field in clean Function

i have a Model called Order and it's it has manytomanyfield to ProductModel
i want to get the values of selected products in clean function to make some calculations
but i cannot find product field
this is the modelform code
class OrderForm(ModelForm):
class Meta:
model = Order
fields = "__all__"
def clean_points(self):
products = self.cleaned_data["Product"]
print(self.cleaned_data.get(
'product', None))
points = 20
self.set_customer_points(self.cleaned_data["customer"], points=points)
return points
def set_customer_points(self, customer, points=0):
customer.points = customer.points + points
customer.save()
and this is OrderModel
class Order(models.Model):
customer = models.ForeignKey(
Customer, on_delete=models.SET_NULL, null=True)
description = models.TextField(max_length=100)
price = models.DecimalField(decimal_places=2, max_digits=100, )
discount = models.DecimalField(decimal_places=2, max_digits=100)
order_state = models.ForeignKey(
'OrderState', on_delete=models.DO_NOTHING, null=True)
points = models.IntegerField(default=0)
product = models.ManyToManyField(
"product.Product", )
def __str__(self):
return self.customer.name
class Product(models.Model):
name = models.CharField(max_length=100)
description = models.TextField(max_length=100)
price = models.DecimalField(decimal_places=2, max_digits=100)
discount = models.DecimalField(decimal_places=2, max_digits=100)
image = models.ImageField(upload_to="products",)
points = models.IntegerField(default=0)
def __str__(self):
return self.name
Have you tried this (lower case)?
If it doesn't work, print(self.cleaned_data) and see the available fields for debugging.
def clean_points(self):
products = self.cleaned_data.get("product")

How get instance id after save_m2m in admin django

I've method in admin.py
def save_model(self, request, instance, form, change):
user = request.user
instance = form.save(commit=False)
if not change or not instance.created_by:
instance.created_by = user
instance.save()
form.save_m2m()
if instance.send_to_killer:
serializer = OrderSerializer(
instance)
emailClass = Email()
emailClass.sendemail(serializer, 1, instance)
return instance
and other one is
class Email(object):
def sendemail(self, data, sendfrom, instance):
print(instance.id)
orders_item = order_item.objects.filter(order_id=instance.id)
print(orders_item)
for item in orders_item:
print(item.qty)
I received instance.id but not getting orders_item as items are saved after order. so how i can get order items data while saving m2m ??
models are
class Order(models.Model):
date = models.DateField(default=timezone.now)
project = models.ForeignKey(
Project, on_delete=models.CASCADE, limit_choices_to={'is_active': True})
send_to_killer = models.BooleanField(default=False)
send_to_sigler = models.BooleanField(default=False)
created_at = models.DateTimeField(default=timezone.now)
created_by = models.ForeignKey(User, on_delete=models.CASCADE, blank=True)
class order_item(models.Model):
# When a Event is deleted, upload models are also deleted
order = models.ForeignKey(Order, on_delete=models.CASCADE, related_name="order_item",
related_query_name="order_item")
item = models.ForeignKey(
Item, on_delete=models.CASCADE, limit_choices_to={'is_active': True}, blank=True, default="")
qty = models.IntegerField(default=0, blank=True)
price = models.DecimalField(
default=Decimal(0), max_digits=12, decimal_places=2, blank=True)
and serializers of order and order_itemare
class orderItemSerializer(serializers.ModelSerializer):
class Meta:
model = order_item
fields = ['qty', 'price']
class OrderSerializer(serializers.ModelSerializer):
order_items = orderItemSerializer(many=True, read_only=True)
class Meta:
model = Order
fields = ['id', 'date', 'project', 'order_items']
You can do it using a signal.
from django.db.models.signals import m2m_changed
m2m_changed.connect(sendemail, sender=YourTable.YourTable_many_to_many_attribute.through)
For detail, please share your model

Django rest fetch data from bridge model

I want to get all the user details and list of all the roles against the
user details model
My Models
class UserDetail(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE,
related_name='userdetail_user', default='111')
cn = models.CharField(max_length=200)
sn = models.CharField(max_length=200)
u_id = models.CharField(max_length=200)
display_name_cn = models.CharField(max_length=200)
display_name_en = models.CharField(max_length=200)
given_name = models.CharField(max_length=200)
employee_number = models.CharField(max_length=200)
email = models.CharField(max_length=200)
created_at = models.DateTimeField(default=datetime.now, blank=True)
last_login = models.DateTimeField(default=datetime.now, blank=True)
def __str__(self):
return self.given_name
class Role(models.Model):
title = models.CharField(max_length=20)
description = models.CharField(max_length=200)
created_at = models.DateTimeField(default=datetime.now, blank=True)
last_updated = models.DateTimeField(default=datetime.now, blank=True)
status = models.BooleanField(default=True)
def __str__(self):
return self.title
class UserRole(models.Model):
userdetail = models.ForeignKey(UserDetail, on_delete=models.CASCADE,
related_name='userrole_userdetail')
role = models.ForeignKey(Role, on_delete=models.CASCADE)
approver = models.ForeignKey(UserDetail, on_delete=models.SET_NULL,
null=True,
related_name='userrole_userdetail_approver')
created_at = models.DateTimeField(default=datetime.now, blank=True)
last_updated = models.DateTimeField(default=datetime.now, blank=True)
status = models.BooleanField(default=True)
My Serializers
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ('id', 'username', 'email')
class UserRoleSerializer(serializers.ModelSerializer):
class Meta:
model = UserRole
fields = (
'id', 'userdetail', 'role', 'approver', 'last_updated', 'status')
depth = 1
def to_representation(self, instance):
representation = super(UserRoleSerializer, self).to_representation(
instance)
representation['userdetail'] = UserDetailSerializer(
instance.userdetail).data
representation['role'] = RoleSerializer(instance.role).data
representation['approver'] = UserDetailSerializer(
instance.approver).data
return representation
class RoleSerializer(serializers.ModelSerializer):
class Meta:
model = Role
fields = ('id', 'title', 'description', 'last_updated', 'status')
class UserDetailSerializer(serializers.ModelSerializer):
user = UserSerializer()
roles = serializers.SerializerMethodField(read_only=True)
class Meta:
model = UserDetail
fields = ('id', 'roles', 'user', 'cn', 'sn', 'u_id', 'display_name_cn',
'display_name_en', 'given_name', 'employee_number', 'email',
'last_login')
lookup_field = 'u_id'
def get_roles(self, obj):
roles = UserRole.objects.filter(userdetail=obj)
return roles
When I try to fetch all the user details it gives me an error
"Object of type 'UserRole' is not JSON serializable".
I have already tried to serialize the list of object fetched inside get_roles method of UserDetailsSerializer but its no help
In your Serializers, you have to replace
roles = serializers.SerializerMethodField(read_only=True)
With
userrole_userdetail = UserRoleSerializer(many=True, read_only=True)
Its because your FK relation name must match the related name given in the model. Also in UserRoleSerializer you do not need the to_representation method.