Building a custom model field from the ground up
CC Attribution 3.0 Unported:
You are free to use, adapt and copy, distribute and transmit the work or content in adapted or unchanged form for any legal purpose as long as the work is attributed to the author in the manner specified by the author or licensor.
Dygalo, Dmitry
A comprehensive guide on building custom models fields in Django. Including descriptors, lookups, expressions and many more. Often you need to map domain entities onto your application and store them in a database. Django provides you with a very extensible API that allows you to integrate domain entities with ORM seamlessly. This talk will walk through all essential steps in building a Money instances support for Django from the ground, based on real-life examples taken from django-money library. Here is an overview of the talk structure: Historical notes on django-money project. Implementing a field for Money Connecting py-moneyed with Django. Map Money to Model What field to choose? Implicit currency field How descriptors could help here? Querying MoneyField Designing the API Lookup API vs. old style model managers surgery Expressions. Enhancing Money class Extras: Integrating Django admin. Utilizing AppConfig.ready Serialization Validators Migrations. Deconstruction & backends differences Testing
 So now I have the pleasure of introducing Dimitri De Gallo. That's right. Yeah, OK, great. Building a custom model field from the ground up. Hello, everybody. Can you hear me? Cool. So I'm Dimitri, and I'm working at qi.com as a technical team lead. I'm located in Prague, Czech Republic. I do Python from 2010. I command a couple of open source projects like Django Money. And I love open source and traveling. So who use custom model fields? Could you raise your hands? Nice. Who tried to build your own? Cool. OK, so basically, why do we need it? First, use case is when we need to map some custom database types into Python objects. And the other way around, store some complex Python objects in the database. So it's two ways. Interaction. And there is a use case for it. The project is called Django Money. It provides you money and currency objects and integrates everything into Django ORM. Also, it has forms, admin integration, template tags, Django REST framework integration, currency rates, stuff like this. This project is kind of made sure it was started in 2011 as a fork of another project. I started to committing to it in 2013. And I used it in my previous job. I started to maintain it a couple of years ago. And the interesting fact is that there are two maintainers here on the conference. And I first time meet Benjamin here after six years of working together on the project. Woo! Hey. A little overview of the topics that we will cover today. First of all, we will inspect the storage level. How to map money to model. What are the queries underneath? How the scripters could help you? Then we will make some queries. We'll try to look up API and introduce some expressions and some extras like migrations, serialization, validation, stuff like this. So let's go for storage. In our domain, we have money. Basically, it consists of two things, amount and currency. And we can use it like this. So we have money, amount, currency. We have decimal and string. Also, we can use some arithmetic, like addition, subtraction, some other operation. Also, we can localize the representation, depending on the locale we want to use. And I have a question for you. Who use decimal or numeric type for storing money? Floating point types? Couple of integers? OK. I believe that the preferred way is to use decimal or numeric for storing it, because otherwise, you could face precision loss in most of the cases. So we need to map these to our beautiful model. For example, we have item to buy. And we have simple name and our new money field. So I would recommend to start always with designing the interface of how you would use your new field. So basically, we need some basic operations, create, get, update. It could be done in different ways, but there are some examples in the code. So save, get, some f is safe and refreshing. No complex queries yet. And I really recommend you to make the test cases from these expectations from your interface. Just like this. Or you can use built-in Django test cases or use pytest, whatever you think will fit here. So on the storage level, we can approach in different ways. For example, we can store data in different fields, as we do in Django money, which is not really good in all cases. So it's standard scale. And unfortunately, managing two fields at once is not trivial in all cases. I will show you some examples of the consequences of such decisions. OK, how can we connect it to the database? We have our money, and we need to store amount in the decimal field and currency in the char field and underlying data types in the database are numeric and voucher. And how we would do it on the Python level? There is a nice, nice thing called descriptors. And basically, it allows you to customize attribute access. So get, set, or delete, you can customize these things, actually. And in our case, we need to build a money instance when we're getting something from the field. And we need to set another field when we are setting something to this price field. So for this purpose, we can utilize contribute to class and add also these currency fields there. But does it seem hacky to you? Who think that it's a hacky approach? Yes. There is a nice alternative called structure type. It's from SQL 1999, I believe. And it implies the usual way of implementing custom fields, because it's much easier to map one field from database to one field in Django. In Postgres, you can, for example, create type Django money as amount and currency of certain types. And the queries will be a bit different. So you need to utilize brackets a little bit more. But surprisingly, it's not supported by mySQL. I believe 20 years is not enough. And also, you would have some overhead for attribute access, because you need to get the tuple with the data and then extract some field from the structure type. But however, it could be mitigated with using indexes. In the worst case, for example, in SQL scan, you will have to evaluate the condition for ishero. But for index only scan, you will get everything from the index. So there are some ways to mitigate it. And how we can implement these two ways of communication? In Django, fields provide you with a couple of different methods. And we need basically two of them from DB value. And here, we need to construct the money instance from some DB level string or other object. And get prep value, we need to construct database level instances. And a little disclaimer, some examples are a little bit sloppy, because there are no corner cases and maybe some error validation. But I would like to emphasize that it's only core actions that you need to make. And also, there are many other places to extend. These are the basic ones. Sir, for the first part, the summary is design the interface first and use it as a test cases. Discover your database queries, because you need to map Python to database. You need to know both sites. Decide on your database support. If you really need to be database agnostic, or maybe you work on Postgres and you're happy with it, up to you. And one field is simpler than multiple fields on Django level, at least. Try structure types for composite values, school feature. OK, let's make some queries. Basically, we can make some lookups, transforms, use some expressions. Like, we need to have some items that price is greater than 10 euros, or only Danish crowns as a currency, or maybe only amount more than 100, or price is equal to some other field. Define your behavior unambiguously, first of all, and inspect your database queries again. So basically, these lookups and transforms could look like this on the database level. You will need this transformation a bit later. So I believe from Django 1.8, there is a lookup API. That's a really, really cool thing. You need to basically define your lookup and register it with register lookup. It's here. So basically, what you need to do is to emit some SQL and some parameters for your queries on the database level. There are a lot of existing lookups that you can reuse. However, the best thing is that you need some SQL as an output. So you need to construct left side, right side, and parameters. For transforms, like extracting some certain subfields from the structure type, you can utilize a similar thing called transform. You need to, again, create some SQL as an output and have some output field for amount. It's decimal field. And for currencies, char field, basically. If you will go this way, a basic expression should work out of the box. For example, here we have some number of items. And we'll use an annotate works just out of the box. Maybe some order by and some other simple expressions. But if you need to use something more sophisticated with f expressions, for example, you need to extend here domain because it's not aware of Django at all. So here, with money, we have magic methods for addition, subtraction, and so on. So we need to add a knowledge of expressions from Django like it is an example. So also, you need to adapt your locup implementation because it's also not aware yet about the expressions. So you need to handle it as well. And for structure types, you could create, for example, your own expressions, like subcolumn or something similar, and use it like this to make some custom queries. So create custom expressions if needed. The summary for the querying part is pretty much the same. You need to define your lookups, transforms, and behavior unambiguously. You need to know your database queries and map these Python things to database things. Use lookup API to build desired queries. It's really nice, too. We started the project when it was like Django 1.0.3.4. And there are a lot of different hacks to have the same behavior. So I really recommend to use lookup API instead. Extend magic methods on your domain entities for fExpressions support and create custom expressions for your structured types if you needed. OK, extras. At some point, you might need to migrate your data, so migrations. For this case, you need to, first of all, extend the construct method on the class of your field. In this case, you will have your custom options in migrations. Also, your domain entities are not aware about migrations. You could use the constructable decorator to add this support. So if you want to have some default value like this, you need to wrap your domain entities in this decorator. Serialization. So maybe you would like to use fixtures or something like this. You need to define. You need to have a module with two things, a serializer class and a serializer callable. And for example, this implementation hooks in value from field. And for our custom structured type, we emit a dictionary that contains these nested fields. And here is the result, nested field. For this serialization support, we need to update our get prep value because in this case, we will have a dictionary. So update it, and it will work. After it, we need to register our serialization module. And the good place is app config. Basically, you can define default app config. And in this case, ready will be fired after in some time when Django installs. At some point, maybe you would like to validate your fields somehow. Like set some minimum values, some maximum for different currencies, something like this. And Django provides you with a lot of tools already built, like validators for minimum values, maximum values. You need to extend it a little bit to work with your domain instances. In this case, we have different boundaries for amount and for certain currencies. So you can define anything you want. A bad example of consequences of some decisions, like having two different fields and working through deco, through descriptors. Descriptors, right. This is because we need to, in Django and we need to hook some modules, we need to update some functions inside in runtime. It's really, really hacky. And I would not recommend to do it ever. But it was like six years ago, we didn't have many options like hookup API and stuff like this. But for structure types, it will work out of the box. OK, so the summary for the third part. Extend existing tools from Django. There are a lot of them, really. Validators, serializers, migrations, everything is there, but you need to extend it in certain points. Use application config to register your extensions. Think about possible use cases for your field. Maybe you don't need serialization or something like this. OK, and summary for the talk. Always start with the interface design first. You need to know what you expect from your custom field and use it for your test. Explore underlying database queries, because it's really important because you need to map to worlds Python databases. Experiment with your implementation. Choose the most simple and unambiguous. And try to evaluate possible consequences of chosen approach, because we have maybe 70% of the code that works only for supporting new things like lookup API and similar behavior that is in Django from some point. But we went another way, and we need to have a lot of hacks for it. So Django provides you with a lot of extendable tools for mapping your domain entities to the database. Use them. It's all I have. Thank you very much. Thank you. Questions. Awesome. We have about six minutes for questions. That means we can do about three, four questions. Just a reminder that you can do it online with DjangoCon QA hashtag and the IRC channel. Thank you. Great thought. Thanks. Structured types is new to me. I'm sorry if I missed it, but what was the approach you took for creating a structured type via Django migration? Once again, please. Creating a structured type via Django migration. Yeah, yeah. It's possible, or you need to run this skill. Like I had an example create type, name of the type, as some structure. It would work. I see. But I don't want to ask you all about migration. Yes. OK. Cool. Maybe in some newer Django versions, it could be supported. I don't know. Another question about migrations. You mentioned the construct that is needed for creating the field type. But did you also need to make special migration operations to add specific migration operations to support your field type? And if so, how did you go about that? OK. Basically, it depends on the database. I believe that in Postgres, you still have alter type stuff like this. However, I'm not sure about the others. But in general case, yes, you need to define your extension for some alter field or something like this. Basically, it's probably the most frequent use case, I believe. So yes. And when you do define these sort of operations, then the Django auto migration creator will not use them, will not determine them. You need to use it manually. As far as I know, maybe something changed. Hi. Hello. I didn't know about this that you can register your serializer with Django. Do you know if it's also picked up by the Django rest framework? Oh, I don't know. If it's in Django and currently, for example, in Django money, basically we replace gson serializer with our own to add this support. So it should be used because it's in Django. But for Django rest framework, you probably need a little bit more, like not regarding sterilization, but having support for this type of fields in serializers, for example. OK, thanks. Any other questions, please? Questions online? Oh, I have someone coming. Hi. What do you think about using a JSON field if you have more than two things to store? Yes. JSON is a bit different. However, I think it could be used. There is no decimal in JSON standard, right? It's only floating for it. So for this exact use case, I wouldn't recommend to use it because of the precision loss by default. Or you can use string, maybe, and wrap it somehow. So it could be used. Yes, as an option. But I don't know about the performance issues or stuff like this. It could be similar, most probably. Hey, I'm wondering if you can use aggregate functions like sum and average and all of that using the fields. Does it work? I believe only count stuff. It will work out of the box. But for average, you still need to extract amount part out of it. And in plain SQL, it will be average of square brackets dot amount, for example. So you need to compile this SQL. So basically, you need to extend a little bit of these aggregates to have a support for it. We have time for about one more question. Isn't it a little bit redundant? Normally, you have one row in the database, and everything is in the same currency. So isn't it a bit redundant to always keep that? And that's another answer to the question before. If you do aggregates, you don't want to sum up, let's say, Danish Krona and euros together, because it doesn't make any sense. It depends on the use case. For example, I usually work with card transactions, for example, for these payments. And we store different currencies. And we need to aggregate by different currency. So I would say it's more implementation-wise, because having two fields is a bit more complex. And having one field is always an option. It's a trade-off. You have a little bit of simpler implementation, but you have limited database support and maybe some performance downgrade. So it's things to consider for your use case. You always need to consider all these factors. But in some case, it could help to reduce some complexity from your code. In some cases, not. So in your case, you have sometimes a row with a lot of different amounts and different currencies? I would say that we have different amounts of the same row. Yeah, yeah. Yes, I mean like different monies. OK. Yes. Thank you so much. Ah. Thank you.
 So now I have the pleasure of introducing Dimitri De Gallo.  That's right.  Yeah, OK, great.  Building a custom model field from the ground up.  Hello, everybody.  Can you hear me?  Cool.  So I'm Dimitri, and I'm working at qi.com  as a technical team lead.  I'm located in Prague, Czech Republic.  I do Python from 2010.  I command a couple of open source projects like Django Money.  And I love open source and traveling.  So who use custom model fields?  Could you raise your hands?  Nice.  Who tried to build your own?  Cool.  OK, so basically, why do we need it?  First, use case is when we need to map some custom database  types into Python objects.  And the other way around, store some complex Python objects  in the database.  So it's two ways.  Interaction.  And there is a use case for it.  The project is called Django Money.  It provides you money and currency objects  and integrates everything into Django ORM.  Also, it has forms, admin integration, template  tags, Django REST framework integration,  currency rates, stuff like this.  This project is kind of made sure it was started in 2011  as a fork of another project.  I started to committing to it in 2013.  And I used it in my previous job.  I started to maintain it a couple of years ago.  And the interesting fact is that there  are two maintainers here on the conference.  And I first time meet Benjamin here  after six years of working together on the project.  Woo!  Hey.  A little overview of the topics that we will cover today.  First of all, we will inspect the storage level.  How to map money to model.  What are the queries underneath?  How the scripters could help you?  Then we will make some queries.  We'll try to look up API and introduce some expressions  and some extras like migrations, serialization,  validation, stuff like this.  So let's go for storage.  In our domain, we have money.  Basically, it consists of two things, amount and currency.  And we can use it like this.  So we have money, amount, currency.  We have decimal and string.  Also, we can use some arithmetic, like addition, subtraction,  some other operation.  Also, we can localize the representation,  depending on the locale we want to use.  And I have a question for you.  Who use decimal or numeric type for storing money?  Floating point types?  Couple of integers?  OK.  I believe that the preferred way is  to use decimal or numeric for storing it,  because otherwise, you could face precision loss  in most of the cases.  So we need to map these to our beautiful model.  For example, we have item to buy.  And we have simple name and our new money field.  So I would recommend to start always  with designing the interface of how  you would use your new field.  So basically, we need some basic operations, create, get,  update.  It could be done in different ways,  but there are some examples in the code.  So save, get, some f is safe and refreshing.  No complex queries yet.  And I really recommend you to make the test cases  from these expectations from your interface.  Just like this.  Or you can use built-in Django test cases  or use pytest, whatever you think will fit here.  So on the storage level, we can approach in different ways.  For example, we can store data in different fields,  as we do in Django money, which is not really good in all cases.  So it's standard scale.  And unfortunately, managing two fields at once  is not trivial in all cases.  I will show you some examples of the consequences  of such decisions.  OK, how can we connect it to the database?  We have our money, and we need to store  amount in the decimal field and currency in the char field  and underlying data types in the database  are numeric and voucher.  And how we would do it on the Python level?  There is a nice, nice thing called descriptors.  And basically, it allows you to customize attribute access.  So get, set, or delete, you can customize these things,  actually.  And in our case, we need to build a money instance  when we're getting something from the field.  And we need to set another field when we are setting something  to this price field.  So for this purpose, we can utilize contribute to class  and add also these currency fields there.  But does it seem hacky to you?  Who think that it's a hacky approach?  Yes.  There is a nice alternative called structure type.  It's from SQL 1999, I believe.  And it implies the usual way of implementing custom fields,  because it's much easier to map one field from database  to one field in Django.  In Postgres, you can, for example,  create type Django money as amount  and currency of certain types.  And the queries will be a bit different.  So you need to utilize brackets a little bit more.  But surprisingly, it's not supported by mySQL.  I believe 20 years is not enough.  And also, you would have some overhead for attribute access,  because you need to get the tuple with the data  and then extract some field from the structure type.  But however, it could be mitigated with using indexes.  In the worst case, for example, in SQL scan,  you will have to evaluate the condition for ishero.  But for index only scan, you will get everything  from the index.  So there are some ways to mitigate it.  And how we can implement these two ways of communication?  In Django, fields provide you with a couple of different methods.  And we need basically two of them from DB value.  And here, we need to construct the money instance  from some DB level string or other object.  And get prep value, we need to construct  database level instances.  And a little disclaimer, some examples  are a little bit sloppy, because there are no corner cases  and maybe some error validation.  But I would like to emphasize that it's only  core actions that you need to make.  And also, there are many other places to extend.  These are the basic ones.  Sir, for the first part, the summary  is design the interface first and use it as a test cases.  Discover your database queries, because you  need to map Python to database.  You need to know both sites.  Decide on your database support.  If you really need to be database agnostic,  or maybe you work on Postgres and you're happy with it,  up to you.  And one field is simpler than multiple fields  on Django level, at least.  Try structure types for composite values, school feature.  OK, let's make some queries.  Basically, we can make some lookups,  transforms, use some expressions.  Like, we need to have some items that price is greater  than 10 euros, or only Danish crowns as a currency,  or maybe only amount more than 100,  or price is equal to some other field.  Define your behavior unambiguously, first of all,  and inspect your database queries again.  So basically, these lookups and transforms  could look like this on the database level.  You will need this transformation a bit later.  So I believe from Django 1.8, there is a lookup API.  That's a really, really cool thing.  You need to basically define your lookup  and register it with register lookup.  It's here.  So basically, what you need to do  is to emit some SQL and some parameters for your queries  on the database level.  There are a lot of existing lookups that you can reuse.  However, the best thing is that you need some SQL as an output.  So you need to construct left side, right side,  and parameters.  For transforms, like extracting some certain subfields  from the structure type, you can utilize a similar thing  called transform.  You need to, again, create some SQL as an output  and have some output field for amount.  It's decimal field.  And for currencies, char field, basically.  If you will go this way, a basic expression  should work out of the box.  For example, here we have some number of items.  And we'll use an annotate works just out of the box.  Maybe some order by and some other simple expressions.  But if you need to use something more sophisticated  with f expressions, for example, you  need to extend here domain because it's not  aware of Django at all.  So here, with money, we have magic methods  for addition, subtraction, and so on.  So we need to add a knowledge of expressions from Django  like it is an example.  So also, you need to adapt your locup implementation  because it's also not aware yet about the expressions.  So you need to handle it as well.  And for structure types, you could create, for example,  your own expressions, like subcolumn or something similar,  and use it like this to make some custom queries.  So create custom expressions if needed.  The summary for the querying part is pretty much the same.  You need to define your lookups, transforms,  and behavior unambiguously.  You need to know your database queries  and map these Python things to database things.  Use lookup API to build desired queries.  It's really nice, too.  We started the project when it was like Django 1.0.3.4.  And there are a lot of different hacks  to have the same behavior.  So I really recommend to use lookup API instead.  Extend magic methods on your domain entities  for fExpressions support and create custom expressions  for your structured types if you needed.  OK, extras.  At some point, you might need to migrate your data, so  migrations.  For this case, you need to, first of all,  extend the construct method on the class of your field.  In this case, you will have your custom options in migrations.  Also, your domain entities are not aware about migrations.  You could use the constructable decorator to add this support.  So if you want to have some default value like this,  you need to wrap your domain entities in this decorator.  Serialization.  So maybe you would like to use fixtures or something like this.  You need to define.  You need to have a module with two things, a serializer class  and a serializer callable.  And for example, this implementation  hooks in value from field.  And for our custom structured type,  we emit a dictionary that contains these nested fields.  And here is the result, nested field.  For this serialization support, we  need to update our get prep value because in this case,  we will have a dictionary.  So update it, and it will work.  After it, we need to register our serialization module.  And the good place is app config.  Basically, you can define default app config.  And in this case, ready will be fired after in some time  when Django installs.  At some point, maybe you would like  to validate your fields somehow.  Like set some minimum values, some maximum  for different currencies, something like this.  And Django provides you with a lot of tools already built,  like validators for minimum values, maximum values.  You need to extend it a little bit  to work with your domain instances.  In this case, we have different boundaries for amount  and for certain currencies.  So you can define anything you want.  A bad example of consequences of some decisions,  like having two different fields and working through deco,  through descriptors.  Descriptors, right.  This is because we need to, in Django  and we need to hook some modules,  we need to update some functions inside in runtime.  It's really, really hacky.  And I would not recommend to do it ever.  But it was like six years ago, we  didn't have many options like hookup API and stuff like this.  But for structure types, it will work out of the box.  OK, so the summary for the third part.  Extend existing tools from Django.  There are a lot of them, really.  Validators, serializers, migrations, everything  is there, but you need to extend it in certain points.  Use application config to register your extensions.  Think about possible use cases for your field.  Maybe you don't need serialization  or something like this.  OK, and summary for the talk.  Always start with the interface design first.  You need to know what you expect from your custom field  and use it for your test.  Explore underlying database queries,  because it's really important because you  need to map to worlds Python databases.  Experiment with your implementation.  Choose the most simple and unambiguous.  And try to evaluate possible consequences of chosen approach,  because we have maybe 70% of the code that works only  for supporting new things like lookup API  and similar behavior that is in Django from some point.  But we went another way, and we need  to have a lot of hacks for it.  So Django provides you with a lot of extendable tools  for mapping your domain entities to the database.  Use them.  It's all I have.  Thank you very much.  Thank you.  Questions.  Awesome.  We have about six minutes for questions.  That means we can do about three, four questions.  Just a reminder that you can do it online with DjangoCon QA  hashtag and the IRC channel.  Thank you.  Great thought.  Thanks.  Structured types is new to me.  I'm sorry if I missed it, but what was the approach you took  for creating a structured type via Django migration?  Once again, please.  Creating a structured type via Django migration.  Yeah, yeah.  It's possible, or you need to run this skill.  Like I had an example create type, name of the type,  as some structure.  It would work.  I see.  But I don't want to ask you all about migration.  Yes.  OK.  Cool.  Maybe in some newer Django versions,  it could be supported.  I don't know.  Another question about migrations.  You mentioned the construct that is needed  for creating the field type.  But did you also need to make special migration operations  to add specific migration operations  to support your field type?  And if so, how did you go about that?  OK.  Basically, it depends on the database.  I believe that in Postgres, you still  have alter type stuff like this.  However, I'm not sure about the others.  But in general case, yes, you need  to define your extension for some alter field  or something like this.  Basically, it's probably the most frequent use case,  I believe.  So yes.  And when you do define these sort of operations,  then the Django auto migration creator  will not use them, will not determine them.  You need to use it manually.  As far as I know, maybe something changed.  Hi.  Hello.  I didn't know about this that you can register your serializer  with Django.  Do you know if it's also picked up by the Django rest framework?  Oh, I don't know.  If it's in Django and currently, for example, in Django money,  basically we replace gson serializer with our own  to add this support.  So it should be used because it's in Django.  But for Django rest framework, you probably  need a little bit more, like not regarding  sterilization, but having support for this type of fields  in serializers, for example.  OK, thanks.  Any other questions, please?  Questions online?  Oh, I have someone coming.  Hi.  What do you think about using a JSON field  if you have more than two things to store?  Yes.  JSON is a bit different.  However, I think it could be used.  There is no decimal in JSON standard, right?  It's only floating for it.  So for this exact use case, I wouldn't recommend  to use it because of the precision loss by default.  Or you can use string, maybe, and wrap it somehow.  So it could be used.  Yes, as an option.  But I don't know about the performance issues or stuff  like this.  It could be similar, most probably.  Hey, I'm wondering if you can use aggregate functions  like sum and average and all of that using the fields.  Does it work?  I believe only count stuff.  It will work out of the box.  But for average, you still need to extract  amount part out of it.  And in plain SQL, it will be average of square brackets  dot amount, for example.  So you need to compile this SQL.  So basically, you need to extend a little bit  of these aggregates to have a support for it.  We have time for about one more question.  Isn't it a little bit redundant?  Normally, you have one row in the database,  and everything is in the same currency.  So isn't it a bit redundant to always keep that?  And that's another answer to the question before.  If you do aggregates, you don't want to sum up, let's say,  Danish Krona and euros together, because it doesn't make  any sense.  It depends on the use case.  For example, I usually work with card transactions,  for example, for these payments.  And we store different currencies.  And we need to aggregate by different currency.  So I would say it's more implementation-wise,  because having two fields is a bit more complex.  And having one field is always an option.  It's a trade-off.  You have a little bit of simpler implementation,  but you have limited database support and maybe  some performance downgrade.  So it's things to consider for your use case.  You always need to consider all these factors.  But in some case, it could help to reduce some complexity  from your code.  In some cases, not.  So in your case, you have sometimes a row  with a lot of different amounts and different currencies?  I would say that we have different amounts of the same row.  Yeah, yeah.  Yes, I mean like different monies.  OK.  Yes.  Thank you so much.  Ah.  Thank you.
DjangoCon_2019_-_Building_a_custom_model_field_from_the_ground_up_0_311.png DjangoCon_2019_-_Building_a_custom_model_field_from_the_ground_up_312_359.png DjangoCon_2019_-_Building_a_custom_model_field_from_the_ground_up_360_431.png DjangoCon_2019_-_Building_a_custom_model_field_from_the_ground_up_432_491.png DjangoCon_2019_-_Building_a_custom_model_field_from_the_ground_up_492_575.png DjangoCon_2019_-_Building_a_custom_model_field_from_the_ground_up_576_647.png DjangoCon_2019_-_Building_a_custom_model_field_from_the_ground_up_648_707.png DjangoCon_2019_-_Building_a_custom_model_field_from_the_ground_up_708_887.png DjangoCon_2019_-_Building_a_custom_model_field_from_the_ground_up_888_1079.png DjangoCon_2019_-_Building_a_custom_model_field_from_the_ground_up_1080_4655.png DjangoCon_2019_-_Building_a_custom_model_field_from_the_ground_up_4656_5831.png DjangoCon_2019_-_Building_a_custom_model_field_from_the_ground_up_5832_7055.png DjangoCon_2019_-_Building_a_custom_model_field_from_the_ground_up_7056_7367.png DjangoCon_2019_-_Building_a_custom_model_field_from_the_ground_up_7368_8171.png DjangoCon_2019_-_Building_a_custom_model_field_from_the_ground_up_8172_8735.png DjangoCon_2019_-_Building_a_custom_model_field_from_the_ground_up_8736_9587.png DjangoCon_2019_-_Building_a_custom_model_field_from_the_ground_up_9588_9863.png DjangoCon_2019_-_Building_a_custom_model_field_from_the_ground_up_9864_11987.png DjangoCon_2019_-_Building_a_custom_model_field_from_the_ground_up_11988_13451.png DjangoCon_2019_-_Building_a_custom_model_field_from_the_ground_up_13452_14627.png DjangoCon_2019_-_Building_a_custom_model_field_from_the_ground_up_14628_15311.png DjangoCon_2019_-_Building_a_custom_model_field_from_the_ground_up_15312_15743.png DjangoCon_2019_-_Building_a_custom_model_field_from_the_ground_up_15744_16787.png DjangoCon_2019_-_Building_a_custom_model_field_from_the_ground_up_16788_17579.png DjangoCon_2019_-_Building_a_custom_model_field_from_the_ground_up_17580_18155.png DjangoCon_2019_-_Building_a_custom_model_field_from_the_ground_up_18156_19175.png DjangoCon_2019_-_Building_a_custom_model_field_from_the_ground_up_19176_21659.png DjangoCon_2019_-_Building_a_custom_model_field_from_the_ground_up_21660_21803.png DjangoCon_2019_-_Building_a_custom_model_field_from_the_ground_up_21804_22403.png DjangoCon_2019_-_Building_a_custom_model_field_from_the_ground_up_22404_23315.png DjangoCon_2019_-_Building_a_custom_model_field_from_the_ground_up_23316_23627.png DjangoCon_2019_-_Building_a_custom_model_field_from_the_ground_up_23628_24335.png DjangoCon_2019_-_Building_a_custom_model_field_from_the_ground_up_24336_24983.png DjangoCon_2019_-_Building_a_custom_model_field_from_the_ground_up_24984_25415.png DjangoCon_2019_-_Building_a_custom_model_field_from_the_ground_up_25416_26723.png DjangoCon_2019_-_Building_a_custom_model_field_from_the_ground_up_26724_30323.png DjangoCon_2019_-_Building_a_custom_model_field_from_the_ground_up_30324_30527.png DjangoCon_2019_-_Building_a_custom_model_field_from_the_ground_up_30528_30719.png DjangoCon_2019_-_Building_a_custom_model_field_from_the_ground_up_30720_33131.png DjangoCon_2019_-_Building_a_custom_model_field_from_the_ground_up_33132_33191.png DjangoCon_2019_-_Building_a_custom_model_field_from_the_ground_up_33192_33395.png DjangoCon_2019_-_Building_a_custom_model_field_from_the_ground_up_33396_39576.png