Get foreign key element from a related_name on django - django

I have three models such as the one below and I am trying to write a query that allows me to access all the Day_Type associated to the Day objects that are pointing to a specific JobProject.
I know that I can get all the Day pointing at a JobProject by querying project.jobproject_days.all() and I can get the values of the Day_Type by doing project.jobproject_days.values_list('day_type__name', flat=True)
BUT how can I get the Day_Type themselves?
class JobProject(models.Model):
......
class Day_Type(models.Model):
name = models.CharField(max_length=30)
class Day(models.Model):
....
day_type = models.ForeignKey(Day_Type, blank=True, on_delete=models.CASCADE, null=True, related_name='day_type')
project = models.ForeignKey(JobProject, blank=True, on_delete=models.CASCADE, related_name='jobproject_days', null=True)

You can fetch it like this:
daytypes = Day_Type.objects.filter(day_type__project=project)

Related

Querying using related field names

I've got two models that I'd like to perform a reverse search on. I'm wondering how to do this given the fact that one model has to fields with foreign keys to the same model.
class Review(models.Model):
cart = models.ForeignKey(Cart, on_delete=models.CASCADE, default=None)
class Cart(models.Model):
cost = models.DecimalField(max_digits=50, decimal_places=2, null=True, blank=True)
class Job(models.Model):
cart = models.ForeignKey(Cart, related_name="cart_one", on_delete=models.CASCADE, null=True, blank=True)
unscheduled_job = models.ForeignKey(Cart, related_name="cart_two", on_delete=models.CASCADE, null=True, blank=True)
employee = models.ForeignKey(Employee, on_delete=models.CASCADE, null=True, blank=True)
My query is as follows:
reviews = Review.objects.filter(cart__job__employee=employee)
This query is failing due to the fact that the Job model has two foreign keys that point to the cart model. How would I fix this?
Thanks!
If you specify a related_query_name=… parameter [Django-doc] or a **related_name=… parameter [Django-doc], then that is the name to access the model in reverse, so you can query with:
Review.objects.filter(cart__cart_one__employee=employee)
or if you want to query in reverse with the unscheduled_job, then it is:
Review.objects.filter(cart__cart_two__employee=employee)
You can also combine the two, so bo5th cart anfd unscheduled_job by making use of a Q object:
from django.db.models import Q
Review.objects.filter(Q(cart__cart_one__employee=employee) | Q(cart__cart_two__employee))
You might however want to change the related_name=…s, since this should be the name to access the Job object from the perspective of a Cart model.

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.

How to get values for a queryset for an model when the foreign key is not in the current model?

I have the following models:
class Work_Music(models.Model):
key = models.CharField(max_length=10, null=True, blank=True)
tonality = models.CharField(max_length=20, null=True, blank=True)
class Catalogue(models.Model):
work_music = models.ForeignKey(Work_Music, verbose_name=_('work_music'), on_delete=models.PROTECT)
name = models.CharField(max_length=100, null=True, blank=True)
name_short = models.CharField(max_length=100, null=True, blank=True)
no = models.CharField(max_length=100, null=True, blank=True)
related_field() only works with the Foreign key is in Work_Music. Many catalogue/catalogue numbers can map to a piece of music (Work_Music). How can I construct a query set on Work_Music to pull all of the catalogues related to the piece of work?
Use catalogue_set.
Django's ORM automatically creates the field for you on the navigation model of the foreign key (Work_Music in this case). For "one-to-many" relationships, this is a queryset with the name of the model on which the foreign key exists appended with _set. For "one-to-one" relationships, this is just the name of the model on which the foreign key exists.
assuming a Work_Music instance called work_music_instance:
catalogues = work_music_instance.catalogue_set.all()
or
catalogues = work_music_instance.catalogue_set.filter(...) # any query set operation
First get an object whose catalogue you want.
workmusic = Work_Music.objects.all()[0]
then
workmusic.catalogue_set.all()
this will return all catalogue related to workmusic object.

Django query set giving attribute_error when trying to get a set with multiple foreign keys

First, here are my models. Each string has from 1 up to 3 performers, each performer linked to several strings:
class Performer(models.Model) :
name = models.CharField(max_length=60, default="None")
description = models.TextField(null=True, default=None)
class String(models.Model) :
index = models.IntegerField(null=True, default=None)
step = models.IntegerField(null=True, default=None)
process = models.CharField(max_length=100,null=True, default=None)
description = models.TextField(null=True, default=None)
performer = models.ForeignKey(Performer, related_name='performer', on_delete=models.CASCADE, null=True, default=None)
performer2 = models.ForeignKey(Performer, related_name='performer2', on_delete=models.CASCADE, null=True, default=None)
performer3 = models.ForeignKey(Performer, related_name='performer3', on_delete=models.CASCADE, null=True, default=None)
I need to make set of all Strings related to single performer. However, if I try to use string_set to get all Strings where any of the Performer foreign keys point to that string like so:
p = Performer.objects.get(name="smth")# so p is a performer object
s = p.string_set.all()
I get this issue:
AttributeError: 'Performer' object has no attribute 'string_set'
Also I've tryed to use filters with related name, but this gives me the same error. Is there a way to get a _set based off of one of any foreign key fields that all point to the same type?
By providing related_name in each of performer, performer2, performer3 relations you override the default related_name linking from Performer class which would be string_set. Now to get the String for each of these relations you would have to get them like the following:
p = Performer.objects.get(name="smth")# so p is a performer object
p.performer.all() #first one which would actually be a queryset
p.performer1.all() #second one which would actually be a queryset
p.performer2.all() #third one which would actually be a queryset
This would be true only if you have single String and single Performer related to each other but you should keep in mind that query like p.performer1.all() can actually return 2 or more String objects which would have a relation with this one Performer. This would make things even more cumbersome.
Keep in mind that the ForeignKey creates one-to-many relation...
The models structure you provide would have issues with doing filtering you want. The better model design would look like the following:
class Performer(models.Model) :
name = models.CharField(max_length=60, default="None")
description = models.TextField(null=True, default=None)
strings = models.ManyToManyField(String, related_name='performers')
class String(models.Model) :
index = models.IntegerField(null=True, default=None)
step = models.IntegerField(null=True, default=None)
process = models.CharField(max_length=100,null=True, default=None)
description = models.TextField(null=True, default=None)
This design would allow you to execute:
p = Performer.objects.get(name="smth")# so p is a performer object
s = p.strings.all()

django prefetch_related not working

I am trying to export all my database with a prefetch_related but I only get data from the main model.
My models:
class GvtCompoModel(models.Model):
gvtCompo= models.CharField(max_length=1000, blank=False, null=False)
...
class ActsIdsModel(models.Model):
year = models.IntegerField(max_length=4, blank=False, null=False)
...
class RespProposModel(models.Model):
respPropos=models.CharField(max_length=50, unique=True)
nationResp = models.ForeignKey('NationRespModel', blank=True, null=True, default=None)
nationalPartyResp = models.ForeignKey('NationalPartyRespModel', blank=True, null=True, default=None)
euGroupResp = models.ForeignKey('EUGroupRespModel', blank=True, null=True, default=None)
class ActsInfoModel(models.Model):
#id of the act
actId = models.OneToOneField(ActsIdsModel, primary_key=True)
respProposId1=models.ForeignKey('RespProposModel', related_name='respProposId1', blank=True, null=True, default=None)
respProposId2=models.ForeignKey('RespProposModel', related_name='respProposId2', blank=True, null=True, default=None)
respProposId3=models.ForeignKey('RespProposModel', related_name='respProposId3', blank=True, null=True, default=None)
gvtCompo= models.ManyToManyField(GvtCompoModel)
My view:
dumpDB=ActsInfoModel.objects.all().prefetch_related("actId", "respProposId1", "respProposId2", "respProposId3", "gvtCompo")
for act in dumpDB.values():
for field in act:
print "dumpDB field", field
When I display "field", I see the fields from ActsInfoModel ONLY, the starting model. Is it normal?
You haven't understood the arguments to prefetch_related. It's not a list of fields, but a list of models.
(Note that your field naming convention is also very misleading - respProposId1 and actId are not IDs, but actual instances of the models. Django has created an underlying field in each case by appending _id, so the db columns are respProposId1_id and actId_id. You should just call the fields resp_propos1 and resp_propos2 - also note that normal style is lower_case_with_underscore, not capWords.)
It is normal, that you are seeing fields from ActsInfoModel only. You can access related models via dot notation, like:
acts = ActsInfoModel.objects.all().prefetch_related("actId", "respProposId1", "respProposId2", "respProposId3", "gvtCompo")
for act in acts:
print act.respProposId1.respPropos
Related models are already prefetched, so it won't produce any additional queries. FYI, quote from docs:
Returns a QuerySet that will automatically retrieve, in a single
batch, related objects for each of the specified lookups.