Django query selecting values and objects - python

I have a problem with the queries when selecting values and objects. Here is a sample structure:
class Property(models.Model):
name = models.CharField(max_length=70, blank=True, verbose_name="Property Name")
type = models.CharField(max_length=10)
class Agreement(models.Model):
property = models.ForeignKey(Property, on_delete=models.CASCADE, related_name="prop")
renter = models.ForeignKey(User, verbose_name="Kiracı", related_name = "renter01")
Here is the first filter.
qs1 = Agreement.objects.all()
This one returns property and renter as objects. So I can refer the object details such as
for q in qs:
print(q.renter.firstname)
Here is the second filter.
When I need only some fields I use this filter:
qs2 = Agreement.objects.all().values('renter',...)
In that case the query returns the pk value of the renter user; and I cannot use it as object.
Is there a way that I can select certain columns and keep the objects in it as objects?

If you want renters, you should query User, not Agreement.
renters = User.objects.exclude(renter01=None)
(Note, having renter01 as the reverse relation makes no sense; unless you have a good reason, you should keep it as the default, which is agreement_set.)

Related

How to filter objects based on model fields in Django

I have a Model named Order that has a foreign key pointed to the current user
class Order(models.Model):
customer_name = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE,
related_name='customer_name',
)
order_individual_price = models.IntegerField(default=1)
order_default_price = models.IntegerField(default=1)
order_name = models.CharField(max_length=200)
order_quantity = models.IntegerField(default=1)
order_total_price = models.IntegerField(default=1)
I currently have 2 order objects from 2 different users. How would I filter the objects so that it only shows the one from a specific user?
I currently have the following code: Order.objects.filter(customer_name='chironsus')
It gives me this error: ValueError: Field 'id' expected a number but got 'chironsus'.
'chironsus' is not the primary key of a User, it is perhaps the username. You can filter that with:
Order.objects.filter(customer_name__username='chironsus')
Note: A ForeignKey does not store the string representation (or name) of the
referenced object in the column, it stores the primary key of the record it
references in a column with an _id suffix to a ForeignKey field. Therefore
ForeignKeys usually do not end with a _name suffix. You might want to
consider renaming the customer_name field to customer.

Iterating Through a Database Django

I have a model in my database called Item. This is the model
class Item(models.Model):
item_title = models.CharField("Item title: ", max_length=50)
item_description = models.CharField("Item description: ", max_length=200)
starting_price = models.FloatField( default = 0)
picture = models.ImageField(upload_to = 'gallery')
finishTime = models.DateTimeField("Finish time: ")
ownerID = models.ForeignKey(User, on_delete = models.CASCADE)
higestBid = models.FloatField()
highestBidderID = models.IntegerField(blank=True, default=-1)
active = models.BooleanField(default = True)
I want to create a function in views.py , which will check the 'active' field of each item in the database. How can I do that? I have tried to do this:
items = list(Item.object.values())
for i in range(items):
print(item[i].active)
However it does not work. Any help is appreciated
You should iterate over the queryset itself:
for item in Item.objects.all():
print(item.active)
Please do not use .values() [Django-doc]. You should only use that for some specific cases, like grouping on a certain value. By working with objects, you will still use model objects, and thus certain logic you added on that object, is still accessible.
Furthermore it is often better not to use list(..). A QuerySet is lazy, and thus if you somehow never iterate over it, then it will not make the query. Furthermore you can then do extra filtering on an existing QuerySet.

Cannot assign "40": "Group.groupParent_id" must be a "Group" instance

I want to add group from my group model. this one is recursive on parent-children relation.
But when I want to create a group with a children. I have the error
my model:
class Group(models.Model):
group_id = models.AutoField(primary_key=True)
groupParent_id = models.ForeignKey('self', blank=True, null=True, related_name='children', on_delete=models.CASCADE)
group_name = models.CharField(max_length=100, null=False, blank=False, unique=True)
views.py:
My function which provoke error on line 18 GroupParent_id :
def add_group_fromcoa(request): # add type and subtype of chart of account as first serie of group and subgroup
# ------ Type adding -----
types = ChartOfAccount.objects.order_by().values_list("field_type", flat=True).distinct()
for type_types in types:
upload_data = Group.objects.get_or_create(group_name=type_types,)
types = ChartOfAccount.objects.order_by().values_list('field_subtype', flat=True).distinct()
for type_types in types:
looktype = ChartOfAccount.objects.filter(field_subtype=type_types).values('field_type').first()
print("retour Groupe: {}".format(looktype['field_type']))
looktyp= Group.objects.filter(group_name=looktype['field_type']).values('group_id').first()
print("IDGroup: {}".format(int(looktyp['group_id'])))
upload_data = Group.objects.get_or_create(
group_name=type_types,
groupParent_id=int(looktyp['group_id']))
return redirect(home)
When you create a foreign key relation in Django, Djano's default behavior is to name the column name <object_column_name>_id. So, when you add the field groupParent_id, Django names the database field groupParent_id_id. Now, when you have a foreign key on a Django model, you have two ways of referencing that relationship: you can use an object, or you can use a database primary key. If you use the name of the field from the model, the reference has to be an object. However, if you add _id onto the end, you can use the primary key, as you're trying to do here. If you change groupParent_id=int(looktyp['group_id']) to groupParent_id_id=int(looktyp['group_id']), this should work.

Django join tables with ORM and conditional Where clause

I have 4 tables to join; Personnels,Machines and Locations. I want to join these tables and add where clause to end of the ORM query if request body includes filtering data. Here is my models and raw query (I want to write this query in django ORM) and sample if condition for where clause;
Models ;
class Sales(models.Model):
MachineId = models.ForeignKey(Machines,on_delete=models.CASCADE,db_column='MachineId',related_name='%(class)s_Machine')
PersonnelId = models.ForeignKey(Personnels,on_delete=models.CASCADE,db_column='PersonnelId',related_name='%(class)s_Personnel')
LocationId = models.ForeignKey(Locations,on_delete=models.CASCADE,db_column='LocationId',related_name='%(class)s_Location')
class Meta:
db_table = "Sales"
class Machines(models.Model):
Name = models.CharField(max_length=200)
Fee = models.DecimalField(max_digits=10,decimal_places=3)
class Meta:
db_table = "Machines"
class Personnels(models.Model):
name = models.CharField(max_length=200)
surname = models.CharField(max_length=200)
class Meta:
db_table = "Personnels"
class Locations(models.Model):
Latitude = models.FloatField()
Longitude = models.FloatField()
LocationName = models.CharField(max_length=1000)
class Meta:
db_table = "Locations"
As you see I have 4 models. "Sales" table has foreignkeys to others. I want to get all informations in tables with using these foreign keys.(With Inner Join)
query = '''select * from "Sales" as "SL" INNER JOIN "Personnels" as "PL" ON ("SL"."PersonnelId" = "PL"."user_id") INNER JOIN "Machines" as "MC" ON ("SL"."MachineId" = "MC"."id") INNER JOIN "Locations" as "LC" ON ("SL"."LocationId" = "LC"."id") '''
if request.method=='POST':
if request.data['personnel_name'] and request.data['personnel_name'] is not None:
personnel_name = request.data['personnel_name']
condition = '''WHERE "PL"."name" = '{0}' '''.format(personnel_name)
query = query+condition
As it is seen, there are lots of quotes (if I don't write,postgresql makes some trouble) and code is not clean.
My question is, how can I write this query with using django ORM? As you see, I want to add where conditions dynamically. How can I achieve that?
I'm going to use conventional naming, with only class names captilized, and model names singular.
class Sale(models.Model):
machine = models.ForeignKey(Machine, on_delete=models.CASCADE)
person = models.ForeignKey(Person, on_delete=models.CASCADE)
location = models.ForeignKey(Location, on_delete=models.CASCADE)
db_column and db_table is useful if you have to connect the django app use an existing database. If not, django will create sensible table names by default. The table name can be different from the model field name.
To create a join where, use a queryset filter.
Sale.objects.filter(person__name='Jane Janes')
You might not need more joins, since django will perform additional queries when needed, but it can be achieved using select_related, and can give you better performance, since it reduces the total number of sql queries needed.
Sale.objects.filter(person__name='Jane Janes').select_related('machine', 'person', 'location')
It can be useful to inspect the actual SQL that will be performed when you evalute a queryset. You can do this by accessing the QuerySet.query property.
queryset = Sale.objects.select_related('machine').filter(
person__name='Jim', location__name='London')
print(queryset.query)

Django relation lookup not creating expected query

I'm using Django 1.11.6, python 3.4.2, postgresql, PyCharm 4.5.2, and windows 10 (only for development purposes).
The goal is to utilize the 'Lookups that span relationships' from the Django docs.
# models
class AlphaType(models.Model):
page_type = models.CharField(max_length=50, primary_key=True, null=False)
created_on = models.DateTimeField(auto_now_add=True)
modified_on = models.DateTimeField(auto_now=True)
class AlphaBoard(models.Model):
title = models.CharField(max_length=50)
alpha_text = models.TextField(max_length=30000)
created_on = models.DateTimeField(auto_now_add=True)
modified_on = models.DateTimeField(auto_now=True)
fk_page_type = models.ForeignKey(AlphaType, on_delete=models.CASCADE, default='general')
#views
....
q = AlphaBoard.objects.filter(fk_page_type__page_type='general')
print(q.query)
....
Just fyi, the tables have the app name prepended to the model name and the foreign key has 'id' appended to the foreign key column name.
Result of the query print.
SELECT
"alpha_alphaboard"."id", "alpha_alphaboard"."title",
"alpha_alphaboard"."alpha_text", "alpha_alphaboard"."created_on",
"alpha_alphaboard"."modified_on", "alpha_alphaboard"."fk_page_type_id"
FROM
"alpha_alphaboard"
WHERE
"alpha_alphaboard"."fk_page_type_id" = "general"
What I was expecting.
SELECT
"alpha_alphaboard"."id", "alpha_alphaboard"."title",
"alpha_alphaboard"."alpha_text", "alpha_alphaboard"."created_on",
"alpha_alphaboard"."modified_on", "alpha_alphaboard"."fk_page_type_id"
FROM
"alpha_alphaboard"
INNER JOIN "alpha_alphaboard" ON "alpha_alphatype"
"alpha_alphaboard"."fk_page_type_id" = "alpha_alphatype"."page_type"
WHERE
"alpha_alphatype"."page_type" = "general"
Questions
Why is the query ignoring the page_type relation from the filter? Look at the result of the printed query and the filter within the views. I should also add that I had a related_name="fk_page_type" within the AlphaBoard.fk_page_type, but I removed it. So a follow up question is why is it still picking up the related_name?
How do you use the "relationship" from the docs to get the expected?
Is there a way to specify the join type?
Since page_type is the primary key of the AlphaType model and its value is just written in the fk_page_type column of the AlphaBoard table, no join is needed:
q = AlphaBoard.objects.filter(fk_page_type__page_type='general')
is the same as
q = AlphaBoard.objects.filter(fk_page_type_id='general')
the field of the related model you are using in your filter is the exact foreign key value that is written in the primary table.
As for the related_name, it is used to access the reverse relation:
class AlphaBoard(models.Model):
fk_page_type = models.ForeignKey(AlphaType, on_delete=models.CASCADE, related_name='boards')
t = AlphaType(...)
boards = t.boards.all() # gives all boards with type t
boards = t.alphaboard_set.all() # default: lowermodelname_set

Categories

Resources