Django model related field set - django

I've got a small problem I can't seem to figure out.
I've got the following model:
class UserWhale(models.Model):
currencyPair = models.ForeignKey('currencies.CurrencyPair', verbose_name='Currency Pair')
currency = models.ForeignKey('currencies.Currency', verbose_name='Source Currency')
currencyTarget = models.ForeignKey('currencies.Currency', related_name='whale_currency_target_rel', verbose_name='Target Currency')
userBankAccount = models.ForeignKey(UserBankAccount, verbose_name='Deposit Bank Account')
whale_fee_percentage = models.DecimalField(max_digits=11, decimal_places=2)
whale_amount = models.DecimalField(max_digits=11, decimal_places=2)
whale_matched = models.DecimalField(max_digits=11, decimal_places=2)
priority = models.IntegerField()
user = models.ForeignKey('auth.User', related_name='whale_relation_user', editable=False)
created_by = models.ForeignKey('auth.User', editable=False)
created = models.DateTimeField(auto_now_add=True, editable=False)
modified = models.DateTimeField(auto_now=True, editable=False)
history = audit.AuditTrail()
When I output the following:
{{ request.user.userwhale_set.count }}
It always outputs as zero even tho the current user has data in that table. The "user" and "created_by" fields are always different so I'm wondering whether or not the code above is using the "created_by" relationship instead of the "user" relationship. If so, how do I specify which one to use?
Many thanks
Ben.

You have specified the related_name property on the user foreignkey, so you should call that name: request.user.whale_relation_user.count.

Related

Trying to get ForeignKey's names instead of pk in a QuerySet Django

Im trying to make a complex queryset and I want to include my ForeignKeys names instead of pk. I'm using ajax to get a live feed from user inputs and print the results on a DataTable but I want to print the names instead of the pk. Im getting a queryset and when I console.log it, sensor_name is not in there.
My models are like this:
class TreeSensor(models.Model):
class Meta:
verbose_name_plural = "Tree Sensors"
field = models.ForeignKey(Field, on_delete=models.CASCADE)
sensor_name = models.CharField(max_length=200, blank=True)
datetime = models.DateTimeField(blank=True, null=True, default=now)
longitude = models.DecimalField(max_digits=22, decimal_places=16, blank=True, null=True)
latitude = models.DecimalField(max_digits=22, decimal_places=16, blank=True, null=True)
class TreeSensorMeasurement(models.Model):
class Meta:
verbose_name_plural = "Tree Sensor Measurements"
sensor = models.ForeignKey(TreeSensor, on_delete=models.CASCADE)
datetime = models.DateTimeField(blank=True, null=True, default=None)
soil_moisture_depth_1 = models.DecimalField(max_digits=15, decimal_places=2)
soil_moisture_depth_2 = models.DecimalField(max_digits=15, decimal_places=2)
soil_moisture_depth_1_filtered = models.DecimalField(max_digits=15, decimal_places=2, blank=True, null=True)
soil_moisture_depth_2_filtered = models.DecimalField(max_digits=15, decimal_places=2, blank=True, null=True)
soil_temperature = models.DecimalField(max_digits=15, decimal_places=2)
And my view looks like this(I've omitted the non-essential code):
field_list = Field.objects.filter(user=request.user)
tree_sensors = TreeSensor.objects.filter(field_id__in=field_list.values_list('id', flat=True))
statSensors = (TreeSensorMeasurement.objects
.filter(sensor_id__in=tree_sensors.values_list('id', flat=True))
.filter(datetime__date__lte=To_T[0]).filter(datetime__date__gte=From_T[0])
.filter(soil_moisture_depth_1__lte=To_T[1]).filter(soil_moisture_depth_1__gte=From_T[1])
.filter(soil_moisture_depth_2__lte=To_T[2]).filter(soil_moisture_depth_2__gte=From_T[2])
.filter(soil_temperature__lte=To_T[3]).filter(soil_temperature__gte=From_T[3])
.order_by('sensor', 'datetime'))
TreeData = serializers.serialize('json', statSensors)
The code above works correctly but I cant figure out the twist I need to do to get the TreeSensors name instead of pk in the frontend. An example of how I receive one instance in the frontend:
datetime: "2022-11-20T13:28:45.901Z"
​​​sensor: 2
​​​soil_moisture_depth_1: "166.00"
​​​soil_moisture_depth_1_filtered: "31.00"
​​​soil_moisture_depth_2: "171.00"
​​​soil_moisture_depth_2_filtered: "197.00"
soil_temperature: "11.00"
Since sensor_name is at the other end of a foreign key field in your TreeSensorMeasurement object, you can grab it using select_related, as in:
.filter(soil_temperature__lte=To_T[3]).filter(soil_temperature__gte=From_T[3])
.select_related('sensor')
.order_by('sensor', 'datetime'))
In a template you could then refer to it, without further DB lookups, as:
{% for ss in statsensors }}
{{ ss.sensor.sensor_name }}
{% endfor }}
If you're using Django Rest Framework you'll need to do a little more - this is adapted from the example at DRF nested relationshipos
class TreeSensorSerializer(serializers.ModelSerializer):
class Meta:
model = TreeSensor
fields = ['sensor_name']
class TreeSensorMeasurementSerializer(serializers.ModelSerializer):
sensor = TreeSensorSerializer(read_only=True)
class Meta:
model = TreeSensorMeasurement
fields = ['sensor',
'datetime',
'soil_moisture_depth1',
'soil_moisture_depth2',
'soil_temoperature',
]
Then when you call serialise it, you'll need to call your serialiser explicitly, so instead of
TreeData = serializers.serialize('json', statSensors)
use
TreeData = TreeSensorMeasurementSerializer(statSensors, many=True).data
The use of .data at end allows the prefetched data relationship to be used without further lookups
Try adding a read-only serializer field in TreeSensorMeasurementSerializer
sensor_name = serializer.ReadOnlyField(source='sensor.sensor_name')

How to copy a object data to another object in Django?

I am trying to create an E-Commerce Website and I am at the Final Step i.e. Placing the Order. So, I am trying to add all the Cart Items into my Shipment model. But I am getting this error.
'QuerySet' object has no attribute 'product'
Here are my models
class Product(models.Model):
productId = models.AutoField(primary_key=True)
productName = models.CharField(max_length=200)
productDescription = models.CharField(max_length=500)
productRealPrice = models.IntegerField()
productDiscountedPrice = models.IntegerField()
productImage = models.ImageField()
productInformation = RichTextField()
productTotalQty = models.IntegerField()
alias = models.CharField(max_length=200)
url = models.CharField(max_length=200, blank=True, null=True)
class Customer(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
name = models.CharField(max_length=100, null=True, blank=True)
email = models.EmailField(max_length=100)
profileImage = models.ImageField(blank=True, null=True, default='profile.png')
phoneNumber = models.CharField(max_length=10, blank=True, null=True)
address = models.CharField(max_length=500, blank=True, null=True)
class Order(models.Model):
customer = models.ForeignKey(Customer, on_delete=models.SET_NULL, blank=True, null=True)
dateOrdered = models.DateTimeField(auto_now_add=True)
orderCompleted = models.BooleanField(default=False)
transactionId = models.AutoField(primary_key=True)
class Cart(models.Model):
product = models.ForeignKey(Product, on_delete=models.SET_NULL, blank=True, null=True)
order = models.ForeignKey(Order, on_delete=models.SET_NULL, blank=True, null=True)
quantity = models.IntegerField(default=0, blank=True, null=True)
dateAdded = models.DateTimeField(auto_now_add=True)
class Shipment(models.Model):
customer = models.ForeignKey(Customer, on_delete=models.SET_NULL, blank=True, null=True)
orderId = models.CharField(max_length=100)
products = models.ManyToManyField(Product)
orderDate = models.CharField(max_length=100)
address = models.CharField(max_length=200)
phoneNumber = models.CharField(max_length=13)
I just removed additional functions i.e. __str__ and others.
Here is the views.py
def orderSuccessful(request):
number = Customer.objects.filter(user=request.user).values('phoneNumber')
fullAddress = Customer.objects.filter(user=request.user).values('address')
timeIn = time.time() * 1000 # convert current time in milliSecond
if request.method == 'POST':
order = Shipment.objects.create(customer=request.user.customer, orderId=timeIn,
orderDate=datetime.datetime.now(), address=fullAddress,
phoneNumber=number)
user = Customer.objects.get(user=request.user)
preOrder = Order.objects.filter(customer=user)
orders = Order.objects.get(customer=request.user.customer, orderCompleted=False)
items = orders.cart_set.all() # Here is all the items of cart
for product in items:
product = Product.objects.filter(productId=items.product.productId) # error is on this line
order.products.add(product)
Cart.objects.filter(order=preOrder).delete()
preOrder.delete()
order.save()
else:
return HttpResponse("Problem in Placing the Order")
context = {
'shipment': Shipment.objects.get(customer=request.user.customer)
}
return render(request, "Amazon/order_success.html", context)
How to resolve this error and all the cart items to field products in Shipment model?
Your model is not really consistent at all. Your Cart object is an m:n (or m2m - ManyToMany) relationship between Product and Order. Usually, you would have a 1:n between Cart and Product (a cart contains one or more products). One Cart might be one Order (unless you would allow more than one carts per order). And a shipment is usually a 1:1 for an order. I do not see any of this relationships in your model.
Draw your model down and illustrate the relations between them first - asking yourself, if it should be a 1:1, 1:n or m:n? The latter can be realized with a "through" model which is necessary if you need attributes like quantities.
In this excample, we have one or more customers placing an order filling a cart with several products in different quantities. The order will also need a shipment fee.
By the way: bear in mind that "filter()" returns a list. If you are filtering on user, which is a one to one to a unique User instance, you would better use "get()" as it returns a single instance.
Putting in into a try - except or using get_object_or_404() makes it more stable.
product = Product.objects.filter(productId=items.product.productId)
should be something like:
product = product.product
not to say, it becomes obsolete.
It looks like you make a cart for a product by multiple instances of Cart, the problem is you try to access the wrong variable, also you don't need to filter again when you already have the instance, make the following changes:
carts = orders.cart_set.all() # Renamed items to carts for clarity
for cart in carts:
product = cart.product
order.products.add(product) # The name order is very misleading makes one think it is an instance of Order, actually it is an instance of Shipment
As mentioned above in my comment your variable names are somewhat misleading, please give names that make sense to any variable.

Django Joining Tables

I am trying to get the information from one table filtered by information from another table (I believe this is called joining tables).
I have these two models:
class Listing(models.Model):
title = models.CharField(max_length=64)
description = models.CharField(max_length=500)
price = models.DecimalField(max_digits=11, decimal_places=2, validators=[MinValueValidator(Decimal('0.01'))])
category = models.ForeignKey(Category, on_delete=models.CASCADE, default="")
imageURL = models.URLField(blank=True, max_length=500)
creator = models.ForeignKey(User, on_delete=models.CASCADE, related_name="creator", default="")
isOpen = models.BooleanField(default=True)
def __str__(self):
return f"{self.id} | {self.creator} | {self.title} | {self.price}"
class Watchlist(models.Model):
listing = models.ForeignKey(Listing, on_delete=models.CASCADE, related_name="listingWatched", default="")
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name="userWatching", default="")
What I need to do is to get all the listings from a specific user Watchlist, the idea is to generate a page with all of the information of each of the listings that are in the user's watchlist. What should I do?
Thanks in advance!
Since is a foreign key, in Django you can access the information by calling the attribute
For example:
my_user = Watchlist.objects.get(pk=1)
print(my_user.listing.title)
You can also access to that attrbute in a query in case you need to filter upwards some value
values = Watchlist.objects.all().filter(listing__title='MyTitle')
my_titles = [x.title for x in values]
print(my_titles)
Or in your case, if you want to list all the title for a specific user
values = Watchlist.objects.all().filter(user='foo_user')
my_titles = [x.listing.title for x in values]
print(my_titles)
More documentation here

Django, detect if object.filter returns 0 objects

I got such table structure
class Item(models.Model):
id = models.AutoField(primary_key=True)
class Car(models.Model):
vin_number = models.CharField(max_length=250, null=True, blank=True)
item = models.OneToOneField(Item, on_delete=models.CASCADE)
name = models.CharField(max_length=1000, null=True)
year = models.IntegerField(null=True)
class Yacht(models.Model):
name = models.CharField(max_length=1000, default='')
boat_type = models.CharField(max_length=1000, default='', null=True)
item = models.OneToOneField(Item, on_delete=models.CASCADE)
description = models.TextField(default='')
year = models.IntegerField(null=False, default=0)
So, both Car and Yacht has relation with Item table
If I have only item id in request, what is the right way to write such query
data = request.POST
item = Car.objects.filter(item_id=data['item_id']).first()
if not item:
item = Yacht.objects.filter(item_id=data['item_id']).first()
Is there any way not to use if/else statement?
You don't need to look into the Car and Yacht model. Directly use the Item model's OneToOne relationship
item = Item.objects.filter(id = data['id']).first
This item has a specific id that relates to one of the other model. You can access them using
if item.car:
car = item.car
else:
yacht = item.yacht
But I guess you also need to add {{ related_name='tags', related_query_name='tag' }} to your OneToOne field for both car and yacht.
I would recommend that you check this out https://kite.com/python/docs/django.db.models.ForeignKey.
For more detail go to https://docs.djangoproject.com/en/3.0/topics/db/examples/one_to_one/
You need to use exists().
Car.objects.filter(item_id=data['item_id']).exists()
Yacht.objects.filter(item_id=data['item_id']).exists()
It returns you True or False.
Links to official docs.

How to annotate a field from a related model to queryset?

I have two models:
Lot:
class Lot(models.Model):
name = models.CharField(max_length=150, db_index=True, unique=True)
step = models.DecimalField(max_digits=2, decimal_places=2)
and Bid:
class Bid(models.Model):
auction = models.ForeignKey('Lot', on_delete=models.CASCADE)
user_id = models.ForeignKey(User, on_delete=models.CASCADE, to_field='username')
value = models.DecimalField(max_digits=5, decimal_places=2)
Every instance of Lot can have a few Bids, however any instance of Bid is only related to a particular Lot.
I have a working annotation for Lot that gives me the max_bid and next_bid values:
self.auc_set = Lot.objects.annotate(max_bid=Max('bid__value'), next_bid=(Max('bid__value') + F('step')))
And what i can't achieve is getting 3 annotated fields: max_bid, next_bid and last_bidder.
Something like:
self.auc_set = Lot.objects.annotate(max_bid=Max('bid__value'), next_bid=(Max('bid__value') + F('step')), last_bidder=F(bid_set).get('auction_id'= F('id'), 'value'=max_bid)['user_id'])
but working.
Update:
The problem would be solved if i knew how to pass the 'id' from Lot.objects.annotate to the Bid.objects.get part:
auc_set = Lot.objects.annotate(last_bidder=Bid.objects.get(auction_id__exact='need_to_put_something_here', value=Max('value').user_id)