(window.webpackJsonp=window.webpackJsonp||[]).push([[162],{686:function(t,a,s){"use strict";s.r(a);var e=s(56),n=Object(e.a)({},(function(){var t=this,a=t.$createElement,s=t._self._c||a;return s("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[s("h1",{attrs:{id:"receive-and-validate-data-using-wtforms"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#receive-and-validate-data-using-wtforms"}},[t._v("#")]),t._v(" Receive and validate data using WTForms")]),t._v(" "),s("div",{staticClass:"custom-block tip"},[s("p",{staticClass:"custom-block-title"},[t._v("TIP")]),t._v(" "),s("p",[t._v("List of all code changes made in this lecture: "),s("a",{attrs:{href:"https://diff-store.com/diff/section14__08_receive_validate_wtform",target:"_blank",rel:"noopener noreferrer"}},[t._v("https://diff-store.com/diff/section14__08_receive_validate_wtform"),s("OutboundLink")],1)])]),t._v(" "),s("h2",{attrs:{id:"validate-form-data"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#validate-form-data"}},[t._v("#")]),t._v(" Validate form data")]),t._v(" "),s("p",[t._v("Now that we've got our form and our endpoint, it's time to connect them and receive the form data in Flask!")]),t._v(" "),s("p",[t._v("Doing so with Flask-WTF is very simple:")]),t._v(" "),s("div",{staticClass:"language-py extra-class"},[s("div",{staticClass:"highlight-lines"},[s("br"),s("br"),s("br"),s("br"),s("div",{staticClass:"highlighted"},[t._v(" ")]),s("br"),s("br"),s("br"),s("br"),s("br"),s("br")]),s("pre",{pre:!0,attrs:{class:"language-py"}},[s("code",[s("span",{pre:!0,attrs:{class:"token decorator annotation punctuation"}},[t._v("@pages"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("route")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"/add"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" methods"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"GET"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"POST"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("def")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("add_movie")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n form "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" MovieForm"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" form"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("validate_on_submit"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("pass")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" render_template"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"new_movie.html"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" title"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Movies Watchlist - Add Movie"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" form"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("form\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])]),s("p",[t._v("Instead of checking whether the "),s("code",[t._v("request.method")]),t._v(" is "),s("code",[t._v('"POST"')]),t._v(", we're running a method of the "),s("code",[t._v("MovieForm")]),t._v(" class: "),s("code",[t._v("validate_on_submit()")]),t._v(".")]),t._v(" "),s("p",[t._v("This does two things:")]),t._v(" "),s("ol",[s("li",[t._v("It checks that the form has been submitted (similar to doing "),s("code",[t._v('if request.method == "POST" and request.form')]),t._v(").")]),t._v(" "),s("li",[t._v("It runs validation on the form, and stores any errors back into the "),s("code",[t._v("form")]),t._v(" object. It returns "),s("code",[t._v("True")]),t._v(" if the validation yielded no errors.")])]),t._v(" "),s("p",[t._v("So we will go into the "),s("code",[t._v("if")]),t._v(" statement if the form was submitted and it validated without errors. Bingo!")]),t._v(" "),s("p",[t._v("Inside the if statement we can now grab the data and insert it into MongoDB.")]),t._v(" "),s("h2",{attrs:{id:"insert-movies-into-mongodb"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#insert-movies-into-mongodb"}},[t._v("#")]),t._v(" Insert movies into MongoDB")]),t._v(" "),s("p",[t._v("The simplest way to grab the form data and insert it into MongoDB would be to do something like this:")]),t._v(" "),s("div",{staticClass:"language-py extra-class"},[s("pre",{pre:!0,attrs:{class:"language-py"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("import")]),t._v(" uuid\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("from")]),t._v(" flask "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("import")]),t._v(" current_app"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" url_for "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# amongst other things")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token decorator annotation punctuation"}},[t._v("@pages"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("route")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"/add"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" methods"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"GET"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"POST"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("def")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("add_movie")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n form "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" MovieForm"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" form"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("validate_on_submit"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n movie "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"_id"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" uuid"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("uuid4"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("hex")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"title"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" form"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("title"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("data"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"director"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" form"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("director"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("data"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"year"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" form"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("year"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("data\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n current_app"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("db"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("movie"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("insert_one"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("movie"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" redirect"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("url_for"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('".index"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" render_template"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"new_movie.html"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" title"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Movies Watchlist - Add Movie"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" form"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("form\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])]),s("p",[t._v("And this would work just fine! However, there's one small issue.")]),t._v(" "),s("p",[t._v("We know that movies need to have more data in them than just "),s("code",[t._v("_id")]),t._v(", "),s("code",[t._v("title")]),t._v(", "),s("code",[t._v("director")]),t._v(", and "),s("code",[t._v("year")]),t._v(". We need to store genre, cast members, the last time we watched it, and a bunch more stuff!")]),t._v(" "),s("p",[t._v("So now is a good time to find a way to collect all the data about a movie in one place.")]),t._v(" "),s("p",[t._v("I think one of the best ways to do this is a "),s("code",[t._v("dataclass")]),t._v(". This is a Python object that is made for defining a cohesive group of data and interacting with it easily.")]),t._v(" "),s("h2",{attrs:{id:"create-a-class-for-storing-movie-data"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#create-a-class-for-storing-movie-data"}},[t._v("#")]),t._v(" Create a class for storing movie data")]),t._v(" "),s("p",[t._v("Let's start by creating a "),s("code",[t._v("movie_library/models.py")]),t._v(" file. Inside it, we'll define a class that represents a movie.")]),t._v(" "),s("div",{staticClass:"custom-block tip"},[s("p",{staticClass:"custom-block-title"},[t._v("TIP")]),t._v(" "),s("p",[t._v("I made a diagram to help you visualize the change from dictionary to class for handling data and interacting with MongoDB. Hope it helps!")]),t._v(" "),s("p",[t._v("Link: "),s("a",{attrs:{href:"https://snappify.io/view/b0880dd5-59c8-4d4b-902b-ca26b1681bb2",target:"_blank",rel:"noopener noreferrer"}},[t._v("https://snappify.io/view/b0880dd5-59c8-4d4b-902b-ca26b1681bb2"),s("OutboundLink")],1)])]),t._v(" "),s("p",[t._v('To "represent" a movie we\'ll define the properties of an object of said class, so that when we create an object, it will have all those properties.')]),t._v(" "),s("p",[t._v("Using the "),s("code",[t._v("dataclasses")]),t._v(" module, you'd do it like this:")]),t._v(" "),s("div",{staticClass:"language-py extra-class"},[s("pre",{pre:!0,attrs:{class:"language-py"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("from")]),t._v(" dataclasses "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("import")]),t._v(" dataclass"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" field\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("from")]),t._v(" datetime "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("import")]),t._v(" datetime\n\n\n"),s("span",{pre:!0,attrs:{class:"token decorator annotation punctuation"}},[t._v("@dataclass")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Movie")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n _id"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("str")]),t._v("\n title"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("str")]),t._v("\n director"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("str")]),t._v("\n year"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("int")]),t._v("\n cast"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("list")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("str")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" field"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("default_factory"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),s("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("list")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n series"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("list")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("str")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" field"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("default_factory"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),s("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("list")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n last_watched"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" datetime "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("None")]),t._v("\n rating"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("int")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("0")]),t._v("\n tags"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("list")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("str")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" field"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("default_factory"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),s("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("list")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n description"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("str")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("None")]),t._v("\n video_link"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("str")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("None")]),t._v("\n")])])]),s("p",[t._v("This uses "),s("strong",[t._v("type hinting")]),t._v(" to define the field name and its data type. The "),s("code",[t._v("dataclasses")]),t._v(" module then does a few things for you, such as define an "),s("code",[t._v("__init__")]),t._v(" method, a "),s("code",[t._v("__repr__")]),t._v(" method, and a few others.")]),t._v(" "),s("p",[t._v("You can think of data classes as a "),s("strong",[t._v("code generation tool")]),t._v(". You give it the fields and types, and it generates a bunch of methods for you so you don't have to.")]),t._v(" "),s("p",[t._v("Two things that are especially important:")]),t._v(" "),s("ul",[s("li",[t._v("Some fields have default values. This is so that we don't "),s("em",[t._v("have to")]),t._v(" pass in a value when we create the object. We must do this so when we create a new movie and don't have all its data yet, we are allowed to do so.")]),t._v(" "),s("li",[t._v('Some fields have "fairly reasonable" default values, like '),s("code",[t._v("0")]),t._v(" or "),s("code",[t._v("None")]),t._v(". Others have a value of "),s("code",[t._v("field(default_factory=list)")]),t._v(". This looks a bit weird, so let me explain.")])]),t._v(" "),s("h3",{attrs:{id:"the-field-object-and-default-factory"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#the-field-object-and-default-factory"}},[t._v("#")]),t._v(" The "),s("code",[t._v("field")]),t._v(" object and "),s("code",[t._v("default_factory")])]),t._v(" "),s("p",[t._v("When we want a bit more control over the default behaviour of fields in our data classes, we can use the "),s("code",[t._v("field")]),t._v(" value.")]),t._v(" "),s("p",[t._v("This allows us to modify things such as:")]),t._v(" "),s("ul",[s("li",[t._v("Whether the field should be included in the generated "),s("code",[t._v("__repr__")]),t._v(" method")]),t._v(" "),s("li",[t._v("Whether the field should expect a value in the "),s("code",[t._v("__init__")]),t._v(" method")]),t._v(" "),s("li",[t._v("Whether the field's value should be used for comparisons between objects of this dataclass")]),t._v(" "),s("li",[t._v("A few other settings"),s("sup",{staticClass:"footnote-ref"},[s("a",{attrs:{href:"#fn1",id:"fnref1"}},[t._v("[1]")])])])]),t._v(" "),s("p",[t._v("One of the things it also allows us to do is define a function as a default value, so that the function will run when the object is created, and the function's return value will be used as the value for the field.")]),t._v(" "),s("p",[t._v("This is necessary for when we want to define mutable values as the default value for the field.")]),t._v(" "),s("p",[t._v("If we did this:")]),t._v(" "),s("div",{staticClass:"language-py extra-class"},[s("pre",{pre:!0,attrs:{class:"language-py"}},[s("code",[s("span",{pre:!0,attrs:{class:"token decorator annotation punctuation"}},[t._v("@dataclass")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Movie")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n cast"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("list")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("str")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\n")])])]),s("p",[t._v("Then this has a problem that isn't easy to spot!")]),t._v(" "),s("p",[t._v("The problem is that when you create two movie objects, they will both have "),s("strong",[t._v("the same")]),t._v(" list as a value for "),s("code",[t._v("cast")]),t._v(". When you modify one, the other will be modified too"),s("sup",{staticClass:"footnote-ref"},[s("a",{attrs:{href:"#fn2",id:"fnref2"}},[t._v("[2]")])]),t._v(".")]),t._v(" "),s("p",[t._v("To circumvent that, we create a different list for each field "),s("em",[t._v("when the object is created")]),t._v(":")]),t._v(" "),s("div",{staticClass:"language-py extra-class"},[s("pre",{pre:!0,attrs:{class:"language-py"}},[s("code",[s("span",{pre:!0,attrs:{class:"token decorator annotation punctuation"}},[t._v("@dataclass")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Movie")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n cast"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("list")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("str")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" field"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("default_factory"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),s("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("list")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])]),s("p",[t._v("This means that, when the object is created, it runs "),s("code",[t._v("list()")]),t._v(", which creates a new list, and assigns it to the field.")]),t._v(" "),s("p",[t._v("Because the list is created as part of the object initialisation, it won't be shared between two or more objects of the same class.")]),t._v(" "),s("h2",{attrs:{id:"use-the-data-model-class-for-saving-to-mongodb"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#use-the-data-model-class-for-saving-to-mongodb"}},[t._v("#")]),t._v(" Use the data model class for saving to MongoDB")]),t._v(" "),s("p",[t._v("Now that we've got our data class, let's use it in our endpoint!")]),t._v(" "),s("p",[t._v("All we have to do is import it:")]),t._v(" "),s("div",{staticClass:"language-py extra-class"},[s("pre",{pre:!0,attrs:{class:"language-py"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("from")]),t._v(" dataclasses "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("import")]),t._v(" asdict\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("from")]),t._v(" movie_library"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("models "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("import")]),t._v(" Movie\n")])])]),s("p",[t._v("And then in the endpoint we can create an object with the values:")]),t._v(" "),s("div",{staticClass:"language-py extra-class"},[s("div",{staticClass:"highlight-lines"},[s("br"),s("br"),s("br"),s("br"),s("br"),s("div",{staticClass:"highlighted"},[t._v(" ")]),s("div",{staticClass:"highlighted"},[t._v(" ")]),s("div",{staticClass:"highlighted"},[t._v(" ")]),s("div",{staticClass:"highlighted"},[t._v(" ")]),s("div",{staticClass:"highlighted"},[t._v(" ")]),s("div",{staticClass:"highlighted"},[t._v(" ")]),s("div",{staticClass:"highlighted"},[t._v(" ")]),s("div",{staticClass:"highlighted"},[t._v(" ")]),s("br"),s("br"),s("br")]),s("pre",{pre:!0,attrs:{class:"language-py"}},[s("code",[s("span",{pre:!0,attrs:{class:"token decorator annotation punctuation"}},[t._v("@pages"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("route")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"/add"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" methods"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"GET"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"POST"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("def")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("add_movie")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n form "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" MovieForm"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" form"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("validate_on_submit"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n movie "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" Movie"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n _id"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("uuid"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("uuid4"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("hex")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n title"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("form"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("title"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("data"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n director"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("form"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("director"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("data"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n year"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("form"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("year"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("data"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n current_app"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("db"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("movie"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("insert_one"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("asdict"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("movie"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" redirect"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("url_for"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('".index"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])]),s("div",{staticClass:"custom-block tip"},[s("p",{staticClass:"custom-block-title"},[t._v("TIP")]),t._v(" "),s("p",[t._v("Note that we are using "),s("code",[t._v("asdict(movie)")]),t._v(" to turn the data class object into a dictionary. Handy!")])]),t._v(" "),s("p",[t._v("And that's it! The default values will go into MongoDB so we have some sensible data there for when we want to add that to the movie, and the code hasn't gotten much more complicated than using only dictionaries.")]),t._v(" "),s("hr",{staticClass:"footnotes-sep"}),t._v(" "),s("section",{staticClass:"footnotes"},[s("ol",{staticClass:"footnotes-list"},[s("li",{staticClass:"footnote-item",attrs:{id:"fn1"}},[s("p",[s("a",{attrs:{href:"https://docs.python.org/3/library/dataclasses.html#re-ordering-of-keyword-only-parameters-in-init",target:"_blank",rel:"noopener noreferrer"}},[s("code",[t._v("dataclasses.field")]),t._v(" (Official Python Documentation)"),s("OutboundLink")],1),t._v(" "),s("a",{staticClass:"footnote-backref",attrs:{href:"#fnref1"}},[t._v("↩︎")])])]),t._v(" "),s("li",{staticClass:"footnote-item",attrs:{id:"fn2"}},[s("p",[s("a",{attrs:{href:"https://docs.python.org/3/library/dataclasses.html#mutable-default-values",target:"_blank",rel:"noopener noreferrer"}},[t._v("Mutable default values (dataclasses, Official Python Documentation)"),s("OutboundLink")],1),t._v(" "),s("a",{staticClass:"footnote-backref",attrs:{href:"#fnref2"}},[t._v("↩︎")])])])])])])}),[],!1,null,null,null);a.default=n.exports}}]);