Modelis probably what most people will be using the majority of the time. The
Modelis basically an wrapper entity around a table. So 1 table will likely equal to 1 model. A
userstable will have a
Usermodel and a
articlestable will have an
Modelis that its just a shell around the
QueryBuilderclass. The majority of the time you call something on the
Modelit's actually just building a query builder class immediately and passing the rest of the call off. This is important to understand:
.get()which is basically an executionary command:
get, the query builder will pass everything you built up (1 select, 2 where statements) and pass those into a
Grammarclass is responsible for looping through the 3 statements and compiling them into a SQL query that will run. So the
Grammarclass will compile a query that looks like this:
user.namewe will get the name of the user. Think of it as loading the dictionary into the class to be used later during accession and setting.
QueryBuilderclass) and then passed to the connection class to make the database call and return the result. Again the grammar class is only responsible for compiling the query into a string. Simply taking attributes passed to it and looping through them and compiling them into a query.
(18,). This helps protect against SQL injection attacks. All queries passed to the connection class should be the qmark query. Compiling SQL is really for debugging purposes while developing. Passing straight SQL into the connection class could leave queries open to SQL injection.
'?'and then adding the value to the bindings. The grammar class knows it should be qmarked by passing the qmark boolean variable throughout the grammar class.
BaseGrammarclass. Child classes (like
PostgresGrammar, etc) really just contain the formatting of the sql strings.
LIMIT Xand Microsoft is
TOP X. We can accomplish this by specifying the differences in their own method. Remember these are all in the subclasses of the grammar class. Mysql is in
MySQLGrammarand Microsoft is in
BaseGrammarclass (which calls the supported grammar class we built above).
_compile_so let's explain what those are.
BaseGrammarclass which is the parent grammar class and really the engine behind compiling the queries for all grammars.
BaseGrammarclass is responsible for doing the actual compiling in the above section. So this class really just has a bunch of classes like
process_selectsetc. These are more supporting methods that help process the sql strings for the
_compile_. These are for responsable for compiling the actual respective queries. The heart of this class really lies in the
_compilemethods in place:
_compilemethods but they are mainly just for supporting the main compiling of the select, create or alter statements.
QueryBuilder. Most methods on the model simply call the
QueryBuilderso we will focus on the
cls) and an object instance. Be sure to read the section below.
Modelclass (the base class that all of your
Articlemodels will inherit). What this does is essentially creates a middleware between first calling methods. Since its really hard to do everything while handling different class instantances and class classes it's easier to catch the call and turn it into an instance before moving on.
Model.pyclass we have a meta class inherited (you'll notice if you look at the file) which actually does a bit of magic and actually instanitates the class before any methods are called. This is similiar to any normal Python hook you can tie into like
selfmuch easier. Although there are special use cases where we need to handle cls directly which is why you will see some
@classmethoddecorators on some model methods.
User.where(..)it will call the where on the User class. Since theres actually no
wheremethod on the model class it will hook into the
__getattr__on the model class. From there we catch a bunch of different methods located in the
__passthrough__attribute on the model and pass that right off to the query builder. This is important to understand.
QueryBuilderclass is responsible for building up the query so it will have a whole bunch of attributes on it that will eventually be passed off to the grammar class and compiled to SQL. That SQL will then be passed to the connection class and will do the database call to return the result.
QueryBuilderclass is really the meat and potatoes of the ORM and really needs to be perfect and will have the most features and will take the most time to build out and get right.
whereon the model it will pass the info to the query builder and return this
.get()it will return a collection of results.
first()it will return a single model:
QueryBuilderto build up a query and then later execute it.
BaseGrammarclass, since we use things like isinstance checks and attribute conditionals. You will not be using these directly when developing applications. These classes are:
QueryExpression- Used for compiling of where statements
HavingExpression- Used for the compiling of Having statements
JoinExpression- Used for the compiling of Join statements
UpdateExpression- Used for the compiling of Update statements.
SubSelectExpression- Used for compiling sub selects. Sub selects can be placed inside where statements to make complex where statements more powerful
SubGroupExpression- Used to be passed into a callable to be executed on later. This is useful again for sub selects but just a layer of abstraction for callables
_compile_updateand other methods are ran on the grammar class, these just make it more simple to fetch the needed data and are not too generic to make difficult use cases challenging to code for.
.first(), all the wheres, selects, group_by's etc are passed off to the correct grammar class like
MySQLGrammarwhich will then compile down to a SQL string.
QueryBuilderobject when returning the response is also responsible for hydrating your models if a model is passed in. If no model is passed into the initializer then it will just return a dictionary or list. Hydrating is really just a fancy word for filling dummy models with data. We really don't want to work with dictionaries in our project so we take the dictionary response and shove it into a Model and return the model. Now we have a class much more useful than a simple dictionary.
.hydrate()method which creates a new instance and hydrates the instance with the dictionary.
__get__magic method which is called whenever an attribute is accessed. We can then hijack this hook and return whatever we need. In this case, a fully hydrated model or a query builder.
BaseRelationshipclass which really just contains all the magic we need for the actual decorator to work.
BelongsTorelationship (which is imported
as belongs_toin the
__init__.pyfile so this is where the name change comes from in the decorator) which has a simple
apply_querymethod with does the query needed to return the connection using the models
QueryBuilder. Here we have
foreignis the relationship class (In this case,
owneris the current model (in this case
limit. Instead of have things in the format of:
Blueprintclass which really is the same thing as the relationship between
QueryBuilder. The Schema class is also responsible for setting either the
altermodes. This is set if you either use
Blueprintclass is similiar to the
QueryBuilderclass because both simply build up a bunch of columns to to act on. One is just used for fetching data and the other is used for changing or creating tables.
Tableclass. If we are updating a table then we will be setting attributes on the
MySQLPlatform, etc. These class have a compile_create_sql and compile_alter_sql methods. These methods take a single table class. The same table class the blueprint class built up.
blueprint.to_sql()which will either build a
alterquery depending on what was originally set by the