Django join unmanaged tables - django

I have a four models which each contains their own data. The models are:
Category (contains department_id foreign key)
Department (contains data, no foreign key)
ProductCategory (join table containing only product_id and category_id)
Product (contains data with no foreign key)
# models.py (excluded the rest for brevity)
from django.db import models
class Department(models.Model):
department_id = models.AutoField(primary_key=True)
name = models.CharField(max_length=100)
description = models.CharField(max_length=1000, blank=True, null=True)
class Meta:
managed = False
db_table = 'department'
class Category(models.Model):
category_id = models.AutoField(primary_key=True)
#department_id = models.IntegerField()
department = models.ForeignKey(Department, on_delete=models.CASCADE)
name = models.CharField(max_length=100)
description = models.CharField(max_length=1000, blank=True, null=True)
class Meta:
managed = False
db_table = 'category'
class Product(models.Model):
product_id = models.AutoField(primary_key=True)
name = models.CharField(max_length=100)
description = models.CharField(max_length=1000)
price = models.DecimalField(max_digits=10, decimal_places=2)
discounted_price = models.DecimalField(max_digits=10, decimal_places=2)
image = models.CharField(max_length=150, blank=True, null=True)
image_2 = models.CharField(max_length=150, blank=True, null=True)
thumbnail = models.CharField(max_length=150, blank=True, null=True)
display = models.SmallIntegerField()
class Meta:
managed = False
db_table = 'product'
class ProductCategory(models.Model):
product = models.ForeignKey(Product, on_delete=models.CASCADE)
category = models.ForeignKey(Category, on_delete=models.CASCADE)
class Meta:
managed = False
db_table = 'product_category'
unique_together = (('product', 'category'),)
From my endpoint, I need to get all products in a department and return the response in the following format:
​"rows"​: [
{
​ "product_id"​: ​integer​,
"name"​: ​string​,
​"description"​: ​string​,
"price"​: ​string​,
​"discounted_price"​: ​string​,
"thumbnail"​: ​string​
}
]
This is the endpoint:
path('products/inDepartment/<int:department_id>/', ProductViewSet.as_view({"get": "get_products_by_department"}))
How can I go about doing this? I'm stuck with the code below:
# products.py
def get_products_by_department(self, request, department_id):
"""
Get a list of Products of Departments
"""
categories = Category.objects.filter(department_id=department_id).values('category_id')
for item in categories:
category_id = item['category_id']
products = ProductCategory.objects.filter(category_id=category_id).values(
'product_id', name=F('product__name'), description=F('product__description'),
price=F('product__price'), discounted_price=F('product__discounted_price'), thumbnail=F('product__thumbnail'))
# Return response
if products.exists():
return Response(products, 200)
else:
return Response(products, 204)
The code above works and gives me the correct response but I'm not sure if I'm doing the query correctly? Should I be using a loop or is there a Django way to do it better without a loop?

Django's ORM allows for reverse relationship lookup.
https://docs.djangoproject.com/en/2.2/topics/db/queries/#lookups-that-span-relationships
categories = Category.objects.filter(department_id=department_id)
products = Product.objects.filter(productcategory__category__in=categories)

Related

labeling in Django Admin

I am new to Django and still learning, I have created a database and some models but I got stuck with meaningful labels in Django Admin. This is the model:
class Product(models.Model):
product_id = models.AutoField(primary_key=True)
product_name = models.CharField(max_length= 50)
brand_name = models.CharField(max_length = 20)
category = models.ForeignKey(Category, on_delete=models.SET_NULL, null=True)
min_order = models.IntegerField()
max_order = models.IntegerField()
units = models.IntegerField()
quantity = models.ForeignKey(Quantity, on_delete=models.SET_NULL, null=True)
objects = ProductManager()
class Meta:
verbose_name = "Product"
verbose_name_plural = 'Products'
And I get this:
I want Product object (3) to be replaced byt the product_name. Thank you in advance!
You can override the __str__ method [python-doc] and return the product_name instead:
class Product(models.Model):
# …
def __str__(self):
return self.product_name

I am getting invalid keyword argument while posting product array in customer order. What should i do?

First i was getting an error like to create an explicit create method while serializing an array of product. So i added it but stiil im getting thhis error :
TypeError: 'customerorder' is an invalid keyword argument for this function
This is my serializers.py
class ProductSerializer(serializers.ModelSerializer):
product_id = serializers.IntegerField(required=False)
class Meta:
model = Product
fields = '__all__'
class CustOrderSerializer(serializers.ModelSerializer):
price = serializers.SlugRelatedField(slug_field='price', queryset=Price.objects.all())
# product = serializers.SlugRelatedField(slug_field='product', queryset=Product.objects.all())
area = serializers.SlugRelatedField(slug_field='address', queryset=Area.objects.all())
city = serializers.SlugRelatedField(slug_field='city', queryset=City.objects.all())
product = ProductSerializer(many=True)
class Meta:
model = CustOrder
fields = '__all__'
def create(self, validated_data):
product = validated_data.pop('product')
customerorder = CustOrder.objects.create(**validated_data)
for product in product:
Product.objects.create(**product, customerorder= customerorder)
return customerorder
This is models.py
class Product(models.Model):
product_id = models.AutoField(primary_key=True)
product = ArrayField(models.CharField(max_length=200, blank=True))
def __str__(self):
return str(self.product)
class CustOrder(models.Model):
Customer_id = models.AutoField(primary_key=True)
CustomerName = models.CharField(max_length=200)
email = models.EmailField(max_length=70,blank=True, null= True, unique= True)
gender = models.CharField(max_length=6, choices=GENDER_CHOICES)
phone = PhoneField(null=False, blank=True, unique=True)
landmark = models.PointField()
#landmark = models.TextField(max_length=400, help_text="Enter the landmark", default='Enter landmark')
houseno = models.IntegerField(default=0)
#product_name = models.CharField(max_length=200, choices=PRODUCT_CHOICES,default='Boneless chicken')
# product_id = models.ForeignKey(Product, on_delete=models.CASCADE,related_name='custorder_productid')
product = models.ManyToManyField(Product, blank=True,related_name='pricetag')
quantity = models.IntegerField(default=0)
# price_id = models.ForeignKey(Price)
price = models.ForeignKey(Price, on_delete=models.SET_NULL, null=True,related_name='pricetag')
#price = models.DecimalField(max_digits=50, decimal_places=5, default=48.9)
pay_method = models.CharField(max_length=200,choices=PAYMENT_CHOICES, default='RAZOR PAY')
city = models.ForeignKey(City, on_delete=models.SET_NULL, null=True)
area = models.ForeignKey(Area, on_delete=models.SET_NULL, null=True)
# Price.objects.aggregate(Sum('price'))
def __str__(self):
return self.CustomerName
There are several errors here.
Firstly for some reason you've set the related name from Product back to CustOrder as pricetag. That name does not appear to relate to either side of the relationship, so not sure why you've used it.
However even with that change, it still won't work, because you can't set many-to-many relationships at create time. You would need to create the product and then add it to the order.
But that still makes no sense, because you don't actually want to be creating products at all here; you want to add existing products to the order. So just do that:
customerorder = CustOrder.objects.create(**validated_data)
customerorder.product.add(*product)
Your Product model has not field customerorder. That is the reason why Django raises the error.

Django Rest Framework- foreign key throwing error

I am using django rest framework wherein the model has composite primary key, one of the them being a foreign key.
models/TestSuite.py
class TestSuite(models.Model):
team_name = models.ForeignKey('Team', on_delete=models.DO_NOTHING, db_column='team_name')
suite_name = models.CharField(max_length=100)
description = models.CharField(max_length=200, blank=True, null=True)
schedule = models.CharField(max_length=100, blank=True, null=True)
email_list_ok = models.CharField(max_length=200, blank=True, null=True)
email_list_fail = models.CharField(max_length=200, blank=True, null=True)
template_name = models.ForeignKey('EmailTemplates', on_delete=models.DO_NOTHING, db_column='template_name')
class Meta:
managed = False
db_table = 'test_suite'
unique_together = (('team_name', 'suite_name'),)
models/Team.py
class Team(models.Model):
team_name = models.CharField(primary_key=True, max_length=30)
description = models.CharField(max_length=100, blank=True, null=True)
class Meta:
managed = False
db_table = 'team'
TestSuiteSerializer.py
class Meta:
model = models.TestSuite
fields = '__all__'
TestSuiteViewSet.py
class TestSuiteViewSet(viewsets.ModelViewSet):
queryset = models.TestSuite.objects.all()
serializer_class = serializers.TestSuiteSerializer
def create(self, request, *args, **kwargs):
serializer = self.get_serializer(data=request.data,
many=isinstance(request.data, list))
serializer.is_valid(raise_exception=True)
self.perform_create(serializer)
headers = self.get_success_headers(serializer.data)
return Response(serializer.data,
status=status.HTTP_201_CREATED, headers=headers)
Now when I do a post request, it throws below errors
When the post() has team_name already existing in team table
{
"team_name": [
"test suite with this team name already exists."
]
}
When the post() has team_name not existing in team table
Exception Type: ValueError
Exception Value:
Cannot assign "'dummy'": "TestSuite.team_name" must be a "Team" instance.
Can someone please help me here. I am assuming I am missing something.
The first argument to your foreign key fields should be the model itself, not a string of the model (eg. not 'Team', but Team - likewise for EmailTemplate)
class TestSuite(models.Model):
# Change this field's first argument from a string to the Team class
team_name = models.ForeignKey(Team, on_delete=models.DO_NOTHING, db_column='team_name')
suite_name = models.CharField(max_length=100)
description = models.CharField(max_length=200, blank=True, null=True)
schedule = models.CharField(max_length=100, blank=True, null=True)
email_list_ok = models.CharField(max_length=200, blank=True, null=True)
email_list_fail = models.CharField(max_length=200, blank=True, null=True)
# Change this field's first argument from a string to the EmailTemplates class
template_name = models.ForeignKey(EmailTemplates, on_delete=models.DO_NOTHING, db_column='template_name')
class Meta:
managed = False
db_table = 'test_suite'
unique_together = (('team_name', 'suite_name'),)

Django REST: How to filter related set?

I'm trying to create a Serializer which contains cities and for every city list of trips which belongs to the current user. The problem is that I'm getting all trips, not just users ones.
My expectation for example if user was two times in London and once in Prague:
[{<serialized London>,'trips':[<serialized the two London trips>]},
{<serialized Prague>, 'trips':[<serialized one trip to Prague]}]
Now I'm getting all trips connected with the city.
Models:
class City(models.Model):
place_id = models.CharField(max_length=1000, unique=True, null=True, blank=True)
lat = models.DecimalField(max_digits=6, decimal_places=3, db_index=True, null=True, blank=True)
lng = models.DecimalField(max_digits=6, decimal_places=3, db_index=True, null=True, blank=True)
class Trip(models.Model):
user = models.ForeignKey('auth.User', related_name='trips')
city = models.ForeignKey('locations.City', related_name='trips')
date_from = models.DateField(default=now)
date_to = models.DateField(default=now)
detail = models.TextField(null=True, blank=True)
View:
def ajax_get_my_trips(request):
trips = Trip.objects.filter(user=request.user)
cities = City.objects.filter(trips__in=trips)
response = MyCityTripsSerializer(cities,many=True).data
return JsonResponse(response, safe=False)
Serializers:
class MyTripsSerializer(serializers.ModelSerializer):
class Meta:
model = Trip
fields = ('date_from', 'date_to', 'detail')
def get_queryset(self):
user = self.request.user
return Trip.objects.filter(user=user)
class MyCityTripsSerializer(serializers.ModelSerializer):
trips = MyTripsSerializer(many=True)
class Meta:
model = City
fields = ('place_id', 'lat', 'lng', 'number_of_users_here_now', 'formatted_address', 'trips')
Do you know how to make it work?
class MyTripsSerializer(serializers.ModelSerializer):
user = serializers.PrimaryKeyRelatedField(queryset=UserModel.objects.all())
city = serializers.PrimaryKeyRelatedField(queryset=City.objects.all())
class Meta:
model = Trip
fields = ('date_from', 'date_to', 'detail')
def get_queryset(self):
user = self.request.user
return Trip.objects.filter(user=user)
class MyCityTripsSerializer(serializers.ModelSerializer):
trips = MyTripsSerializer(many=True)
class Meta:
model = City
fields = ('place_id', 'lat', 'lng', 'number_of_users_here_now', 'formatted_address', 'trips')
class Trip(models.Model):
user = models.ForeignKey('auth.User', related_name='user_trips')
city = models.ForeignKey('locations.City', related_name='trips')
date_from = models.DateField(default=now)
date_to = models.DateField(default=now)
detail = models.TextField(null=True, blank=True)
Related name must be unique for every ForeignKey.

django model ManyToManyField field join

--models.py--
class Products(models.Model):
name= models.CharField(max_length=120, unique=True)
slug = models.SlugField(unique=True)
price = models.IntegerField(default=100)
image1 = models.ImageField(upload_to='static/images/home', blank=True, null=True)
class Cart(models.Model):
user = models.ForeignKey(User, null=True, blank=True)
product = models.ManyToManyField(Products, blank=True)
--views.py--
#login_required
def cart(request):
try:
cart_user = Cart.objects.filter(user = request.user)
except:
cart_user = False
if cart_user != False:
j = Products.objects.filter(pk=Cart.objects.filter(user=request.user)) #Not getting results in j
now i want the list of products which is selected by user form Cart Model when he or she is logged in.
how to apply join in two models so that i get all the product list in 'p' variable which is in Cart.product model. Thanks
Shang Wang was right about model naming. Let's use those.
class Product(models.Model):
name= models.CharField(max_length=120, unique=True)
slug = models.SlugField(unique = True)
price = models.IntegerField(default=100)
image1 = models.ImageField(upload_to='static/images/home',blank=True,null=True)
class Cart(models.Model):
user = models.ForeignKey(User,null=True, blank=True)
products = models.ManyToManyField(Product, blank=True)
Now you can use filters like this.
products = Product.objects.filter(cart__user__id=1)
carts = Cart.objects.filter(articles__name__startswith="Something").distinct()