Django relation lookup not creating expected query - python

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

Related

django: how can i get the last id or row_id of a table?

I'm writing a website, i need to make a numbering system, i need to add the latest row_id/id + 1 to a charfield, alll work is nearly done but this.
any idea how to get the number? its like getting the row id of the object before adding it to the table.
letter_numbering = cjy + latest_row_id +1
~~~
class Entry(models.Model):
topic = models.ForeignKey(Topic, on_delete=models.CASCADE)
title = models.CharField(max_length=200)
jalali_date = models.CharField(max_length=10, default=current_full_j_date)
-> letter_number = models.CharField(max_length=7, default=letter_numbering)
from_to = models.CharField(max_length=200)
file = forms.FileField()
letter_type = models.CharField(max_length=8, choices=letter_direction, default='incoming')
text = models.TextField()
date_added = models.DateTimeField(auto_now_add=True)
Based on your question what I get is you want the id of latest record that you inserted
It can be obtained using:-
latest_id = Entry.objects.latest('id').id
In your model, there is no primary key so Django will create a default primary key i.e id which will be incremented automatically every time you create a record.
So you can use it as the latest row_id.
Based on the autokey id you can get the last created id as
last_id = Entry.objects.last().id
Either of these will give solution to your question.

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.

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.

how to select values from two models having a foreign key relation in django

I have two models one called person and the other called permission , the person have a foreign key called p_perm that relates permission model to a perm_id field ,
i want to filter in the person table by id and select the relative permission values of this person from permission table
My model:
class Person(models.Model):
p_id = models.AutoField(primary_key=True)
p_fname = models.CharField(max_length=20)
p_perm = models.ForeignKey(Permission,
on_delete=models.DO_NOTHING, to_field="perm_id")
class Permission(models.Model):
perm_id = models.CharField( max_length=1, unique=True,
primary_key=True)
perm_label = models.CharField( max_length=30)
I have done this in my view:
x = Person.objects.get(p_id=user)
print(x.p_perm)
y = Permission.objects.get(perm_id= x.p_perm)
print(y.perm_id)
You can do:
y = Permission.objects.get(perm_id=x.p_perm_id)
Or simply, this object is accessible directly from the source model instance:
y = x.p_perm
However, note that this will trigger two SQL queries. You can limit to one query by letting Django ORM know that you will need to access the foreign key:
x = Person.objects.select_related('p_perm').get(p_id=user)
y = x.p_perm
It will do the appropriate join to retrieve both Person and Permission at once.

Django query selecting values and objects

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.)

Categories

Resources