-
Notifications
You must be signed in to change notification settings - Fork 30
5.0 step6 correction
It is a domain on "A", which should look like:
domain=[If(
~Eval('B') | ~Eval('C'),
[('A', '=', 0)],
If(Eval('B') > Eval('C'),
[('A', '>', 0)],
[]))]
On the first condition, the |
operator operands do not need to be wrapped
in parenthesis, because ~
has a higher priority. We must do the checks in
this order, because evaluating the comparison on empty elements may return
True
. Note how nested If
can quickly become hard to read.
This one is not possible as is. As explained, you cannot Eval('B.x')
.
Usually, this kind of problem could be solved by defining a new Function
field B_x
which contains the value that we need, then using this field in
the following domain:
domain=[If(
Eval('B_x') > 0,
[('x', '!=', 0)],
[])]
This situation is even harder. There is no way to use a domain (for the same
reason than above). The sole solution would be to add a Function
field on
the model of "A" with a searcher that checks for this condition, and use it
in the domain.
It is a domain on "A":
domain=['OR', ('x', '>=', Eval('B')), ('x', '=', Eval('C'))]
Update the death_date
field as such:
death_date = fields.Date('Death date',
domain=['OR', ('death_date', '=', None),
('death_date', '>', Eval('birth_date'))],
states={'invisible': ~Eval('birth_date')},
depends=['birth_date'])
The domain is usually set before the states, which are themselves before the
depends. This is a question of priority, domains are "more important" than
states (apart from the required
states, they are not important server
side), which are more important than depends (they are just a technical
information).
The 'OR'
in the domain is important, because without it an empty end_date
will be invalid. Another tweak could be to check the value of birth_date
in
the domain to avoid comparing to an empty value, however since birth_date
is required once death_date
is set, it is not critical.
Update the states for latest_book
and genres
of library.author
:
states={'invisible': ~Eval('books', False)}
Remember that for Function
fields, the states
(and domain
)
parameters are to be set in the "inner" field.
Here there are no need to add the depends because the books
field may not
be displayed. In fact, if you have lists that you expect to frequently have
over a hundred elements, you should avoid displaying them directly in the main
object (there are other UI options to show them). Because depends
is empty,
setting a default value for Eval('books')
is a good idea (not doing so
could lead to client crashes if books
field is not displayed in the view).
This one is not exactly possible as is. We are in the case where we would have to write:
domain=[('genre', 'in', Eval('editor.genres'))]
which as we explained above and in the pyson / domain exercises is not possible.
There are multiple solutions to this problem:
- Adding a
editor_genres
Function
field on books and using it in the domain - Setting the constraint the other way around (limit possible editors to those that deal in the book's genre)
- The mystery best answer
The first possibility seems not so bad. However, when the book is being
created, the field will be empty, because Function
fields are only
calculated when the record is saved. So that will make it hard to use, having
to select the editor, then save, so that finally the genre can be set.
Note: There is actually a way to do this properly, we will talk about it later
The second is good, but feels more like a hack. Wa cannot set the constraint where we want, so we find another way to ensure consistency. It is a solution that you will often use if you cannot find another way around.
The third is to add a new editors
field on the library.genre
model. As
explained in step 2, since there already is a Many2Many
field
between the two models, this field is "free" in terms of database management,
and can be declared as follow:
editors = fields.Many2Many('library.editor-library.genre', 'genre',
'editor', 'Editors', readonly=True)
We can reuse the same model for the middle table, and just swap the two field names to read the table "the other way around". We set it readonly, because we want the users to add genres to editors (the opposite does not feel logical, though it is technically possible). It is not necessary to show this field in the view, it is only declared (for now) for technical purposes.
Now we can add our domain on the genre
field:
domain=[('editors', '=', Eval('editor'))]
You must add the editor
in the field's depends
.
Whichever solution is chosen may cause problems if you need to add a new genre
to the editor. Of course you can use the Editor
entry point to do so,
but if you imagine a "huge" library, the users which will create books in the
application may not be the same that those who manage editors, but this is a
"good" problem. We will talk about access rights extensively later.
This one obvsiouly cannot be done via domains or states, the right tool being validate. We already used it to make sure our string was actually a number, we will now expand it to validate the checksum:
@classmethod
def __setup__(cls):
super(Book, cls).__setup__()
cls._error_messages.update({
'invalid_isbn': 'ISBN should only be digits',
'bad_isbn_size': 'ISBN must have 13 digits',
'invalid_isbn_checksum': 'ISBN checksum invalid',
})
@classmethod
def validate(cls, books):
for book in books:
if not book.isbn:
continue
try:
if int(book.isbn) < 0:
raise ValueError
except ValueError:
cls.raise_user_error('invalid_isbn')
if len(book.isbn) != 13:
cls.raise_user_error('bad_isbn_size')
checksum = 0
for idx, digit in enumerate(book.isbn):
checksum += int(digit) * (1 if idx % 2 else 3)
if checksum % 10:
cls.raise_user_error('invalid_isbn_checksum')
This is more of a python problem, you should take the time to figure out how it works if you are new to it.
It is a typical use case for a SQL constraint. The tuple author / title must be
unique for books. In the __setup__
of library.book
:
t = cls.__table__()
cls._sql_constraints += [
('author_title_uniq', Unique(t, t.author, t.title),
'The title must be unique per author!'),
]