Django loves strawberries
Update
Please prepare the Workshop as described [here](https://github.com/Speedy1991/strawberry-workshop)
Delve into the world of GraphQL Strawberry and Django in this comprehensive workshop designed to unravel the intricacies of these technologies. Throughout the sessions, participants will navigate the synergy between Strawberry, a GraphQL library for Python, and Django, a robust web framework. The workshop kicks off with an exploration of type definitions, offering insights into creating robust schemas and defining custom types to suit project requirements.
Moving beyond the fundamentals, attendees dive into the realm of queries and mutations, mastering the art of fetching data and manipulating it through GraphQL. With Django's ORM seamlessly integrated into Strawberry, participants discover how to effortlessly execute complex queries and mutations.
Furthermore, the workshop explores the integration of Starlette, a lightweight ASGI framework, into the mix. Uncover how Starlette complements Django and Strawberry, enhancing API development with its performance and flexibility.
The hands-on approach of this workshop ensures participants grasp each concept thoroughly. Through guided exercises and practical examples, attendees gain confidence in implementing GraphQL APIs using Strawberry and Django, unlocking the potential to build robust and scalable applications.
By the workshop's conclusion, participants will have a comprehensive understanding of:
- Creating GraphQL schemas using Strawberry and Django
- Executing queries and mutations seamlessly within Django applications
- Leveraging Starlette for efficient API development alongside Django
Whether you're a seasoned developer or new to these technologies, this workshop promises to equip you with the skills needed to harness the combined power of GraphQL Strawberry and Django for your projects' success.
This session took place in track Django & Web and was classified suitable for novice domain / intermediate python by the speaker.
Transcript (auto)
Auto-generated from the recording utilizing Open-Source AI. Speaker labels (Speaker 1, Speaker 2) reflect diarization, not identity. Timestamps refer to the recording.
Speaker 1 [00:05]
My name is Artur Bayer. I work for S-Docs for several years now. I'm a full-stack developer with a focus on API architecture, performance, security, and backend and frontend side. I've been using Django for over seven years and also doing Vue, React, mostly React and LastTime for over five years, and doing some DevOps and server admin stuff. yeah I worked with beating edge technologies but it's not really true anymore with GraphQL it's on the market for about I think 5 to 7 years there are still many people who don't know GraphQL and they just go with REST or some fancy new remote procedure calls and sometimes I'm a prompt engineer I'm writing three kits I give them some input and I get some random response. So that's all about AI you heard about today from me. And my typical stack is a caddy web server with a Django and strawberry. In the front end I use NX, React and Apollo. And who of you are using GraphQL in the past? Okay. Who of you were using Django in the past? Okay. Nice. GraphQL is an APA specification from Meta, Facebook, and it's implemented in many languages. In Python, you have strawberry and graphene, or graphene, maybe. And one big point of GraphQL is you get exactly that what you ask for. Your client asks for a name, you get the name. In REST, you ask for a person, and you get always the full person object and not exactly what you're asking for. That's a nice interface. It's called GraphQL. We use this for querying our back end in the workshop. And in the docs there's no versioning defined. But is this really true? I saw GraphQL endpoints with slash v1, v2, v3. So in GraphQL you normally do deprecate fields and use some open telemetry or any other logs see if this field is maybe under 1% usage and then you really drop it. Only one endpoint and that's definitely not true in my opinion because there's something called federation where you can connect many GraphQL endpoints to one big schema. And a schema is the definition of your whole API. So you have some primitives like integers, strings, UUIDs, IDs, and they are wrapped in lists, object types, interfaces, unions, and it looks all similar to like JSON. So I got some questions before the workshop started. So why do I prefer strawberry with four costars on GitHub over graphene with eight costars? I used Graphene myself for several years, but the maintainer leave this project and with him the majority of core developers and contributors left with him. There's no more, or there's not many action in this repository. Another question is, is there any AI covered in your workshop? Nope. I am a full-stack engineer and I'm very interested in AI. And I'm also using it sometimes, but it's very hard to keep up to date with so many technologies and different scopes. So I think this is the last slide before we start. Each exercise is self-contained. So as long as you don't add any syntax errors, you can just go on. Because the exercise two is based on exercise one, But I fixed all errors for you, and you can just go on without fixing your errors from exercise one. And this workshop uses an open source tool, Strawberry. And in open source, it's very important to talk, discuss, and help each other. So please do not hesitate to ask the people next to you for help or advice. There are still questions. can just raise your hand and I come to you and I will help you out. So let's go. I hope everybody of you cloned the GitHub repo. If you didn't, now would be a great time to do it. And that's the outline, the pre-install requirements, I will skip this, and the exercise overview. Each exercise has a readme and this is very exercise-based. I commented you to do stocks, some help with jungle code and you just go through the code and fix one to do after another. In the first exercise, we will write some typedefs and resolvers, and we will refactor our code until we've finished the whole API. And if time is left, we will talk about ASGI, Starlet, and so on. And as homework, we can check out Strawberry Jungle. There's our database scheme. It's really easy. We have a social club, some members, guests, and a product. And Strawberry, Docs, plus Discord. Discord has a very active channel on Strawberry. There you will get help immediately. The creator is Patrick. Thanks so much for creating the framework. And the core developers are Bellini, Dr. John, Eric Red, and Skilkeys. Yeah. And in the first exercise, you can just open your private IDE going to exercise one and just open the readme. And the first thing you must do is to change the line in core URLs to use your exercise one schema. So you go to from XSRS1 schema, save it, maybe restart your server to avoid any stale code. And you can check if everything works if you go to 127.00.18000. This will redirect you to the GraphQL endpoint and here we have the GraphQL interface and I can show you shortly what I mean with what you ask is what you get. So I query all social clubs here with ID, okay. I should use... You can just press Control-Space. You can see ID is there and name is there. And you press Control-Enter, and you just get the data on the right side. Any questions so far? OK. So the first exercise is defining the README. That's really easy. you go to the types in exercise one. It's in schema, types, and this concept is repeating. So I explain it one time now. And in future, we can just go into types, query, and sometimes in the schema pi, and work through the to-dos. So I will show you the first to-do, and then I think you can just go on. So street would be street column string. I will save this. And now if I update my scheme, my endpoint, I can query the street. If I query the street, this won't work now because you have to fix the query afterwards. And just uncomment some lines. I did many of precoding for you because it's very boilerplate code, and we will refactor this later. So I will give you 10 minutes for the first exercise, and I think it's until 1.20. If you have any questions, just raise your hand and I come to you. Thank you. Thank you. Thank you. Thank you. Oh, that's cool. I expected that the numbers would be built. We'll be able to set up. Yeah, you're absolutely right. Okay. Thank you. I think you have to do something with that. Thank you. Thank you. Oh, but it seems to use, like, a dictionary notation. . . . . . . Thank you. Thank you. So you have three minutes left. No pressure. Thank you. Thank you. Oh, maybe there she has a position. Okay, but then... But then CT doesn't look for a student. Oh, they're all equally long and yes, it's correct. It's a bit cheesy. Respect some name. Thank you. time would be up do you need one more minute or yeah okay does anybody finish this exercise nice Thank you. So I will do some live coding now, and you just can finish your exercise on your own or just look at my code, how I would solve it, yeah. So I already implemented street, the next time field is zip, it's also string. I forgot to mention, Strawberry is fully based on data classes. Both of you works with typing in Python? Oh, OK, nice. The product type has a name. It's also a string. price is an integer, and quality is a quality enum, imported from core schema enum. There's a small trick, because the quality enum is a quality choice, it's field from and you can easily make an enum from it if you make a strawberry enum, quality choices and you must give it a name, then you can use it. There's also the age, which is an int, and the rating, which is an int, and the types are finished now. We have to fix queries, and there's just uncommenting, I think. And there's an extra to-do here, because this is a top-level field. On the query, we can, no, that's not correct. On any typedef, you can also define any custom fields, like, hey, I want to have the current date time. This takes all of the info object. Info is like a request. It's a bit more. It has information about the schema, but it also has a request. And it will return a date time and just do a time zone, time, time, zone, null. Get this from maybe. Get the date time from date time. And everything should work in the front end now. So we have the, just check it out if it's still working, yeah. So we have a SIP implemented, and it returns the SIP. And also, you can query the, oh, I forgot that. must decorate this as a strawberry field or it doesn't occur in the schema so now you can also query on the top level time. That's interesting. I think I must do a from date time and port date time. Yeah, now it's working. So on the top level you get the social clubs and also our implemented current date time and I don't know if anybody had time left for implement the member and guess it's just the thing code as above with the product and social clubs are there any questions yeah It's a different notation for current data and no underscores and capital letters. So Strawberry converts everything to CamelCase on default. You can disable this behavior on the schema, I think, with a schema configuration. I think that this also, I will look up the docs and will show it to you if you're interested in this. The background is JSON as camel case. You see not often JSON in snake case. So the Python snake case collides with the front end now. And this is an API, so we'd return the data structure for the front end. You can enforce this behavior with the schema config if you really need the underscores. Yeah? Where are all the values in terms of the speed and zip code and so on defined? You run the load data, Python manage load data, data chasing I think I called it. And I prepared a small SQLite database and Django uses a SQLite database on default. And as soon you run Python manage migrate, this database gets created and the data you you injected this data I randomly created, I think, three or five days ago. If you're interested in how I created the data, under Core Management, Comments, Mock Data, there's a small script. It's not very performant, but it does the job. And just spin up some random data. So I think we can go on with exercise two. What do you think about exercise one? Was it hard or? OK, yeah. It's not a problem if you didn't finish the exercise one because the important part is you get the feeling how these things work. And I will show you my solution. That doesn't mean it's the best solution. But you have a good starting point how you can implement the whole schema you will build in the future, maybe. So exercise two is, I will show this in GitHub. There is it nicely formatted. Do not forget to update the to exercise two. This will load the next schema. The are in the types. And at the moment, we cannot query any related things like a foreign key from a social club and which members are in the social club or which products are at this social club. And there are many to-dos again. Look out for the forward declaration. And typing in Python, you use this double quote just to forward a class defined under your current class. And I think you only needed this in line 14 to 16. And the other two should be straightforward, I think. And you will have time until 14, I think. Thank you. Thank you. This is a package, not on Ikea, it's a package, it's a So you just run the console, put this in, and then minus R. I think you have to stop your development. . . . . It could be that your root is not a package. I don't know if you can set an approach to that. Can you right-click on this photo and mark it as source? Oh, it's a type-changer. So this should be the... But you can... Is it working? can just make a right-click and mark it as a project source, and all paths should be read. I was wondering, is there a way to create a filter by, like, greater than or less than? It's a very draining exercise. So we will reflect on this . And you know how . And if you don't want all by your own, there's a . And they find all your filters and pre-patches and pre-selects and so on for you. Let's have some side examples. Last time I used it, it was not mighty enough to combine custom types with general types. And I needed to fix it quickly. So there was no chance to mix something like a custom interface. It will come later. But general types, you know. So you can just plug in any library that you want and mix it up. There's also a question. Oh, yes. I would find the GraphQL site. There was nothing about comparisons. No, GraphQL itself doesn't make any filters. If you want a filter, you can define one yourself. Oh, so it's part of your own. Yeah, it's not part of the language. The language offers you the possibility to add arguments to your filters. OK. But I think it's an exercise for you, or for me, or for the audience, and then everybody will have some more arguments about what this is coming from. . . . . . . So here, you do have to map everything from the model to data. Okay, so basically, for all the model that has all the relationships, you have to basically call all the objects for it to do it. or should I just turn it somewhere else? It seems like it's an edge approach from the Tango model into a data container. But that's . So let's say we have, like, let's say we have, like, so we have quite even . The members are . That is a plain strawberry, it seems. I think you have to do a lot of things to make it even more complete. Other library changes. That won't be necessary. This was the problem I had the first time I tried GraphQL. It doesn't even count. I programmed completely nothing. It's way too much work, and I might just Well, it's the same question now. If this can be automated, then it should be fine. in my touch panel, I changed it all the time. So we just defined the type, and I already created for you in the social. I think that's amazing. I don't understand the concept of queries and types. Do I need to send you a professional in addition to recognize this one? I also get a warning, and this is a problem in Python, I think it said that there's an old issue in PyCharm. That's what we're trying to do is support it instead of making it a problem. Okay. So I think this old PyCharm has issues like the old PyCharm. The old PyCharm has a technical problem. It's a kind of package that includes and the important thing about the wine bowl is the file name. The file name is strawberry minus, what do you say? Yep, that's good. I don't know. Strawberry. I cannot. Strawberry minus . And I can only imagine this name What's the name of the system that imports? What they import is the strawberry load. Types of strawberry are correct and fine. What's the name of the system that imports? Typesharm, which uses to implement this system. But I need a little bit of a question. A question in addition to a regular type object. Yes, in a way. Good. the object to some other program, which should, or maybe your project is a set, and there's a file that you don't check. Yeah, I just want to look at the edition, I can't see it. Yeah, but I know this from a topic. I always run a version, so. Okay. Thank you. So I see that time is up. I think I'll show you the solution. The first to do is members. And members is a list of member time. And this we have to copy for guest and product. There should be products. I will try it in a minute. Maybe I have a bug in it. This could be possible. Also, can you mention this question below? Yeah, sure. I will just pick the times that I don't forget anything and then I will mention the question. So there's a question, oh, this could go very wrong in future. At the moment, there is not a problem, because I checked this data on a static query. We will refactor this soon. And I just checked the members with a member type outside to fulfill this social club time. But as soon as we implemented this, we can. I'll show you something. So we can query members here. And members, we can query in the ID and again the social club. And in the social club, we can query again the members. And in the members, we can query again the social club. And yeah, that's a graph. It's GraphQL. So we can just go from one node to another, and back, and forward, and back, and forward. And there's something to prevent this. So I added an exercise three. I don't want to type everything again. There are extensions to the schema. You can limit your query by depth. You can limit the aliases. There's another tech for GraphQL schemas. So you can do something like, you have a very expensive field, let's assume the first name is very expensive. So you make an A, you make an alias. So this field will be, I will show you. This field will be finished types first. Do not mix up things too fast. Guests, social club, I have to find guests. So should I have to find guess guess s is missing So everything should work now. Yeah, so if you can notice there's a response a year inside on the right side and It is a first name. So if I remove the alias I get first name again I can just rename the fields on the fly. So let's assume first name is a really expensive field field, so I can do a B first name, C first name, and if each query will take five seconds, so we are on 15 seconds, if you are async, you will just blow up your processes. And in the end, I just return every field three times. This is useful if you use something like thumbnails with arguments so you can do original, this is not a re-case just for showing what aliases do, original with no arguments and you can and query a thumbnail 400 by 400, and you will call it with x 400 and y 400, and so on. So that's a really useful case for thumbnails if you need many of them. But I think this goes out of scope. With these extensions implemented on the schema, you can limit this. You should tighten it enough to prevent these attacks, but you shouldn't make it to tighten to prevent your developers from developing because if you have always to fix the def limiter or always to fix the alias limiter, you make more trouble than solutions, I think. There are some optimizers like pass cache, parser cache, validation cache, mask errors. So you won't show the original errors to the end user. You can customize this with should mask error function. So you can just define a callback on here. And you can just define yourself what should the response look like. But we are still in exercise two, I think. And yeah, I think this, I think it's complete. Members should work. Also, the guests should work. Yeah. Are there any questions to exercise two? Yeah. Can you try to query products? Yeah, I can also query the products. And I get what I ask for. And I can also remove the members and guests to have some less noise. And now I have the products. Yeah, we can look inside it, I think, at this time in the next exercise, or at the end of the workshop, we can just talk about it. So next exercise is about lots of boilerplanes. And the types and the query, I already fixed the query pipe for you, I think. There's a really interesting question. There are two, maybe more, possibilities to implement this. One is a from object, and one is a private field on the field definition. I already prepared your type with this instance private. If you look it up, private is just a strawberry field definition. So this field does not show up in your scheme. So you can't query instance. It's private. But you have access in the field resolvers. Now the type changed from this definitions, this data style, data classes definition style, to this field resolver style. So you can access your instance with itself. This is also typed, so you get autocomplete for social club. The same happens with member. You have a lot of to-dos here to resolve everything else. And there are some special cases. So if you are annoyed by this repeating resolvers up here, we can maybe skip to to-do six, where you can define an uppercase name field. There are two ways, one with a field resolver and one with a field extension. I've already prepared you the extension because it is just copy paste from docs, so you don't have to do it yourself. And the question is, another question is, think about the pros and cons for more boilerplate and times and less logic in your queries. Thank you. Ah, don't forget to change the exercise three in the ULS file. Thank you. Thank you. Thank you. I think you mean the info object or? The info object is typed, I hope. The info object has some raw information about the schema. And it also has the information about your current field. I don't think, no, you don't need this info object in this exercise. But there are also some interesting things like field name, field node, selected fields. Selected fields is very interesting if you're working with Django, because if your fields match the name of your database, you can just prefetch and select before you even execute your query to have one query and not the n plus 1 problem if you subquery nested types. If you're looking for the Django request object, it's under info context request. So you can make some authentication maybe there if the user's logged in. So you can go, you can check it on the API endpoint. You can check it on this schema. You can check it on your query definition, I think. And the lowest possible place is on the field definition. So you can have a type defined, like person, and you have access to the name, but not on the last name. So you can query name as a public user, but as soon as you want to access the last name, you just write an error or return none. I have a question about the difference between a strawberry ID and a string, I think. is just constant definition in the strawberry schema, not schema, but specification, because you have a front-end client, like Apollo or Relay, and they have a normalized cache. So you have something like member type colon 1, and that's in your front-end cache. It's not the browser cache. It's inside JavaScript, like in Apollo. And you can normalize this object. And you can gain a lot of performance out of this. Because you can query a member, and later you have a component. And you can reuse that member without querying the server. Because you can just look up, ah, I have a member type, column one. This is in query. Ah, OK, I don't have to fetch it from the server. So I just grab it from my cache. And this does not work with strings, because the string is not an identifier. It's just a constant. And the hood ID is just an alias for string, but another data type. I think so. Thank you. Thank you. Thank you very much. So you have one minute left. Oh, no, push next time. Oh, there's a reverse. Oh, there's a query between those sides. That's kind of bad. So I will just show you one example with the name, I will just skip these copy paste stuff I think. So we have a strawberry field, we want to have the name. By the way, you don't have to implement info if you don't use info. Strawberry looks up if there's an info inside this. This decorator checks if there's an info with a typing of info. And if there is this info object that exists, Strawberry will then check that if you don't define this, this works completely fine, too, as long as you don't access or you don't need the info object. Name will return a string, so this is just normal Python return definition from type. And we will return self.instance, and we just see here the auto-completion from PyCharm kicking in. It's a social club type, and we just need the name. Difference to Graphene, I think, is you have no typing, so you have to guess the stuff. I'm not sure. That's my last stem. So the next interesting part is this name uppercase. It's, again, a strawberry field. Everything is a strawberry field most of the times. And we define our name uppercase. And we have, again, the info, info. And it will return, obviously, a string again. And we will just make a self, self instance And this should work as expected. Another way to do the same thing is to have this logic of uppercase reusable inside an extension. So you can add a feed extension. Like this. This one. Then you can just return the name again. And the extensions are executed like generators, I think. So there is like a middleware one way down and one way up. If you write a custom one, just look up the docs. And there's a question left. Do you know some pros, cons for more boilerplate and types, but less logic and queries? Can someone guess this? I would say that you can reuse them. But then you have more than just one query for the same type. Yeah, exactly. So you can reuse it, and you can tweak a lot of performance out of it. So I already told you you have the member of ID1, and you can store this member in so-called data loaders from strawberry if you are running in an async context. Or you can add any self-designed cache stuff on the request object, like you have a request object and you set an attribute like members and you have already queried the member one, you can just pass it to the request object in a sync environment to not mix up the request object. As soon as you have to resolve any members, you can just look up your cache. Is this member already inside? Because you have one member type with one ID, this will exactly exist one time in your database if your ID is a primary key. The social club here is a member field type. So you can not just return the database model. Maybe you can, because there's some magic going on. Like in FastAPI, you don't have to return this exact type. So you can also return a dictionary. And Strawberry will do its best to match this. But you don't get any IDE support, like type validation. So in this example, we will just return product time. It has an ID, and the ID comes from product ID. We have a name. It comes from product, phone name, and so on. I will skip this. And we have a social club, and this must be this type or a dictionary type. So you must create a social club type here. And social club type is already refactored. So your social club type takes an instance. And from there on, it is self-contained to resolve its fields on its own. So the control of resolving the fields went from the query to the type. And we can just make it work like this. I will skip this because we are running out of time, I think. I think this exercise is finished. What's the advantage difference between from object and private? Does anyone have an idea? Private is a field with a field typing. So you have your social club as a model type as in types, let's check it. So this is typed. So what is if you, what happens if you want to mock some data? You have to create this database object to match the type definition. If you have something like from object, nothing stops you to say, hey, it's a product or it's my mock data defined anywhere. And you just make something like if instance product do this and else do this. So this comes in handy as soon as we read the exercise five because we're talking about interfaces. In the next access, are there any questions to exercise three? Yeah. Yeah. So we did a lot of . So I managed to do like the shared implementation of from object. Yeah. For all of these classes, just the introspects that the class fields. Yeah. This works as long as your field names match the database name, I think. No, no, no, no, no, because, yeah, yeah, yeah. But in this case, they might. Yeah, so what you can do is, if you're running the from object or the feed definition, you always can do something like looking up some attributes on another object. So you can take maybe the info.getFieldDefinition, I think, .fieldName. And if this match, you can write a completely generic resolver. I won't do this. I would take a library called Jungle Strawberry, I think. I mentioned it in the Read Me Outside as homework. Because as soon as you use this framework, it comes with many advantages, like pre-selecting a prefetch and select related, and so on. And there are also implemented filters. And there you can just define your model and say, take this, this, and this field, and it will just resolve automatically. There are some advantages, some disadvantages, but I think we can talk about this in detail later. So the next thing is we query data, but we also want to create data. So we have a mutation, a feed argument, and because we are running out of time, I think I give you five minutes, maybe seven, just to get into the topic, and then I will show show you how to implement it on your own later. Yeah. Thank you. maybe it's just because of the example like in the this query but it doesn't return anything that isn't asked for in this case it will still query it even if it isn't being asked for but just not send it back to the client in this case yes You can calculate channel and this line and then you can make a sort of values and then you can specify which values you want to query from the data. This adds a lot of complexity to the code because you have to inspect the query in the social apps of all channels. which query depth you have, and which fields are related, and the field name should match the database. And before you run your query, you say, okay, query is a member, it's a social club, so a pre-fetched member in social club. And from the member, maybe a grass name, and last name, from the social club, the ID and name. And you have to always specify this in your values from this query in this line, but it's kind of hard to calculate, because maybe your API fields differ from the database fields, so the API is called firstname, and the database is just called name, because it's maybe some lexical, and then you have some problems to match this firstname to the name. That's one disadvantage of this jungle strawberry probably already technically mentioned earlier, because this assumes you have one-to-one, that the database measures one-to-one in those two months. Yeah, you can pick your own schema, that's fine, but if you have to comply with an existing schema, then you might not be able to do that. If you have the freedom to fill up your own schema, you can just make it match your own model, but if you don't have the freedom. So, if you're starting from . So, if you're starting from an empty project, just go with the library because it makes life so much easier. But the problem is, most of the times, if you're changing projects and you have some, like the REST API, or remote procedure calls, and remote procedure calls can match with new API like to the existing field, but you want to have a front end and the fields must be noisy. First name is defined as first, you know what is the first name, but just give it a name and then the company and ask you what is the first name, is it full name, is it last name, is it with or without salutations. And in GraphQL, you try to define it as a component of the JSON. So, is there some kind of library or effort they made to make more of this automated? Because I think there's a lot of translation code. I don't know how you don't need because you only ask what you need Calculate the hash in the front end then look up the hash in the back end hash table from the back end, even if it's defined as the front end. But this is a combined task from the back end to the front end. And my idea is that there wasn't a back end to the channel. You can channel all those services and templates, and they're developed by all the back-end and the front-end. So this makes stuff with it more like a channel panel. So, I will show you how this mutation will work. I don't think that we have to fix anything else. Yeah, so the mutation will just take an input object, and it's defined as strawberry input, and we have to match the field name as good as possible to our back end, so we have a price, it's in the teacher, and we have a quality, which is our quality enum. And to update our instance we just make a product.price is input.price and the quality as a product.quality equals to input.quality and that's an enum so you have to access actual value and then you just have to save this. I have a question here, can we optimize this boilerplate? Yes, we can. I prepared a utils function in core and this is just doing this input type to a dictionary and we can just iterate it like key value pairs. You have to care for enums, date, time, and so on. And this only works if your input name matches the name of your object, your instance of your database object. An example should be in exercise five, I think. But to complete this exercise we can add an argument like this one, we have social clubs. We want to have the min member count, only social clubs where the min member count is greater than equal the specified number. So we add a min member count and this should be optional. And it should be an int, and it should be default, none, or unset. Unset is a specific type from strawberry. It's like undefined in JavaScript. So we can filter on the database level or we can filter in Python. This is the answer to this question. We did some performance measurements in our company and most of the time we just prefetch and pre-select the stuff in the database and just, not always, but often fill in Python or Elasticsearch so we can just specify, get some performance boost because this prefetch doesn't get destroyed. Yeah. What is prefetch? Prefetch is like you have a member on a social club. And if you access a member, you will make one database query. If you make member and curly braces and access a social club, there's another query fired. And if you query member again inside the social club, there's again a query against the database. And a prefetch just makes one query and joins this data. So instead of querying member and then social club, to query member and social club and join them. And this is automatically done by how on? No, this is jungle code. So on the query level, we can do something like objects, select, prefetch. Prefetch is a reverse lookup. And select related is a one-to-many lookup. And we can say it's a member set here. And now all members from the social clubs are joined to this column. Yeah? But this approach probably works when you have not so much data, actually. Yeah. Like the member studies can fit into your memory. Yeah. But will you query your 20,000 members at one query, or will you use pigmentation or endless scrolling or? For sure, but the pigmentation, so the member is the host page of all the members right now? the nation of words here? Not out of the box. So I think there are 200 members, or 100, I don't know exactly. As soon as you have a big data set, I would move this search into something like Elasticsearch, get the IDs, and just query the IDs from Django. And if you want to gain more performance, to just select the columns you also specified in your query. So like from member, you only want first name, last name. You will make a dot values first name, last name to get only the first and last names out from the database and not select star from database. To run this mutation, you can define a mutation, create product, create product, so we have 10 minutes left. So I will just show you how you can use this. And inside here, you can just query again the stuff from your product, like ID, name, and so on. And then the input you specify, you get the variables. This is not clean code, because if you want to use this in the front end, you will do something like variable specification, like here, like you have an input, and this is of type input type, and so on. And we'll use this and send the variables in a separate field, so you can reuse this mutation with different variables and not hard code it inside here. So I don't think we have time left for exercise five, but I think it's very important to understand how interfaces work. So I will just show you how this thing works in the final. Final is everything you implemented, more or less, in this workshop. So there's something in the types called personal. personal, and the person interface, and interface is just a definition of fields in common. So it doesn't matter if this is a member or a guest, every member and guest has an ID, first name, last name, and a social club, and they only differ in age and rating. So you have something like from object, I mentioned it earlier, with a union type, like You can feed your person interface with member and guest and depending on the time, what this person really is, you can query the age or rating, I will show this in the GraphQL. Because this is a really nice tool name, where is it? So I prepared a social club where you can query by ID, just look up the source code and the to-dos and do your homework, then you know how you can do it. And there are persons, and the person has an ID and first name, and now it's some magic like dot, dot, dot, on, and I can say on member type I want to have additionally the age, and if this person is a guest, I want to have their rating. And this stuff differs on the type name. Every field comes with a type name and if you execute this query, you can see we have social club one with ID one. Let's take the name from it also and the social club number zero, okay. We have different persons like, okay, we have member, again a member, member, member, member, member. OK. And we have three guests. So this is very useful in the front end if you have something like an overview of your persons inside your social club, and you just want to flag it if it's a member or a guest. Yeah, we run a little bit out of time. If you have any questions about the exercise, especially maybe the five, because we didn't enter that. Just hit me up on Discord or write me an email. I love to talk about GraphQL, Django. Yeah. Thank you for being my audience. Are there any questions in general? What is your Discord tag then? I think you can, I will write it in the channel, in the room channel later. Yeah. Can I ask you about, I had a discussion where GraphQL is good for projects, where GraphQL is probably an overkill for projects? Yeah, that's a really good question. GraphQL is useful if you have many or more than one or two front ends. Like you have a web page and a custom native app. And you have to resolve different fields on each application. So on a desktop page, you may have more room to visualize stuff so we can query more in one time, while you have a nested navigation on a mobile device, and you don't have to fetch all query at one time, and you can query it nested. Actually, in my case, we have an analytical website, And it's only one front-end, but different backend components are used on different pages, let's say. Yeah. So one backend endpoint can be used in multiple places, slightly different ways. So I thought. Yeah, you can always make a member type 1, member type 2, like this. It's not really nice because this, again, the GraphQL shouldn't work like this. So you have a member, so you have one member type, and you define your fields, what you need in this member type. But nobody stops you from defining different types. So you also can make something like a federation. Just look it up. There you can define multiple schemas and just connect related fields. And you mount the schema you need for your analytics tool, what you need on the server. And you just have one endpoint. And it will route it to the right direction. Any more questions? Why would I use strawberry over graphene? I already mentioned this in my slides, I already closed them. Graphene with eight Ks of stars on GitHub has no active maintainer as far as I know. I used Graphene in the past for three years and then I switched to Strawberry because the maintainer was away and nobody maintained this project and the pull requests just increased and increased. And so I checked out other GraphQL libraries and I found Strawberry and Strawberry has such a nice community in Discord. If you ask any questions there, I think I have, if you wait two or three hours for an answer, it's long. So yeah. And the maintainer, Patrick, a really nice person. It's very helpful. And if you have a deep question about the framework, how something works, or if you understand something, if you don't understand something, he's mostly there and will help you. For instance, Strawberry, I think there's one release per day like this. But a really good change lot because there's a nice automatic release bot behind it. And each pull request also creates a release. And I don't have any breaking changes in the last two years, I think, because I just follow the change log, and it's stable enough. So yeah. Can I use GraphQL without Strawberry? GraphQL itself is just a specification. Strawberry is a library which implement this specification. So under the hood there is GraphQL core from Python, and there are many libraries sitting on this GraphQL core, and GraphQL core implements this specification. Strawberry says, OK, we use data classes. We use this at strawberry field decorator and so on. In Graphene, you have some magic with dev resolve underscore field name, and this will make the magic. So it doesn't matter if you take strawberry or graphene, because the specification for the front end for like a polo or relay will be the same. A nice thing about GraphQL is also you can deprecate fields. And it doesn't show up in the IDE. Or if it shows up, it is yellow underlined. And on each place in your code in VSC, for instance, your front end team uses member dot deprecated field, so like age is deprecated, they will get problems in the problems tab that they use a deprecated field. Also, GraphQL creates automatically TypeScript, so you don't have to write any query mutation, field definition. You don't need this. You just write your GraphQL files, how the query and mutations should look like, and this will create all the stuff for you. Yeah, nice. Thank you very much.