Django - Following a foreign key relationship (i.e JOIN in SQL) - python

Busy playing with django, but one thing seems to be tripping me up is following a foreign key relationship. Now, I have a ton of experience in writing SQL, so i could prob. return the result if the ORM was not there.
Basically this is the SQL query i want returned
Select
table1.id
table1.text
table1.user
table2.user_name
table2.url
from table1, table2
where table1.user_id = table2.id
My model classes have been defined as:
class Table1(models.Model):
#other fields
text = models.TextField()
user = models.ForeignKey('table2')
class Table2(models.Model):
# other fields
user_name = models.CharField(max_length=50)
url = models.URLField(blank=True, null=True)
I have been through the documentation and reference for querysets, models and views on the django website. But its still not clear on how to do this.
I have also setup the url with a generic list view, but would like to access the user_name field from the second table in the template. I tried select_related in urls.py and also via the shell but it does not seem to work. See examples below.
config in urls
url(r'^$','django.views.generic.list_detail.object_list', { 'queryset': Table1.objects.select_related() }),
At the shell
>>> a = Table1.objects.select_related().get(id=1)
>>> a.id
1
>>> a.user_name
Traceback (most recent call last):
File "<console>", line 1, in <module>
AttributeError: 'Table1' object has no attribute 'user_name'
So basically,
What am i doing wrong?
Am i missing something?
What's the best way to pass fields from two tables in the same queryset to your template (So fields from both tables can be accessed)
Can this be done with generic views?

Something like this should work:
u = Table1.objects.get(id=1)
print u.id
print u.user.user_name
If you want to follow a foreign key, you must do it explicitly. You don't get an automatic join, when you retrieve an object from Table1. You will only get an object from Table2, when you access a foreign key field, which is user in this example

select_related() do not add second table result directly to the query, it just "Loads" them, insead of giving to you lazily. You should only use it, when you are sure it can boost your site performance. To get second table you need to write
a.user.username
In Django to get related table you need to follow them through foreign-keys that you have designed. Query itself do not directly translate to SQL query, because it is "lazy". It will execute only SQL that you need and only when you need.
If you have select_related SQL would have been executed at the moment when you do original query for a. But if you didn't have select_related then it would load DB only when you actually execute a.user.username.

Related

Djanjo with Rest Framework and Postgres search

I need to make search for looking some data from database and this search field should support some logical operations. Like AND, OR, NOT and so on.
So I found that Postgres db has something that I need. Ad Django documentation saying to us we need to use SearchQuery with parameter search_type='websearch'
And we have something like
SearchQuery("'tomato' ('red' OR 'green')", search_type='websearch') # websearch operators
When I'm tried to implement to my project I did something like that
# views.py
class DataSearch(generics.ListAPIView):
serializer_class = DataSerializer
def get_queryset(self):
queryset = Data.objects.all()
query = self.request.query_params.get('query')
if query is not None:
queryset = queryset.filter(
search_vector = SearchQuery(
query,
search_type='websearch'
)
)
return queryset
But when I'm trying to run it I get
Cannot resolve keyword 'search_vector' into field. Choices are: data, foo, foo_id
So what I should do to make it work and to make API endpoint for this type of search?

How can I get all Django groups and optionally get associated user record?

This should be pretty simple since it's very simple with pure SQL. I have the following query which gets exactly what I want in Django:
SELECT auth_group.id, auth_group.name, auth_user.username
FROM auth_group
LEFT JOIN auth_user_groups
ON auth_group.id = auth_user_groups.group_id
LEFT JOIN auth_user
ON auth_user_groups.user_id = auth_user.id
WHERE auth_user.id = 3
OR auth_user.id IS NULL;
How can I get this result using the ORM properly?
You can query with:
from django.contrib.auth.models import Group
from django.db.models import F, Q
Group.objects.filter(
Q(user=None) | Q(user=3)
).annotate(
username=F('user__username')
)
The Group objects that arise from this queryset will have an extra attribute .username with the name of the user. Although this will introduce likely a lot of duplicate data, since the username will be either None (NULL) or the username of the user with id=3.

How to retrieve a single record using icontains in django

I'm trying to query a single record using the following but I get a 500 error.
cdtools = CdTool.objects.get(product=product_record.id,
platform=platform_record.id, url__icontains=toolname)
models.py
class CdTool(models.Model):
product = models.ForeignKey(Product)
platform = models.ForeignKey(Platform)
url = models.CharField(max_length=300)
a model instance has an full url, but in my query 'toolname' is the short form (ie: google instead of https://google.com), so I'm trying to figure out what the correct query would be here. I'm open to modifying models.py as long as there is no data migration stuff involved.

Does PeeWee support interaction with MySQL Views?

I am trying to access pre-created MySQL View in the database via. peewee treating it as a table [peewee.model], however I am still prompted with Operational Error 1054 unknown column.
Does PeeWee Supports interactions with database view ?
Peewee has been able to query against views when I've tried it, but while typing up a simple proof-of-concept I ran into two potential gotcha's.
First, the code:
from peewee import *
db = SqliteDatabase(':memory:')
class Foo(Model):
name = TextField()
class Meta: database = db
db.create_tables([Foo])
for name in ('huey', 'mickey', 'zaizee'):
Foo.create(name=name)
OK -- nothing exciting, just loaded three names into a table. Then I made a view that corresponds to the upper-case conversion of the name:
db.execute_sql('CREATE VIEW foo_view AS SELECT UPPER(name) FROM foo')
I then tried the following, which failed:
class FooView(Foo):
class Meta:
db_table = 'foo_view'
print [fv.name for fv in FooView.select()]
Then I ran into the first issue.
When I subclassed "Foo", I brought along a primary key column named "id". Since I used a bare select() (FooView.select()), peewee assumed i wasnted both the "id" and the "name". Since the view has no "id", I got an error.
I tried again, specifying only the name:
print [fv.name for fv in FooView.select(FooView.name)]
This also failed.
The reason this second query fails can be found by looking at the cursor description on a bare select:
curs = db.execute_sql('select * from foo_view')
print curs.description[0][0] # Print the first column's name.
# prints UPPER(name)
SQLite named the view's column "UPPER(name)". To fix this, I redefined the view:
db.execute_sql('CREATE VIEW foo_view AS SELECT UPPER(name) AS name FROM foo')
Now, when I query the view it works just fine:
print [x.name for x in FooView.select(FooView.name)]
# prints ['HUEY', 'MICKEY', 'ZAIZEE']
Hope that helps.

Querying a for table not defined in models Sqlalchemy

I have this table in my database (using Posgresql and Sqlalchemy) called "participants".
In my models.py I want to access the participant's records. Since participants is not in my models.py and resides as a table in my db, when I do query = db.session.query('participants').order_by('name').all() I get an error:
ProgrammingError: (ProgrammingError) column "participants" does not exist
LINE 1: SELECT participants ORDER BY name
^
What can I do to retrieve this information?
Like the comment on the original post, did something like:
query = db.engine.execute('select * from participants order by name')
This doesn't give it in the same format as the query so I could use it for what I needed (a dictionary output, and a format for web), so I did:
partner_list = []
for record in query:
record_dict = dict(record)
partner_list.append(record_dict)

Categories