Django merge two QuerySets - django

I want to merge these two QuerySets. HotkeyAndPrefix do not have entries for every Collection in all_collections. This means len(all_collections) >= len(all_collections_hotkeys_and_prefixes). How can i merge these two QuerySets? If there is no entrie found for a Collection in HotkeyAndPrefix I want hotkey = None, prefix=None. Can I achieve this in one query?
models.py:
class Collection(models.Model):
creator = models.ForeignKey(User, blank=True, null=True)
...
class HotkeyAndPrefix(models.Model):
user = models.ForeignKey(User, null=True)
assigned_collection = models.ForeignKey(Collection, null=True)
hotkey = models.CharField(max_length=1, blank=True, null=True)
prefix = models.CharField(max_length=20, blank=True, null=True)
class Meta:
unique_together = ('user', 'assigned_collection')
view.py
admin = User.objects.filter(username='admin')[0]
all_collections = Collection.objects.filter(creator=admin)
current_user = request.user
all_collections_hotkeys_and_prefixes = HotkeyAndPrefix.objects.filter(assigned_collection__in=all_collections, user=current_user)

You need to use exclude() query. You can take the list of values which are in the
HotkeyAndPrefix.objects.filter(assigned_collection__in=all_collections, user=current_user) queryset
using
all_collections_hotkeys_and_prefixes_values = all_collections_hotkeys_and_prefixes.values_list('assigned_collection',flat=True)
and you can filter out the value, not in the all_collections_hotkeys_and_prefixes_values with one more query
all_collections_hotkeys_and_prefixes_excluded = all_collections.exclude(pk__in=all_collections_hotkeys_and_prefixes_values)
now you have two querysets, one of collection for which a user has hotkey/prefix and another for which the user doesn't

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 filter data in different models in django?

my models
class Player(TimeStampedModel):
name = models.CharField(max_length=200)
email = models.CharField(max_length=200)
email_verified = models.BooleanField(default=False, blank=True)
phone = models.CharField(max_length=200)
phone_verified = models.BooleanField(default=False, blank=True)
company_id = models.ImageField(upload_to=get_file_path_id_card, null=True,
max_length=255)
company_id_verified = models.BooleanField(default=False, blank=True)
team = models.ForeignKey(Team, related_name='player', on_delete=models.DO_NOTHING)
def __str__(self):
return self.name
this is my model , how to filter data in multiple model?
You can use a Queryset to filter by modal object's field.
You can use this to also filter relationships on models.
In your example, you can do a filter of all the Player entries that have a Character that have Weapon with strength > 10
Player.objects.filter(character__weapon__strength__gt=10)
You can also separate them out into 3 variables for readability purposes.
player_q = Player.objects.filter(character__isnull=False)
ch_q = player_q.filter(weapon__isnull=False)
wpn_dmg = ch_q.filter(strength__gt=10)
Please note that filters are lazy and thus don't return actual model instances untill they're evaluated. I think in this case gt returns an instance.
This documentation goes over all the fieldset lookups you can do with QuerySet object methods filter(), get(), and exclude()

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 : Create custom object list in the view and pass it to template to loop over

I want to create a custom object list in the view and pass it to the template. In the template I want to loop over the list and display the information.
My models are
class CustomUser(AbstractUser):
def __str__(self):
return self.email
class Post(models.Model):
author = models.ForeignKey(CustomUser,on_delete=models.CASCADE,)
text = models.TextField()
created_date = models.DateTimeField(default=timezone.now)
published_date = models.DateTimeField(blank=True, null=True)
post_url = models.URLField(max_length = 200, blank = True)
slug = models.SlugField(unique=True, blank=True)
class subscription(models.Model):
creator = models.ForeignKey(CustomUser,default=None, null=True,on_delete=models.CASCADE,related_name='creator',)
booster = models.ForeignKey(CustomUser,default=None, null=True,on_delete=models.CASCADE,related_name='booster')
sub_value = models.FloatField(blank = True)
sub_id = models.TextField(blank = True)
status = models.BooleanField(default=False)
dateSubscribed = models.DateTimeField(default=timezone.now)
dateSubscriptionEnded = models.DateTimeField(default=timezone.now)
paymentCount = models.FloatField(default= 0)
I want to filter objects from subscription model like below
subs = subscription.objects.filter(booster = request.user)
Then find creators in the above subs object list and for each creator get the name, numbers Posts, and number of Subscribers. Add this to custom list and pass it to the template to loop over and display the information in the template. Can someone help me how to create this custom list. Thanks!
Ok so here are the basics minus the subscribers because I don't see the relation clearly. This is how to parse the name and the number of posts. \
my_list = []
for sub in subs:
name = sub.creator.name
auth_id = sub.creator.id
posts = Post.objects.filter(author=auth_id)
num_of_posts = len(posts)
my_list.append({
'name':name,
'post_count': num_of_posts,
})
then you would pass mylist thru the template context.
It is a common mistake to name the related_name=… parameter [Django-doc] to the same value as the name of the field. The related_name parameter however is the name of the reverse relation Django will automatically add. So here it means a relation to access for example the related subscription objects of a given CustomUser.
Therefore it makes more sense to rename these, for example like:
class Subscription(models.Model):
creator = models.ForeignKey(
CustomUser,
default=None,
null=True,
on_delete=models.CASCADE,
related_name='created_subscriptions'
)
booster = models.ForeignKey(
CustomUser,
default=None,
null=True,
on_delete=models.CASCADE,
related_name='boosted_subscriptions'
)
sub_value = models.FloatField(blank=True)
sub_id = models.TextField(blank =True)
status = models.BooleanField(default=False)
dateSubscribed = models.DateTimeField(default=timezone.now)
dateSubscriptionEnded = models.DateTimeField(default=timezone.now)
paymentCount = models.FloatField(default=0)
Next we can make a query where:
from django.db.models import Count
CustomUser.objects.filter(
created_subscriptions__booster=request.user
).annotate(
number_of_posts=Count('post', distinct=True)
)
This is a QuerySet of CustomUsers where each CustomUser that arises from this QuerySet has an extra attribute .number_of_posts that contains the number of posts. You thus can iterate over the queryset directly in the template.

order_by causing not distinct items

I've implemented a messaging system:
class Message(models.Model):
user = models.ForeignKey(User, unique=False, related_name = 'messages')
conversation = models.ForeignKey('Conversation', related_name = 'messages')
body = models.TextField(max_length=750)
reads = models.ManyToManyField(User, related_name='read_messages', null=True, blank=True)
# Other
date_created = models.DateTimeField(auto_now=False, auto_now_add=True, blank=True)
date_modified = models.DateTimeField(auto_now=True, auto_now_add=False, blank=True)
class Conversation(models.Model):
participants = models.ManyToManyField(User, related_name='conversations')
type = models.CharField(max_length=1, default="D", choices=config.CONVERSATION_TYPE_OPTIONS)
Using Django Rest Framework, I'd like to order a conversation by the last message.
class ConversationFilter(filters.BaseFilterBackend):
"""
Filters to only show by current user
"""
def filter_queryset(self, request, queryset, view):
return queryset.filter(
participants=request.user,
).order_by('-messages__date_created')
However once I add the order_by method, the queries are no longer distinct. Adding distinct() does not work either. What is going on here?
You have a one to many relationship between Conversation and Message.
When you join the message table into the Conversation query (which happens when you add the order_by clause using messages), then you will get multiple Conversation entries, one for each message.