Frappe Database api

How to use Frappe database api

Frappe provides a database api using which you can communicate with the underlying database of your site. In this post we will try different frappe database methods from the python shell.

Start shell

You can start a python shell by issuing the following command:

bench --site <site_name> console

My site name is my.second. I issued the following command

bench --site my.second console

Import the global frappe variable.

In [1]: import frappe

frappe has several attributes. The attribute which encapsulates database connection and is used to communicate with the database is frappe.db.

Any default installation of frappe has a doctype called User which stores user details like username, first_name, email etc. This is the table which stores Administrator detail which is created when you run frappe init <site_name>.

Count

Let’s get a count of User in the database.

In [2]: frappe.db.count('User')
Out[2]: 3

Add few Users using /desk#List/User/List and get the count again.

In [3]: frappe.db.count('User')
Out[3]: 5

You can add filter conditions too in count.

In [4]: frappe.db.count('User', filters={'email': '[email protected]'})
Out[4]: 1

In [7]: frappe.db.count('User', filters={'email': ('like', 'david%')})
Out[7]: 2

In [8]: frappe.db.count('User', filters={'email': ('in', ['[email protected]', '[email protected]'])})
Out[8]: 2

get_values()

You can get all users using following query.

In [39]: users = frappe.db.get_values("User", filters={})

In [40]: users
Out[40]:
((u'Administrator',),
 (u'[email protected]',),
 (u'[email protected]',),
 (u'Guest',),
 (u'[email protected]',))

You can get name and email for all users using following query.

In [41]: users = frappe.db.get_values("User", filters={}, fieldname=["name", "email"])

In [42]: users
Out[42]:
((u'Administrator', u'[email protected]'),
 (u'[email protected]', u'[email protected]'))

Get it as a dict using:

In [43]: users = frappe.db.get_values("User", filters={}, fieldname=["name", "email"], as_dict=True)

In [44]: users
Out[44]:
[{u'email': u'[email protected]', u'name': u'Administrator'},
 {u'email': u'[email protected]',
  u'name': u'[email protected]'}]

Ordering

You can order the results by passing kwarg order_by to get_values().

In [45]: users = frappe.db.get_values("User", filters={}, fieldname=["name", "email"], as_dict=True, order_by='creation')

In [46]: users
Out[46]:
[{u'email': u'[email protected]',
  u'name': u'[email protected]'},
 {u'email': u'[email protected]', u'name': u'Administrator'}]

You can order in descending order using <column_name> desc.

In [47]: users = frappe.db.get_values("User", filters={}, fieldname=["name", "email"], as_dict=True, order_by='creation desc')

In [48]: users
Out[48]:
 [{u'email': u'[email protected]', u'name': u'Administrator'},
 {u'email': u'[email protected]',
  u'name': u'[email protected]'}]

Getting a single row

You can retrieve a single row from db using method get_value().

In [61]: user = frappe.db.get_value("User", filters={"name": "Administrator"}, fieldname="*")

In [62]: user
Out[62]:
{u'_assign': None,
 u'_comments': None,
 u'_liked_by': None,
 u'_user_tags': None,
 u'background_image': None,
 u'background_style': u'Fill Screen',
 .....
 .....
 u'email': u'[email protected]',
 u'email_signature': None,
 u'enabled': 1,
 u'first_name': u'Administrator',
 u'full_name': u'Administrator'}

If there is no row which matches the filter criteria then get_value() would return None.

user = frappe.db.get_value("User", filters={"name": "jhhooreqereee"}, fieldname="*")
In [65]: print(user)
None

If you are filtering by name column, then you can send filters kwarg as a string instead of as a dictionary.

In [66]: user = frappe.db.get_value("User", filters="Administrator")

Infact you can send it as an arg and not as a kwarg.

In [66]: user = frappe.db.get_value("User", "Administrator")

There is even a shorter way of achieving the above result. If you want all the fields of the document and are filtering by name, then you don’t need to use get_value(). You can use get() in such cases.

In [67]: user = frappe.db.get("User", "Administrator")

Raw query

You can run raw sql queries too with frappe.

Get username for all users.

In [9]: users = frappe.db.sql("select name from tabUser");

In [10]: users
Out[10]:
((u'[email protected]',),
 (u'Guest',),
 (u'Administrator',),
 (u'[email protected]',),
 (u'[email protected]',))

You can get the results as a dictionary where each table column would be mapped to the corresponding value.

In [13]: users = frappe.db.sql("select name, email from tabUser", as_dict=True);

In [14]: users
Out[14]:
[{u'email': u'[email protected]', u'name': u'Administrator'},
 {u'email': u'[email protected]',
  u'name': u'[email protected]'}]

Or you can get the results as a list and not as a dict. In this case every db row would be returned as a list.

In [15]: users = frappe.db.sql("select name, email from tabUser", as_list=True);

In [16]: users
Out[16]:
[[u'Administrator', u'[email protected]'],
 [u'[email protected]', u'[email protected]']]

You can do joins in frappe.db.sql(). Default Frappe installation creates a User table called tabUser and Language table called tabLanguage. User has a link field to Language. If we want to find language_code for language associated with each user we can do in following way.

In [35]: users = frappe.db.sql("select u.name, l.language_code from tabUser as u inner join tabLanguage as l on u.language=l.name", as_dict=True);

In [36]: users
Out[36]:
[{u'language_code': u'en', u'name': u'[email protected]'},
 {u'language_code': u'en', u'name': u'[email protected]'},
 {u'language_code': u'en', u'name': u'[email protected]'}]

With frappe.db.sql you can essentially do anything you are allowed to do with plain sql.

Thank you for reading the Agiliq blog. This article was written by Akshar on Jul 15, 2018 in pythonerpnextfrappe .

You can subscribe ⚛ to our blog.

We love building amazing apps for web and mobile for our clients. If you are looking for development help, contact us today ✉.

Would you like to download 10+ free Django and Python books? Get them here