Looks like there's a flaw here: every section below "113. Alembic migrations on Heroku Postgres instance" is linked to 43200s timestamp. Good job anyways though, thank you!
I paid $1600 for a "Backend Python SQL and Devops" bootcamp and let me tell you...this video taught me more in 3 hours than I did in 3 months at the bootcamp. I haven't finished the video, currently stopping on 4:31:18 ORMs
At 13:55:05 for those who wondering what causing the Internal server error. In the postgres docker container the tables are not creating, so we need to create the tables in order perform the requested action on localhost:8000. Follow these steps it has worked for me 1) Put the command docker ps and find your container ID 2) Then enter into the bash -> docker exec -t YOUR_CONTAINER_ID bash 3) Now it will enter into the bash, type -> alembic upgrade head This will fix the issue by creating the tables to perform the action. Now go to Postman API and run the create user request, it will work. But the only issue is the data is not storing.
Thanks a million man. Live saver comment! I had to use: docker exec -it CONTAINER_ID bash if i only used the -t flag my terminal freeze. Anyways. Thanks a ton.
This guy is a LEGEND. If you disagree may you be condemned to using Pascal forever. Seriously, each of these segments is like a full course by itself! 00:00:10 Intro 00:06:33 Project overview 00:11:23 Setting up (Venv at 00:22:20) 00:34:17 FastAPI basics (Postman at 00:54:00) 02:24:10 Databases and SQL (psycopg at 03:58:21, ORM at 04:31:18) 05:50:08 Adding users 06:32:50 Authentication 07:42:44 Postman environments 07:50:33 Linking users to posts 08:38:30 Query parameters 08:53:53 Environment variables 09:21:20 Post voting framework 10:30:18 Alembic 11:14:28 CORS 11:23:38 Git 11:34:38 Deploying to Heroku 12:05:04 Deploying to a server (DigitalOcean) 13:04:42 SSL 13:20:05 Firewall 13:23:46 Push changes manually 13:26:08 Docker 14:14:49 Test framework 17:34:13 Automated CI/CD @freeCodeCamp.org
I thought 20 hours was a lot but now I'm seeing how detailed this course is. It shows how to do everything properly. Definately worth the time investment.
Hi, im python beginner, i know the basics of python included OOP and also the focus of my knowledge is Data Analytics. Is this course appropiate for my level? i know NOTHING about APIS
I think it would be nice to add it to your skillset cause there's lots of data related stuff here. Everything revolves around data.@@JesusSevillanoZamarreno-cu5hk
Started April 2022 and finished finally October 19th 2022 at 5:42 am. I cannot thank Sanjeev enough for this marvelous and comprehensive course. God bless you.
For those wondering, at 10:15:39, the bug was that he made the class PostOut inherit from PostBase instead of BaseModel. It was throwing errors because Pydantic was expecting all the members of class PostBase to be present in the object returned by the API.
have you finished this course? how was it? is it suitable for me who only knows Python? well, I know some HTML CSS JS to build simple website. because Im trying to deploy my Machine Learning project which is from Python libraries, into a sort of simple web app...
@@danielniels22 I think the course is well worth your time if you never used python in a real-world project. I have skipped the deploy part btw. I also suggest to watch in 1.25x or even 1.50x
@@luca-dallavalle i used Python a lot just in data science and machine learning related libraries, like pandas numpy sklearn tensorflow and some others. But never had experience for webdev, like django, flask, and fastapi. My understanding in other website language like html css JS PHP are still on the surface. but i need to do my school project. where I deploy my ML (which I mostly done only in Jupyter Notebook or Google Colab, which is not attractive), so I can make a simple web app....
Hi, I am having a problem while importing BaseModel from pydantic. The error says its unresolved. I have done all installations mentioned here. Please could you help me?
I don't usually comment on RUclips material I've watched, whether it was useful for otherwise, however I do feel compelled to say just how AWESOME this series is! Very thorough, at a good pace for beginner or intermediate level, and comprehensive. From references to relevant resources, to deep dives into the how and why of processes and implementation, I really got a lot out of this. So much so that I did the walkthrough once as it, and now I'm using it as reference and guide a second time (at 1.25 speed) for reiteration/repetition and in order to develop a new portfolio project based around a Music Library implementation. 5 out of 5 stars, would recommend.
I want to clarify the issue that is happening at 4:23:45. The cursor.execute() method takes an iterable object as its 2nd argument(like list, tuple, string, etc.), because internally the function loops through the values passed in 2nd argument, to place them into the "%s" placeholders of the 1st argument. Now, when we write like this :- (id) or like (2), because of only single value, it is considered as integer, and not a tuple even parenthesis are used. But if we just put a comma and make it like this:- (id,) or (2,), it is indicative of multiple values, and now the object is a tuple, which is an iterable. Here, we actually do not need the string conversion that is being shown here as cursor.execute(...,str(id)), and we can simply do it as cursor.execute(... , (id,)). It is better actually. But nevertheless, this content is best in RUclips. Hats off to freecodecamp and Mr. Sanjeev Thiyagarajan sir!
I was reading through the documentation since I'm using Psycopg3 and also found about the iterables, but your explanation helped me understand further, thanks!
Thank you so much for the explanation. It worked for me without the comma(,) but I ran into an error (not all arguments were converted to string) when i was passing ids of double digits. But adding the comma apparently solved the issue, but am curious how! Please explain if you knew. (btw: the two digit id arguments worked without the str conversion though based on your explanation above)
@@email2n I could only understand your question partially, and would answer to that. Actually, when you are putting a comma at the end (of a single element specially), python takes it as of a tuple datatype. Single element can be of other datatype, that might not be an iterable in python (if simply told, iterables are those datatypes that could be iterated by directly using for loop). Tuple is an iterable, and the paramter of cur.execute() is expected to be an iterable only. For better understanding, you can use the type() function. Inside it, pass the object with comma once, and without comma once, and print the results, and see how python takes the object to a different datatype due to putting of a comma at the end.
for those of you who are still getting an error at 10:22:17 like: TypeError('cannot convert dictionary update sequence element #0 to a sequence') try to add this line of code before returning results: results = list ( map (lambda x : x._mapping, results) ) When querying the db with two arguments in the .query method, sqlalchemy returns a list of sqlalchemy.engine.row.Row objects. As far as I have acknowledged from the documentation: "Changed in version 1.4: Renamed RowProxy to .Row. .Row is no longer a "proxy" object in that it contains the final form of data within it, and now acts mostly like a named tuple. Mapping-like functionality is moved to the .Row._mapping attribute, but will remain available in SQLAlchemy 1.x ... " So, in my understanding, we are not allowed to retrieve the jsonized data directly from the query anymore; the ._mapping method takes care of building the dict structure with "Post" and "votes" keys, and using map does this for each .Row element in the list; we then convert map to a list to be able to return it. Please feel free to correct me if I'm wrong, or if you have any better workaround.
You absolutely got me on this after an hour of debugging 😅.. I finally thought that it was a kind of a version conflict issue.. then scrolling to you comment! 😃.. Thanks Mattia
and if anybody having a problem with get_post function retrieving individual posts and get "AttributeError: 'Post' object has no attribute '__mapping' ", do not apply .first() method to the post variable, use .all() method instead. As I understand .first() returns first matching row as an object instead of giving us back an iterable or a list. Since we don't get a list we need and we have to use lambda, map(), and list() functions for that - an iterable is exactly what we want to deal with in this case (so that map() function would work and apply lambda function to each element of an iterable). SQLModel ----> Tutorial - User Guide ----> Read One Row
@@seanwaugh8911 Not saying that beginner can't take this course, but after almost finishing this course I can tell that knowing some concepts beforehand really speed ups things.
Great video, i am on 9:38:00 you can do the following. from typing import Literal. And then in class Vote you can write: dir: Literal[0, 1]. It will automatically check that value should be one of you specified in brackets
9:38:00 for conint you can also pass ge=0, so conint(ge=0, le=1) will constrain the integer to 0 or 1 (you could also use a bool which would only accept integers 0 and 1, but then it will be cast to bool so not ideal)
I was thinking like there must be some way to tell that it should be >= 0, but couldn't find it. Thanks for your post(reply) which gave me the answer to my problem.
using dir:bool really works pydantic doesnot performs typecasting when I tested(I dont know why) it throws validation error for everything except 0,1,true,false
I am still around 11 hrs into this course but I can truly tell the difference in the contents. I like how this course not only offers what's in the title but also a complete package from scratch. Especially with the SQL, alembic, git and other tools. Thanks a lot. I have learned so much till now with this course. Truly appreciate the effort.
Got stucked at 11:59:12 I was unable to connect to the instance postgres dB created in Heroku after entering all dB credentials Error message 👇 Unable to connect to sever: SSL error code 336151528 Will be glad to get help here
Hi, im python beginner, i know the basics of python included OOP and also the focus of my knowledge is Data Analytics. Is this course appropiate for my level? i know NOTHING about APIS
This course starts from basics. So, no worries if you do not know much about APIs. I say give it a go. Do a few of the lectures and see if they are understandable for you. What's the harm?
I like that when you look at the date at the bottom right of Sanjeev's computer when he started filming it was the 10th of June and by the time he finished it was the 18th of September! Thanks for the epic course...it's taken me 3 days to go through it!
at 4:24:06, if someone is wondering why we need an additional comma "," after (str(id)) like (str(id),), here is the explanation: in python the syntax to create a tuple is (ele,) when we have only one element named ele and not (ele) please check the output of the following: t = (1) print(type(t)) # o/p: t = (1,) print(type(t)) # o/p:
For those who are still thinking about the issue in 10:22:17 raise ValueError(errors) from e ValueError: [TypeError('cannot convert dictionary update sequence element #0 to a sequence'), TypeError('vars() argument must have __dict__ attribute')] Add this line before returning the results results = list(map(lambda x:x._mapping,results)) return(results) This works for me, it is a version conflict issue.
Truly incredible content. I'm currently a CS student and found this free course more helpful and practical than most of my classes. I really appreciate all the hard work Sanjeev and the team put into this; you guys are amazing!
This course had everything that i needed in my first project as a developer. Thank you for everything Sanjeev Thiyagarajan. I hope I can become a developer like you someday and give back to the community.
This is such outstanding content. I'm sure if people give themselves enough time for these 19h, they can build a whole career on this course! Just brilliant and epic!
Hi, im python beginner, i know the basics of python included OOP and also the focus of my knowledge is Data Analytics. Is this course appropiate for my level? i know NOTHING about APIS
@@JesusSevillanoZamarreno-cu5hk yes! i am 7 hours in, and this course is probably equivalent to taking a backend development course in a coding bootcamp
If you don't know anything about APIs please do a quick RUclips course from any of the channels to get a basic understanding of REST apis. Then if you know the basics of python, this should be good for your. @@JesusSevillanoZamarreno-cu5hk
@@JesusSevillanoZamarreno-cu5hk I think APIs are usually used in web deelopment in the where you might be required to integrate softwares like google maps and in this case API basically facilitates the interaction between the frontend and the backend. For Data analytics, you will be required to learn Machine learning models, statistics and a bit of data processing. Cheering for your journey in data analytics 👍.
A List wasn't the best choice to store that type of data, a dictionary would have been more suitable where Mapping was done as so all that was necessary is `dict.get(id)` to see if the key exists, this would also be convenient to solve the dupe id issue
About 5 hours in your course and I just wanted to make a genuine comment on the quality of the teaching, concepts that I've struggled with for a long time are now easy to work with. Very much qualified to teach ANYTHING.
When defining the Vote schema, you can pass multiple condition to conint() to ensure it only allows 0 and 1 as option for dir class Vote(BaseModel): post_id: int dir: conint(ge=0, le=1)
This works perfectly but you can as well create an enum instance to be able to present the exact accepted values: from enum import IntEnum class Choices(IntEnum): remove = 0 add = 1 class Vote(BaseModel): post_id: int direction: Choices
Was looking for this lol, though I don't understand why he doesn't just use a boolean to do this, it makes more intuitive sense to represent a like by true and no like by false.
@Sanjeev Thiyagarajan, Thank you for making this class available to the open source community. This course is the best FastAPI course I have taken. For others, I took three weeks of regular evening study to complete all 19 hours, but my VSCode remote development environment was a major challenge - all fixed now. As stated previously by other people, your teaching is on the next level. I am still looking to find a place to send you a monetary token of appreciation.
Around 11:55:05 I spend so much time trying to fix an issue here, so hopefully my comment can help someone: 1 - Since we use Alembic, the tables are not created when we start our containers so after running docker-compose up -d, you need to go inside the container and manually run the command: "docker exec -it bash" " alembic upgrade head" You should be able to create a user now. 2- If it says "database fastapi does not exist" whatever you had in the docker-compose file when your first ran it is probably still stored in there. Get rid of all volumes containers and ilages and restart: "docker image rm " "docker volume rm " and then docker-compose up -d and then step 1 and you'll be fine :D
where were you before?? ?? ????? So much knowledge in one video, I'm overloaded with excitement but I have to be calm down, things can get overwhelming easily. Massive thanks to you......... .. ......
At 4:23:50, the reason for putting a comma is because execute method requires a tuple. A single item such as id can be converted to tuple by putting a comma at the end. So, cursor.execute("SELECT * FROM posts WHERE id = %s", (id,)) would work as well. Amazing content. Thanks a ton for providing such gems. Sanjeev, you are AWESOME.❤
Finally finished it. Amazing experience. So thorough. The style of trying and committing errors and correcting it on the fly by suggesting alternatives and making us part of his thinking process to fix the errors was very helpful. The only thing missing was if he could have added a basic UI for the social media post with a simple frontend(React.js ?) would have made this tutorial a full package. But hey it can be an assignment for me to try that part. Have been hearing this man's voice daily a little for over a month and now feels strange that I'll miss it.
@@khanhnam61 FastAPI and Django are different architecture .. IMHO, Django is like a truck with a full container and FastAPI is like a truck with empty container so its perform better and you can customize.. But django-ninja come to close this gap..
4:21:49 I think the more appropriate fix is to use (id,) instead of (str(id)). The error is there because it expects an object that supports indexing, so putting a comma after id would make it indexable. Edit: Ok you mentioned about the comma later ... all good.
To add some context to your comment, the indexing issue is because he is trying to pass a tuple with a single value. Tuples with a single value requires a comma after the value. With out the comma, python doesn't recognize it as a tuple, and that's creating the error. From the Psycopg docs: "For positional variables binding, the second argument must always be a sequence, even if it contains a single variable (remember that Python requires a comma to create a single element tuple):" Apparently Psycopg is cool with using a list instead of tuple. IIRC, the SQLite3 module in Python requires that positional variables be a tuple. Also, as you mentioned, all he needed to do was (id,). It's not necessary to convert the id to a string as psycopg handles converting whatever input it is given to a string. It's all in the docs here: www.psycopg.org/docs/usage.html#passing-parameters-to-sql-queries
Yes, we need to use a tuple, and tuples do this weird thing that if you need one that only has 1 value, you must end it with a comma, i.e., my_tuple = (1,)
If you are watching this after Jan 2023, and you install SQLAlchemy using the pip install command, it will install version 2.0.x or above by default. The code at the 10:25:00 hr marker where you get count is incompatible with the new version of SQLAlchemy. I spent a few hours figuring out why my exact same code isn't working. Use the following command to install (or re-install) to a compatible version of SQLAlchemy pip install --force-reinstall -v "SQLAlchemy==1.4.46" Also, your PostOut pydantic schema should derive from BaseModel, not Post or PostBase.
SQLAlchemy==1.4.46 has broken all my database connection and I couldn't fix it. So I came back to 1.40. I still have problem to present "results" as {"Post": {...}, "Votes":...} json. Read @luca-dallavalle solution below. Basically inherit PostOut from BaseModel not PostBase.
I was struggling for the first hour to set up those things. now, 4 hours and keep going. my feeling: every word, and explanation is precise and easy to follow, I may not judge it's the best practice but this is actually the comprehensive way to get started to learn from 0. Many thanks to Sanjeev Thiyagarajan !!
Such A Great Course Thankyou sir, at 04:24:00 the error is because the second argument should be a tuple. So we have to use comma. Think it helps Others.
Finally, the course is completed by me and I can't thank enough Sanjeev and FCC for such a quality content they have put out on Internet, this course is a blessing for people like me who want to learn development on their own. This is premium level package dished out in Python, I 100% recommend this to a person looking for a learning as a Python backend developer. I don't know why but I am bit sad the course is over now... Once again a huge thanks to Sanjeev and FCC!!!
Before doing this course I had no idea about API and I was mostly learning about Machine Learning and I did this course and after a week got an interview for backend engineer (internship) and now i'm working as a software engineer at a tech compnay. Thank you so much for this.
I normally don't bother with courses as i think it's faster to read a book on the topic, but this course is actually legendary. There were quite a few topics i didn't get even up to now that suddenly make a whole lot of sense in less than 30 mins. can 1000000% recommend
For those who're getting error in 9:38:00 , try to use Annotated with Fields instead of conint. It has been deprecated in pydantic 3.0 #Schema for vote class Vote(BaseModel): post_id :int dir: Annotated[int, Field(ge=0, le=1)]
The amount of material covered in this video is amazing. I have spent over 30 hours watching and re-watching portions of the video while taking notes. Thank you for all the detailed explanations and examples.
This is amazing. Just two hours in and I have learned more than with other courses which were way longer. I can't believe this is free! Thank you so much ❤️
Estoy en el mismo camino! Estaba aprendiendo django pero luego de ver un poco lo completo que es este curso y lo que ofrece FastAPI decidí cambiarlo y comenzar este curso!
Finally completed this 19 hour long course, it is my first time completing any course as I leave most of them half way. This is possible because of great explanation given by excellent teacher. Thank you Sanjeev Thank you FCC. 🤗🤗
Just completed this one. Oh man 19 hours!! Totally worth it , learnt a lot, would definately recommend for anyone whose thinking of starting this one. Everything is explained in detail and I'm sure you'll enjoy learning all the technologies that are used.
Went through the entire course. I learnt around 1000 different concepts in Python, ORMs, Database Migrations, Dockerising, Testing(Woah this was super complicated, even though Sanjeev made it as easy as possible), and the best part was pushing to production and docker hub at the end... All this in 36 hours.
I did some digging in the psycopg2 implementation and I think I have an explanation that ties together what you're addressing at 4:21:33 and 4:23:36. TLDR: Always use a 'sequence' like tuples, lists, and so on for the second parameter of cursor.execute(). For tuples with a single object, write '(object, )' instead of '(object)'. Firstly, we should look at some signatures. The execute method for cursor objects: def execute(self, query: str | bytes | Composable, vars: _Vars = ...) -> None: ... The _Vars type alias: _Vars: TypeAlias = Sequence[Any] | Mapping[str, Any] | None These explain what makes the 'convert to str' workaround tick. But as you've demonstrated before while writing the create_posts function, you can pass non-string values (e.g., bools in the case of post.published) just fine. So, why wasn't '(id)' working? I think this is because of the weird syntax of Python's tuples. '(id)' is not necessarily a tuple, and therefore not a sequence either. But '(id, )' is always a tuple in Python, and so it works just fine. But when you're forcing it to be a tuple with that extra comma, your previous workaround of converting to string becomes redundant. And because that workaround doesn't always work, I think it's safe to say that we should try not to write code that way. I hope this helped.
Just in case anyone was wondering why the id parameter for the cursor.execute method needed a comma at 4:24:11 , the psycopg2 library requires the parameters for the query to be provided as a sequence. adding a comma, passes the id as a single tuple
for the pytest section of the course: I can strongly recommend an extension for VS Code called Test Explorer UI. You can then run each individual test or bundle. Recommended.
The issue around 4:23:53 (and actually I also believe the issue around why it's not accepting an int) is because the cursor.execute() function expects a Tuple as the second argument. Without the comma the parenthesis are meaningless. cursor.execute("""SELECT * FROM posts WHERE id=%s""", (id,)) works just fine
Close, but not quite accurate. It's because it's expecting an indexable object. an int isn't indexable . A tuple is, so that works, so does an array [id] or even {id} as well as the tuple (id,)
@@jamesreader5955 Right. vars needs to be indexable, so (id,) or [id] is best. Converting id into a string only works when using a single digit id. If you try with id=10, then it would take the first index (which is '10'[0], so '1') for the first %s, but not know what to do with the second index (which is '10'[1] , so '0'). So you would get a TypeError, since not all arguments '1' and '0' would be able to be converted during string formatting.
4:23:40 the execute method expects a sequence or mapping, and adding the comma declares the id as a tuple with one element, satisfying the type requirement. source: i paused the video and followed the stack trace to the docs for 20 min then resumed the video and you immediately solved the issue
Issue at 10:26:00 The issue seems to lie in inheriting from PostBase (or Post for that matter) from schemas. The issue is fixed when PostOut inherits from BaseModel instead. As the response (without response model) returns a Post dictionary and a vote count, it does not have the fields that PostBase requires (title and content are present in the Post dictionary within the response, not within the response directly like vote count). PostBase (or Post) can be used if a new dictionary is defined that includes all the fields that PostBase (or Post) requires. Also orm_mode need not be set in PostOut as it uses the class Post that has orm_mode set (this is used to import owner information and show it as a dictionary despite it being an object). Also the fields defined in PostOut must match what the query returns (which can be seen by removing the response model), which is why the field 'Post' must have a capital P (as the model.py contains Post) and why the label for vote count in the query must be the same as the respective field defined in PostOut.
This comment was exactly what I was looking for!! I was re-reading the FastAPI pydantic and SQL Database docs and not getting the answer to why my code wasn't working. Now my code is working, I understand the capital P 'Post' and 'votes' labels better and finally need to look again at the inheritance docs to solidify my understanding there. Thanks so much @Ammar
Got stucked at 11:59:12 I was unable to connect to the instance postgres dB created in Heroku after entering all dB credentials Error message 👇 Unable to connect to sever: SSL error code 336151528 Will be glad to get help here
I don't know if anyone has answered this already or not, but at 4:23:47 where he talks about receiving an error for not including a comma is because in python single value tuples can only be created by including a comma after the singular value as we are passing a tuple in the second argument of execute command for singular values we need to include the comma for correct python syntax. Thanks for this amazing tutorial.
I finally finished this after almost two months Alhamdulillah... It was a long and enjoyable process for me but sometimes it was very challenging. I did all the things inside the course except a few parts in the testing section. I think I learned a looooot. I have to review some of the previous sections. Thank you, Mr. Sanjeev!
Well, I did it. Just finished the course and I'm glad I did. I came to learn FastAPI, and that section was straight forward along with the official documentation, which is fine, but where this course really shines is by introducing you to all the other technologies alongside it. If you don't know anything about CI/CD, testing, or deployment, then I recommend sticking it through. Thanks.
Project building based teaching method should be the teaching standard Fabulous tutorial succeeded to understand the Python apps concept despite being a totally newbie Thank you!
This is one of the best tutorials I found for beginners to understand APIs from scratch, really like how you explain the JWT part, it makes thing so clear and easy to understand. Really appreciate your hard work hope to see your tutorial more so we all can learn more x)
@@akshayrr3061 haven't, I'm now at 7:28:00, and alr learnt lot of stuff like how to make a simple API, how to play with the API without a frontend and what is ORM, also he taught about the JWT stuff which is very interesting as well like how simple Web application can applied token based sign on and many more and I will continue watching it ltr on, it's really beginner friendly, if you have only learnt about basic programming and have 0 knowledge on things like Flask-mega, fast api, rest api, databases, sql, this is the right videos. As the timestamp mentioned at the description, I believe we can learn more about how deployment works how to make unit testing and etc, this is definitely worth the time. And what's more even better is, he will always show some error intended or accidentally, and will show the solution to it which is a good way for beginners to learn how a experienced programmer figure out and solved the problem 10/10 Ps: I have learnt about flask mega before through the "Microblog" tutorials, and it is very hard for me as the tutor are teaching in a way that I'm not a beginner (I was really new to Web applications that time), so I highly recommend this if u are a fresh beginner like me that time Sorry for the long words, hope this will help you.
This course was very helpful! I'm not a programmer but have spent the last 4 months teaching myself Python and SQL. I need to develop the phone app for me and subscribers to access my program remotely but had no clue where to start. This course has definitely helped me understand the next steps I need to take. Thank you so much!
At 9:38:00 If you just want two values, you can use a custom validator class Vote(BaseModel): post_id:int direction:int @validator('direction') def direction0or1(cls, d): if (d == 0) or (d == 1): return d else: raise ValueError('Integer must be 0 or 1') This is a custom validator and it'll ensure if the given integer is only 0 or 1
4:23:49 - what causes the issue, is that in python in order to declare a tuple it has to have at least one comma inside the parenthesis, otherwise it would be considered a simple variable as if there were no parenthesis. that's why you ran into this issue at first place. and you don't have to convert the argument into a string. to fix the issue just write it like this: (id,) or you can use named parameters cursor.execute("SELECT * FROM posts WHERE id = %(id)s", ('id' = id))
09:38:05 for the vote model and new pydantic updates, it can be done in the following way, make sure to import these: from typing import Annotated from pydantic import Field class Vote(BaseModel): post_id: int dir: Annotated[int, Field(ge=0, le=1)] According to pydantic, conint returns a new type which cause issues with static type checkers, while, Annotated allows to add metadata (like constraints) to existing types, thus making it more type-safe and clear. Field(ge=0, le=1): this specifies that dir must be greater than or equal to 0 (inclusive), and less than or equal to 1 (inclusive). Cheers
I still can't understand, there are people like him who are doing this for free! You are contributing to this community, I hope one day I'll be in a position like you who can contribute like you! Thank you so much, next goal is to complete this video in a week!
same man... he could have easily chose the "buy my course because i know your company will pay for it" sector, but instead chose to give public access. The world is truly filled with kind and genuine people!
This is a goldmine of knowledge. I learned a lot of new concepts. I can't thank Sajeev enough for doing a fantastic job of explaining everything. And thank you, FCC, for this video.
Great course, lots of valuable info. Also appreciate keeping things like 3:31:49 in, the random things that happen to everyone we don't always get. Here, for those wondering, he highlighted some text before running the query, that's why he got the syntax error, as it was only running the highlighted part.
4:24:10 The execute() function expects some sequence type and this comma indicates that this is a tuple not just a string and it's better to put it there so you will not run into some unexpected behaviours later on (e.g. the code will run on some machines and on some it won't)
At 4:24:00 you wonder why you need the extra comma this is because the second argument has to be a sequence (iterable) . A quirk of python is that (id) is not a tuple. To create a tuple you have to do (id,) else it sees it as an int. Interesting thing is, because it expects an iterable you can use a list like this ("""SELECT * FROM posts WHERE id=%s""", [id]).fetchone().
This is a truly wonderful course. I actually completed this course a few months back and learnt so much! I am back again to revise everything I learned and to brush up on some difficult concepts. I have even recommended this course to my colleagues who were making a transition from front-end development to full stack. Great work, keep it going, and thank you so much for the hard work :)
Amazing course! Thanks a lot 10:25:00 issue was in inheritance from PostBase instead of BaseModel. Not in capital or lower letter. Hope will help someone
I tried to extend BaseModel instead of PostBase. It solved the content and the title issue but the votes part still giving me error. ( value_error.missing). ı tried to make votes an optional parameter. it worked but ı dont want it to be optional. Any ideas? My schemas are like the below:
class PostOut(BaseModel): Post: Post votes: int class Config: orm_mode = True
I can't believe they've put this one youtube for free, you guys are legends
That's why they named this channel free code camp
ruclips.net/video/5FsIa4Mp3ho/видео.html
How much I love FCC, I owe my entire Software Dev Skills to them including my recent Software Engineering role
So you watched the full video right.. 😅
Mad lads
### Section 1: Introduction
1. Course Project
2. Course Intro
3. Course Project Overview 06:33
### Section 2: Setup & installation
4. Mac Python Installation 11:22
5. Mac VS Code install and setup 13:15
6. Windows Python Installation 16:37
7. Windows VS Code install and setup 18:30
8. Python virtual environment Basics 22:11
9. Virtual environment on windows 24:35
10. Virtual environment on Mac 28:56
### Section 3: FastAPI
11. Install dependencies w/ pip 34:17
12. Starting Fast API 36:21
13. Path operations 39:23
14. Path Operation Order(yes it matters) 51:08
15. Intro to Postman 53:22
16. HTTP Post Requests 57:34
17. Schema Validation with Pydantic 1:07:29
18. CRUD Operations 1:22:45
19. storing posts in Array 1:29:44
20. creating posts 1:34:06
21. Postman Collections & saving requests 1:38:15
22. Retrieve One Post 1:39:47
23. Path order Matters 1:48:10
24. Changing response Status Codes 1:52:46
25. Deleting Posts 2:01:49
26. Updating Posts 2:10:31
27. Automatic Documentation 2:18:02
28. Python packages 2:21:34
### Section 4: Databases
29. Database Intro 2:24:11
30. Postgres Windows Install 2:28:54
31. Postgres Mac Install 2:31:28
32. Database Schema & Tables 2:34:26
33. Managing Postgres with PgAdmin GUI 2:44:35
34. Your first SQL Query 3:12:10
35. Filter results with "where" keyword 3:19:43
36. SQL Operators 3:22:55
37. IN Keyword 3:26:38
38. Pattern matching with LIKE keyword 3:28:07
39. Ordering Results 3:31:59
40. LIMIT & OFFSET 3:36:27
41. Inserting Data 3:39:21
42. Deleting Data 3:47:16
43. Updating Data 3:50:11
### Section 5: Python + Raw SQL
44. Setup App Database 3:53:48
45. Connecting to database w/ Python 3:58:21
46. Retrieving Posts 4:08:00
47. Creating Post 4:11:53
48. Get One Post 4:19:18
49. Delete Post 4:24:12
50. Update Post 4:26:31
### Section 6: ORMs
51. ORM intro 4:31:18
52. SQLALCHEMY setup 4:35:33
53. Adding CreatedAt Column 4:55:25
54. Get All Posts 5:00:59
55. Create Posts 5:07:55
56. Get Post by ID 5:15:50
57. Delete Post 5:19:50
58. Update Post 5:22:31
### Section 7: Pydantic Models
59. Pydantic vs ORM Models 5:28:21
60. Pydantic Models Deep Dive 5:32:21
61. Response Model 5:38:57
### Section 8: Authentication & Users
62. Creating Users Table 5:50:08
63. User Registration Path Operation 5:54:50
64. Hashing User Passwords 6:03:27
65. Refractor Hashing Logic 6:08:49
66. Get User by ID 6:10:32
67. FastAPI Routers 6:17:13
68. Router Prefix 6:27:34
69. Router Tags 6:30:31
70. JWT Token Basics 6:32:49
71. Login Process 6:47:03
72. Creating a Token 7:00:44
73. OAuth2 PasswordRequestForm 7:09:58
74. Verify user is Logged In 7:13:23
75. Fixing Bugs 7:25:21
76. Protecting Routes 7:27:59
77. Test Expired Token 7:36:17
78. Fetching User in Protected Routes 7:38:13
79. Postman advanced Features 7:42:44
### Section 9: Relationships
80. SQL Relationship Basics 7:50:33
81. Postgres Foreign Keys 7:54:59
82. SQLAlchemy Foreign Keys 8:07:20
83. Update Post Schema to include User 8:13:40
84. Assigning Owner id when creating new post 8:17:59
85. Delete and Update only your own posts 8:21:01
86. Only Retrieving Logged in User's posts 8:27:48
87. Sqlalchemy Relationships 8:33:37
88. Query Parameters 8:38:32
89. Cleanup our main.py file 8:50:46
90. Environment Variables 8:53:53
### Section 10: Vote/Like System
91. Vote/Like Theory 9:21:20
92. Votes Table 9:26:36
93. Votes Sqlalchemy 9:31:33
94. Votes Route 9:34:11
95. SQL Joins 9:52:31
96. Joins in SqlAlchemy 10:15:26
97. Get One Post with Joins 10:28:21
### Section 11: Database Migration w/ Alembic
98. What is a database migration tool 10:30:18
99. Alembic Setup 10:33:45
100. Alembic First Revision
101. Alembic Rollback database Schema
102. Alembic finishing up the rest of the schema
103. Disable SqlAlchemy create Engine 11:13:50
### Section 12: Pre Deployment Checklist
104. What is CORS????? 11:14:28
105. Git PreReqs 11:23:38
106. Git Install 11:27:40
107. Github 11:29:23
### Section 13: Deployment Heroku
108. Heroku intro 11:34:39
109. Create Heroku App 11:35:40
110. Heroku procfile 11:40:21
111. Adding a Postgres database 11:44:59
112. Environment Variables in Heroku 11:48:42
113. Alembic migrations on Heroku Postgres instance 11:58:59
114. Pushing changed to production 12:02:52
### Section 14: Deployment Ubuntu
115. Create an Ubuntu VM 12:05:04
116. Update packages 12:08:04
117. Install Python 12:10:47
118. Install Postgres & setup password 12:12:21
119. Postgres Config 12:17:28
120. Create new user and setup python environment 12:24:50
121. Environment Variables 12:34:06
122. Alembic migrations on production database 12:42:24
123. Gunicorn 12:45:57
124. Creating a Systemd service 12:54:12
125. NGINX 13:04:45
126. Setting up Domain name 13:10:45
127. SSL/HTTPS 13:15:19
128. NGINX enable 13:19:31
129. Firewall 13:20:06
130. Pushing code changes to Production 13:23:47
### Section 15: Docker
131. Dockerfile 13:26:09
132. Docker Compose 13:38:39
133. Postgres Container 13:48:34
134. Bind Mounts 13:56:22
135. Dockerhub 14:03:39
136. Production vs Development 14:08:08
### Section 16: Testing
137. Testing Intro 14:14:51
138. Writing your first test 14:17:19
139. The -s & -v flags 14:30:22
140. Testing more functions 14:31:44
141. Parametrize 14:35:29
142. Testing Classes 14:40:21
143. Fixtures 14:48:37
144. Combining Fixtures + Parametrize 14:55:40
145. Testing Exceptions 14:59:13
146. FastAPI TestClient 15:06:07
147. Pytest flags 15:14:26
148. Test create user 15:17:31
149. Setup testing database 15:25:23
150. Create & destroy database after each test 15:36:47
151. More Fixtures to handle database interaction 15:44:18
152. Trailing slashes in path 15:50:35
153. Fixture scope 15:53:12
154. Test user fixture 16:07:50
155. Test/validate token 16:14:40
156. Conftest.py 16:18:59
157. Failed login test 16:22:09
158. Get all posts test 16:28:28
159. Posts fixture to create test posts 16:29:34
160. Unauthorized Get Posts test 16:51:33
161. Get one post test 16:55:16
162. Create post test 16:59:19
163. Delete post test 17:08:05
164. Update post 17:15:17
165. Voting tests 17:22:09
### Section 17: CI/CD pipeline
166. CI/CD intro 17:34:15
167. Github Actions 17:43:29
168. Creating Jobs 17:49:32
169. Setup python/dependencies/pytest 17:57:38
170. Environment variables 18:06:14
171. Github Secrets 18:11:19
172. Testing database 18:18:14
173. Building Docker images 18:23:42
174. Deploy to Heroku 18:34:33
175. Failing tests in pipeline 18:49:10
176. Deploy to Ubuntu 18:52:18
The Hero of the comments!
Thanks fam
I am going through this course and this indexing is helping a lot, thank you!
Looks like there's a flaw here: every section below "113. Alembic migrations on Heroku Postgres instance" is linked to 43200s timestamp.
Good job anyways though, thank you!
@@kj_ysmemhs_int we have to wait until Google fix it
People pay more than $2000 for Python lectures and they don’t come close to quality content like this. YOU ARE ABSOLUTE LEGENDS!
You are right.
I paid $1600 for a "Backend Python SQL and Devops" bootcamp and let me tell you...this video taught me more in 3 hours than I did in 3 months at the bootcamp. I haven't finished the video, currently stopping on 4:31:18 ORMs
@@kairoswave Boot camps are just MLM for tech bros.
@@theblindprogrammer agreed 💯
@@kairoswave Are you studying in College or self taught?
At 13:55:05 for those who wondering what causing the Internal server error. In the postgres docker container the tables are not creating, so we need to create the tables in order perform the requested action on localhost:8000.
Follow these steps it has worked for me
1) Put the command docker ps and find your container ID
2) Then enter into the bash -> docker exec -t YOUR_CONTAINER_ID bash
3) Now it will enter into the bash, type -> alembic upgrade head
This will fix the issue by creating the tables to perform the action. Now go to Postman API and run the create user request, it will work. But the only issue is the data is not storing.
savior of the day - badrinarayanans355
what do you mean by "not storing", after simple testing, i am able to retrieve data even after "docker compose down" and back up.
Thanks a lot
fix worked for me, but also not storing data in DB after fix. Anyone know how to fix this?
Thanks a million man. Live saver comment!
I had to use:
docker exec -it CONTAINER_ID bash
if i only used the -t flag my terminal freeze. Anyways. Thanks a ton.
I was a carpenter before this video, now I am a senior developer at SpaceX. You guys have changed my life!
Why didn't you learn a little magic? You could have started your own religion. Then u could have changed our lives.
How is that possible ??
@@michealmagbagbeola3214 He was a magic carpenter... weren't you paying attention?
@@michealmagbagbeola3214 It's a joke.
i can't believe this, OMG u are so inspirational
I'm going to watch this whole course 2 hours a day. So many concepts i've wanted to learn in one package, amazing!
Are you on track, my friend?
@@vamsimohanramineedi7630 Yes, I'm 3.5 hours in, haven't been able to 2 hours a day, but I'm getting there!
@@vamsimohanramineedi7630 Mee Too, I'm currently in the Shaping response part using Pydantic !!
Great. I am doing the same. Let's keep going.
@@akanimohosutuk928 Good luck! I'm at 9 hour mark, and I've already learned so much new.
This is what I've been searching all day, and these GIGA CHADS blessed me again. Thank you so much!
Pplpp you
Sop m
lpp
I searched for 2 days!
This guy is a LEGEND. If you disagree may you be condemned to using Pascal forever. Seriously, each of these segments is like a full course by itself!
00:00:10 Intro
00:06:33 Project overview
00:11:23 Setting up (Venv at 00:22:20)
00:34:17 FastAPI basics (Postman at 00:54:00)
02:24:10 Databases and SQL (psycopg at 03:58:21, ORM at 04:31:18)
05:50:08 Adding users
06:32:50 Authentication
07:42:44 Postman environments
07:50:33 Linking users to posts
08:38:30 Query parameters
08:53:53 Environment variables
09:21:20 Post voting framework
10:30:18 Alembic
11:14:28 CORS
11:23:38 Git
11:34:38 Deploying to Heroku
12:05:04 Deploying to a server (DigitalOcean)
13:04:42 SSL
13:20:05 Firewall
13:23:46 Push changes manually
13:26:08 Docker
14:14:49 Test framework
17:34:13 Automated CI/CD
@freeCodeCamp.org
I thought 20 hours was a lot but now I'm seeing how detailed this course is. It shows how to do everything properly. Definately worth the time investment.
Hi, im python beginner, i know the basics of python included OOP and also the focus of my knowledge is Data Analytics. Is this course appropiate for my level? i know NOTHING about APIS
I think it would be nice to add it to your skillset cause there's lots of data related stuff here. Everything revolves around data.@@JesusSevillanoZamarreno-cu5hk
@@JesusSevillanoZamarreno-cu5hk Yes, absolutly
@@JesusSevillanoZamarreno-cu5hk In my view, I don't think this is really much of something you should learn. Perhaps of curiosity that's fine.
Started April 2022 and finished finally October 19th 2022 at 5:42 am. I cannot thank Sanjeev enough for this marvelous and comprehensive course. God bless you.
would mastering everything in the video make ones-self fully employable ?
@@IanSilxr you have to learn a bit of front end and more devops
For those wondering, at 10:15:39, the bug was that he made the class PostOut inherit from PostBase instead of BaseModel. It was throwing errors because Pydantic was expecting all the members of class PostBase to be present in the object returned by the API.
Thank you very much!! I was stuck.
have you finished this course? how was it? is it suitable for me who only knows Python?
well, I know some HTML CSS JS to build simple website. because Im trying to deploy my Machine Learning project which is from Python libraries, into a sort of simple web app...
@@danielniels22 I think the course is well worth your time if you never used python in a real-world project. I have skipped the deploy part btw. I also suggest to watch in 1.25x or even 1.50x
@@luca-dallavalle i used Python a lot just in data science and machine learning related libraries, like pandas numpy sklearn tensorflow and some others. But never had experience for webdev, like django, flask, and fastapi. My understanding in other website language like html css JS PHP are still on the surface.
but i need to do my school project. where I deploy my ML (which I mostly done only in Jupyter Notebook or Google Colab, which is not attractive), so I can make a simple web app....
Hi, I am having a problem while importing BaseModel from pydantic. The error says its unresolved. I have done all installations mentioned here. Please could you help me?
I just wanna say that this channel is a pure gold on RUclips and i want to thank the whole team of free code camp for these content. !!!!
I don't usually comment on RUclips material I've watched, whether it was useful for otherwise, however I do feel compelled to say just how AWESOME this series is! Very thorough, at a good pace for beginner or intermediate level, and comprehensive. From references to relevant resources, to deep dives into the how and why of processes and implementation, I really got a lot out of this. So much so that I did the walkthrough once as it, and now I'm using it as reference and guide a second time (at 1.25 speed) for reiteration/repetition and in order to develop a new portfolio project based around a Music Library implementation. 5 out of 5 stars, would recommend.
I want to clarify the issue that is happening at 4:23:45.
The cursor.execute() method takes an iterable object as its 2nd argument(like list, tuple, string, etc.), because internally the function loops through the values passed in 2nd argument, to place them into the "%s" placeholders of the 1st argument. Now, when we write like this :- (id) or like (2), because of only single value, it is considered as integer, and not a tuple even parenthesis are used.
But if we just put a comma and make it like this:- (id,) or (2,), it is indicative of multiple values, and now the object is a tuple, which is an iterable.
Here, we actually do not need the string conversion that is being shown here as cursor.execute(...,str(id)), and we can simply do it as cursor.execute(... , (id,)). It is better actually.
But nevertheless, this content is best in RUclips. Hats off to freecodecamp and Mr. Sanjeev Thiyagarajan sir!
I was reading through the documentation since I'm using Psycopg3 and also found about the iterables, but your explanation helped me understand further, thanks!
@@alhensouher Happy to help!
Thank you so much for the explanation.
It worked for me without the comma(,) but I ran into an error (not all arguments were converted to string) when i was passing ids of double digits. But adding the comma apparently solved the issue, but am curious how! Please explain if you knew.
(btw: the two digit id arguments worked without the str conversion though based on your explanation above)
@@email2n I could only understand your question partially, and would answer to that. Actually, when you are putting a comma at the end (of a single element specially), python takes it as of a tuple datatype. Single element can be of other datatype, that might not be an iterable in python (if simply told, iterables are those datatypes that could be iterated by directly using for loop).
Tuple is an iterable, and the paramter of cur.execute() is expected to be an iterable only.
For better understanding, you can use the type() function. Inside it, pass the object with comma once, and without comma once, and print the results, and see how python takes the object to a different datatype due to putting of a comma at the end.
that's what I was looking
for those of you who are still getting an error at 10:22:17 like:
TypeError('cannot convert dictionary update sequence element #0 to a sequence')
try to add this line of code before returning results:
results = list ( map (lambda x : x._mapping, results) )
When querying the db with two arguments in the .query method, sqlalchemy returns a list of sqlalchemy.engine.row.Row objects. As far as I have acknowledged from the documentation:
"Changed in version 1.4:
Renamed RowProxy to .Row. .Row is no longer a "proxy" object in that it contains the final form of data within it, and now acts mostly like a named tuple. Mapping-like functionality is moved to the .Row._mapping attribute, but will remain available in SQLAlchemy 1.x ... "
So, in my understanding, we are not allowed to retrieve the jsonized data directly from the query anymore; the ._mapping method takes care of building the dict structure with "Post" and "votes" keys, and using map does this for each .Row element in the list; we then convert map to a list to be able to return it.
Please feel free to correct me if I'm wrong, or if you have any better workaround.
You absolutely got me on this after an hour of debugging 😅.. I finally thought that it was a kind of a version conflict issue.. then scrolling to you comment! 😃.. Thanks Mattia
@@tarekhiast you're welcome Tarek, I'm glad it helped! Yeah that took me a while to debug too.. 😅
and if anybody having a problem with get_post function retrieving individual posts and get "AttributeError: 'Post' object has no attribute '__mapping' ", do not apply .first() method to the post variable, use .all() method instead. As I understand .first() returns first matching row as an object instead of giving us back an iterable or a list. Since we don't get a list we need and we have to use lambda, map(), and list() functions for that - an iterable is exactly what we want to deal with in this case (so that map() function would work and apply lambda function to each element of an iterable).
SQLModel ----> Tutorial - User Guide ----> Read One Row
Thankyou mattia for providing the solution, now I understand that it is a version conflict. It works.
Thanks @mattiapavese4465, you save my life !!!
I have 2 years experience in this, and genuinely saying this is premium course level content.
Is this a good course for beginners?
@@seanwaugh8911 Not saying that beginner can't take this course, but after almost finishing this course I can tell that knowing some concepts beforehand really speed ups things.
@@TheRonpe thank you. I'm currently learning python and I haven't made anything really exciting yet. I'll give it a try.
Dude my man is doing general programming tutorial in a single video, what a legend 👍.
Great video, i am on 9:38:00 you can do the following. from typing import Literal. And then in class Vote you can write: dir: Literal[0, 1]. It will automatically check that value should be one of you specified in brackets
Yeah, or anither option:
dir: Annotated[int, Field(ge=0, le=1)]
Bro, ya'll make me have faith in humanity. So much knowledge given for free. so much hard work on your side. Thank you :)
9:38:00 for conint you can also pass ge=0, so conint(ge=0, le=1) will constrain the integer to 0 or 1 (you could also use a bool which would only accept integers 0 and 1, but then it will be cast to bool so not ideal)
Thanks man
I was thinking like there must be some way to tell that it should be >= 0, but couldn't find it. Thanks for your post(reply) which gave me the answer to my problem.
using dir:bool really works
pydantic doesnot performs typecasting when I tested(I dont know why)
it throws validation error for everything except 0,1,true,false
@@karthiksalian1635 works better actually
I am still around 11 hrs into this course but I can truly tell the difference in the contents. I like how this course not only offers what's in the title but also a complete package from scratch. Especially with the SQL, alembic, git and other tools. Thanks a lot. I have learned so much till now with this course. Truly appreciate the effort.
Got stucked at 11:59:12
I was unable to connect to the instance postgres dB created in Heroku after entering all dB credentials
Error message 👇
Unable to connect to sever: SSL error code 336151528
Will be glad to get help here
@@adigunoluwadamilolavictori7170 What is the command that you ran? after alembic upgrade head?
What are the prerequisites?
@@KnowledgeKattaOffi knowledge in python
Cant believe I just finished 19 hours of this. This course is gold! Thank you so much Sanjeev!
wow congratulationss
Hi, im python beginner, i know the basics of python included OOP and also the focus of my knowledge is Data Analytics. Is this course appropiate for my level? i know NOTHING about APIS
This course starts from basics. So, no worries if you do not know much about APIs. I say give it a go. Do a few of the lectures and see if they are understandable for you. What's the harm?
I like that when you look at the date at the bottom right of Sanjeev's computer when he started filming it was the 10th of June and by the time he finished it was the 18th of September! Thanks for the epic course...it's taken me 3 days to go through it!
at 4:24:06, if someone is wondering why we need an additional comma "," after (str(id)) like (str(id),), here is the explanation:
in python the syntax to create a tuple is (ele,) when we have only one element named ele and not (ele)
please check the output of the following:
t = (1)
print(type(t)) # o/p:
t = (1,)
print(type(t)) # o/p:
How 'passlib' library verifies password if it produces different hash for same password?
@@DhruvPatel-qo9kh the passlib hashes to same value if the password in plain text is the same
For those who are still thinking about the issue in 10:22:17
raise ValueError(errors) from e
ValueError: [TypeError('cannot convert dictionary update sequence element #0 to a sequence'), TypeError('vars() argument must have __dict__ attribute')]
Add this line before returning the results
results = list(map(lambda x:x._mapping,results))
return(results)
This works for me, it is a version conflict issue.
Thanks, this worked for me too. I was stuck with this Error for last 20 min looking for solution .
thanks you very much!
Very helpful! Thank you
Truly incredible content. I'm currently a CS student and found this free course more helpful and practical than most of my classes. I really appreciate all the hard work Sanjeev and the team put into this; you guys are amazing!
i need help plz
Me too!
This course had everything that i needed in my first project as a developer. Thank you for everything Sanjeev Thiyagarajan. I hope I can become a developer like you someday and give back to the community.
This is such outstanding content. I'm sure if people give themselves enough time for these 19h, they can build a whole career on this course! Just brilliant and epic!
Hi, im python beginner, i know the basics of python included OOP and also the focus of my knowledge is Data Analytics. Is this course appropiate for my level? i know NOTHING about APIS
@@JesusSevillanoZamarreno-cu5hk yes! i am 7 hours in, and this course is probably equivalent to taking a backend development course in a coding bootcamp
If you don't know anything about APIs please do a quick RUclips course from any of the channels to get a basic understanding of REST apis.
Then if you know the basics of python, this should be good for your. @@JesusSevillanoZamarreno-cu5hk
@@JesusSevillanoZamarreno-cu5hk I think APIs are usually used in web deelopment in the where you might be required to integrate softwares like google maps and in this case API basically facilitates the interaction between the frontend and the backend. For Data analytics, you will be required to learn Machine learning models, statistics and a bit of data processing. Cheering for your journey in data analytics 👍.
@@pikapikachuchu808 you may need to know about APIs too in data science, to retrieve data from remote servers
I have never seen an educator who pays attention to such fine details and needs an explanation before. Thank you for a great course.
well i didnt understand the damn thing
are u a promoter
A List wasn't the best choice to store that type of data, a dictionary would have been more suitable where Mapping was done as so all that was necessary is `dict.get(id)` to see if the key exists, this would also be convenient to solve the dupe id issue
About 5 hours in your course and I just wanted to make a genuine comment on the quality of the teaching, concepts that I've struggled with for a long time are now easy to work with. Very much qualified to teach ANYTHING.
I must practice this twice. Thanks for your support. God bless you.
When defining the Vote schema, you can pass multiple condition to conint() to ensure it only allows 0 and 1 as option for dir
class Vote(BaseModel):
post_id: int
dir: conint(ge=0, le=1)
This works perfectly but you can as well create an enum instance to be able to present the exact accepted values:
from enum import IntEnum
class Choices(IntEnum):
remove = 0
add = 1
class Vote(BaseModel):
post_id: int
direction: Choices
Was looking for this lol, though I don't understand why he doesn't just use a boolean to do this, it makes more intuitive sense to represent a like by true and no like by false.
@Sanjeev Thiyagarajan, Thank you for making this class available to the open source community. This course is the best FastAPI course I have taken. For others, I took three weeks of regular evening study to complete all 19 hours, but my VSCode remote development environment was a major challenge - all fixed now. As stated previously by other people, your teaching is on the next level. I am still looking to find a place to send you a monetary token of appreciation.
Around 11:55:05 I spend so much time trying to fix an issue here, so hopefully my comment can help someone:
1 - Since we use Alembic, the tables are not created when we start our containers so after running docker-compose up -d, you need to go inside the container and manually run the command:
"docker exec -it bash"
" alembic upgrade head"
You should be able to create a user now.
2- If it says "database fastapi does not exist" whatever you had in the docker-compose file when your first ran it is probably still stored in there. Get rid of all volumes containers and ilages and restart:
"docker image rm "
"docker volume rm "
and then docker-compose up -d
and then step 1 and you'll be fine :D
Thanks for this course, at time 10:26:00 the reason that the code worked well is that the PostOut class inherited from BaseModel
Thank you for this comment. God bless you
The humongous amount of information with such lucidity and patience that has been conveyed is really unbelievable!
Kudos to Sanjeev!
where were you before?? ?? ????? So much knowledge in one video, I'm overloaded with excitement but I have to be calm down, things can get overwhelming easily. Massive thanks to you......... .. ......
A combination of diverse skills is required to successfully complete this project and tutorial. It's impressive!
At 4:23:50, the reason for putting a comma is because execute method requires a tuple. A single item such as id can be converted to tuple by putting a comma at the end. So, cursor.execute("SELECT * FROM posts WHERE id = %s", (id,)) would work as well.
Amazing content. Thanks a ton for providing such gems. Sanjeev, you are AWESOME.❤
Finally finished it. Amazing experience. So thorough. The style of trying and committing errors and correcting it on the fly by suggesting alternatives and making us part of his thinking process to fix the errors was very helpful. The only thing missing was if he could have added a basic UI for the social media post with a simple frontend(React.js ?) would have made this tutorial a full package. But hey it can be an assignment for me to try that part. Have been hearing this man's voice daily a little for over a month and now feels strange that I'll miss it.
do I need to have knowledge about DevOps to understand it? I'm asking since it has docker and related content .....
@@shashanksingh4708 Not required
My team is currently transitioning from Django to fast api, this course is a blessing
And I just got internship in django. I wish I could get django tutorials as good as this.
@@rheumaticharm9551 where did you got an django internship opportunity ? I need one too.
Why not django ninja ?
can you tell why you are switching? what the advantage of fastapi over django
@@khanhnam61 FastAPI and Django are different architecture ..
IMHO, Django is like a truck with a full container and FastAPI is like a truck with empty container so its perform better and you can customize..
But django-ninja come to close this gap..
4:21:49 I think the more appropriate fix is to use (id,) instead of (str(id)).
The error is there because it expects an object that supports indexing, so putting a comma after id would make it indexable.
Edit: Ok you mentioned about the comma later ... all good.
So not a random issue, it has a purpose. Nice!
To add some context to your comment, the indexing issue is because he is trying to pass a tuple with a single value. Tuples with a single value requires a comma after the value. With out the comma, python doesn't recognize it as a tuple, and that's creating the error. From the Psycopg docs: "For positional variables binding, the second argument must always be a sequence, even if it contains a single variable (remember that Python requires a comma to create a single element tuple):"
Apparently Psycopg is cool with using a list instead of tuple. IIRC, the SQLite3 module in Python requires that positional variables be a tuple.
Also, as you mentioned, all he needed to do was (id,). It's not necessary to convert the id to a string as psycopg handles converting whatever input it is given to a string. It's all in the docs here: www.psycopg.org/docs/usage.html#passing-parameters-to-sql-queries
@@Mark-zy7ki thanks
Yes, we need to use a tuple, and tuples do this weird thing that if you need one that only has 1 value, you must end it with a comma, i.e., my_tuple = (1,)
Thanks for the elaboration, your comment should be pinned to the top
If you are watching this after Jan 2023, and you install SQLAlchemy using the pip install command, it will install version 2.0.x or above by default. The code at the 10:25:00 hr marker where you get count is incompatible with the new version of SQLAlchemy.
I spent a few hours figuring out why my exact same code isn't working.
Use the following command to install (or re-install) to a compatible version of SQLAlchemy
pip install --force-reinstall -v "SQLAlchemy==1.4.46"
Also, your PostOut pydantic schema should derive from BaseModel, not Post or PostBase.
thank you so much
SQLAlchemy==1.4.46 has broken all my database connection and I couldn't fix it. So I came back to 1.40. I still have problem to present "results" as {"Post": {...}, "Votes":...} json. Read @luca-dallavalle solution below. Basically inherit PostOut from BaseModel not PostBase.
Thank you so much! you saved me😁
SERIOUSLY AMAZING VIDEO!!! You can literally become a senior developer just by watching and implementing it.
The 7 dislikes are from those instructors selling courses on Udemy
Those too can be got for free if u put in the hard work..
@@kithenry don't steal
@@allthecommonsense haha
ha ha
now 22
I was struggling for the first hour to set up those things. now, 4 hours and keep going.
my feeling: every word, and explanation is precise and easy to follow, I may not judge it's the best practice but this is actually the comprehensive way to get started to learn from 0. Many thanks to Sanjeev Thiyagarajan !!
Such A Great Course Thankyou sir, at 04:24:00 the error is because the second argument should be a tuple. So we have to use comma. Think it helps Others.
it doesn't expect a tuple, just an indexable object. an array [id] also works
Finally, the course is completed by me and I can't thank enough Sanjeev and FCC for such a quality content they have put out on Internet, this course is a blessing for people like me who want to learn development on their own. This is premium level package dished out in Python, I 100% recommend this to a person looking for a learning as a Python backend developer.
I don't know why but I am bit sad the course is over now...
Once again a huge thanks to Sanjeev and FCC!!!
How much time did it take you to finish the course?
Did you really code the course ? cause I got lots of problem with it. A lot of problem with post requests!!!!
@@LearnWithBahman For now I've reached 12:00:00. No problems with post requests.
@@BestProgrammer-c7e Got to 8 hours so far. it is great course with no problem
Before doing this course I had no idea about API and I was mostly learning about Machine Learning and I did this course and after a week got an interview for backend engineer (internship) and now i'm working as a software engineer at a tech compnay. Thank you so much for this.
Lol
This man is a hero.
This is pure charity ! Thank you so much for making the dev community great!
I normally don't bother with courses as i think it's faster to read a book on the topic, but this course is actually legendary. There were quite a few topics i didn't get even up to now that suddenly make a whole lot of sense in less than 30 mins. can 1000000% recommend
For those who're getting error in 9:38:00 ,
try to use Annotated with Fields instead of conint. It has been deprecated in pydantic 3.0
#Schema for vote
class Vote(BaseModel):
post_id :int
dir: Annotated[int, Field(ge=0, le=1)]
The amount of material covered in this video is amazing. I have spent over 30 hours watching and re-watching portions of the video while taking notes. Thank you for all the detailed explanations and examples.
This is amazing. Just two hours in and I have learned more than with other courses which were way longer. I can't believe this is free! Thank you so much ❤️
Estoy en el mismo camino! Estaba aprendiendo django pero luego de ver un poco lo completo que es este curso y lo que ofrece FastAPI decidí cambiarlo y comenzar este curso!
I only hope that by the time I finish this course, python won't be obsolete...
Lol...
Don't worry it would take time for sure to surpass something like Python.
Finally completed this 19 hour long course, it is my first time completing any course as I leave most of them half way.
This is possible because of great explanation given by excellent teacher.
Thank you Sanjeev
Thank you FCC.
🤗🤗
bhai qchq hai kya?
rohitansh, do you think there would be any problem in using the newer versions of the techstack.
at 10:24 .. i am getting error how you fixed it.. error was about json encoder
9:38:15 Annotated[int, Field(strict=True, le=1)]
Just completed this one. Oh man 19 hours!! Totally worth it , learnt a lot, would definately recommend for anyone whose thinking of starting this one. Everything is explained in detail and I'm sure you'll enjoy learning all the technologies that are used.
That’s insane course I’m really supporting your efforts in this, I wish one day i can support your community as you
This course is incredible. I respect what you've done. Thank you so much.
Went through the entire course. I learnt around 1000 different concepts in Python, ORMs, Database Migrations, Dockerising, Testing(Woah this was super complicated, even though Sanjeev made it as easy as possible), and the best part was pushing to production and docker hub at the end... All this in 36 hours.
how long did it take you to finish this
@@jasonharris35136 hours, lol
3:05:15 - to refresh the data output, click the execute script button (the 'play' button) to rerun the same query or press F5.
I did some digging in the psycopg2 implementation and I think I have an explanation that ties together what you're addressing at 4:21:33 and 4:23:36.
TLDR: Always use a 'sequence' like tuples, lists, and so on for the second parameter of cursor.execute(). For tuples with a single object, write '(object, )' instead of '(object)'.
Firstly, we should look at some signatures.
The execute method for cursor objects:
def execute(self, query: str | bytes | Composable, vars: _Vars = ...) -> None: ...
The _Vars type alias:
_Vars: TypeAlias = Sequence[Any] | Mapping[str, Any] | None
These explain what makes the 'convert to str' workaround tick. But as you've demonstrated before while writing the create_posts function, you can pass non-string values (e.g., bools in the case of post.published) just fine. So, why wasn't '(id)' working? I think this is because of the weird syntax of Python's tuples. '(id)' is not necessarily a tuple, and therefore not a sequence either. But '(id, )' is always a tuple in Python, and so it works just fine. But when you're forcing it to be a tuple with that extra comma, your previous workaround of converting to string becomes redundant. And because that workaround doesn't always work, I think it's safe to say that we should try not to write code that way. I hope this helped.
Just in case anyone was wondering why the id parameter for the cursor.execute method needed a comma at 4:24:11 , the psycopg2 library requires the parameters for the query to be provided as a sequence. adding a comma, passes the id as a single tuple
for the pytest section of the course: I can strongly recommend an extension for VS Code called Test Explorer UI. You can then run each individual test or bundle. Recommended.
Are there any other extensions you will suggest as well ?
The issue around 4:23:53 (and actually I also believe the issue around why it's not accepting an int) is because the cursor.execute() function expects a Tuple as the second argument. Without the comma the parenthesis are meaningless. cursor.execute("""SELECT * FROM posts WHERE id=%s""", (id,)) works just fine
Exactly. If you hadn't made this comment I would have.
Thank you very much!
Close, but not quite accurate. It's because it's expecting an indexable object. an int isn't indexable . A tuple is, so that works, so does an array [id] or even {id} as well as the tuple (id,)
@@jamesreader5955 Right. vars needs to be indexable, so (id,) or [id] is best. Converting id into a string only works when using a single digit id. If you try with id=10, then it would take the first index (which is '10'[0], so '1') for the first %s, but not know what to do with the second index (which is '10'[1] , so '0'). So you would get a TypeError, since not all arguments '1' and '0' would be able to be converted during string formatting.
6hrs into this video...absolutely loving it. Wanted to learn FastApi and I couldn't have learnt any better than this.
4:23:40 the execute method expects a sequence or mapping, and adding the comma declares the id as a tuple with one element, satisfying the type requirement. source: i paused the video and followed the stack trace to the docs for 20 min then resumed the video and you immediately solved the issue
Almost 12.000 likes and *zero* dislikes - more than deserved, thank you for this phantastic online course!
Because youtube had hidden the dislike button
Issue at 10:26:00
The issue seems to lie in inheriting from PostBase (or Post for that matter) from schemas. The issue is fixed when PostOut inherits from BaseModel instead.
As the response (without response model) returns a Post dictionary and a vote count, it does not have the fields that PostBase requires (title and content are present in the Post dictionary within the response, not within the response directly like vote count). PostBase (or Post) can be used if a new dictionary is defined that includes all the fields that PostBase (or Post) requires.
Also orm_mode need not be set in PostOut as it uses the class Post that has orm_mode set (this is used to import owner information and show it as a dictionary despite it being an object).
Also the fields defined in PostOut must match what the query returns (which can be seen by removing the response model), which is why the field 'Post' must have a capital P (as the model.py contains Post) and why the label for vote count in the query must be the same as the respective field defined in PostOut.
This comment was exactly what I was looking for!! I was re-reading the FastAPI pydantic and SQL Database docs and not getting the answer to why my code wasn't working. Now my code is working, I understand the capital P 'Post' and 'votes' labels better and finally need to look again at the inheritance docs to solidify my understanding there.
Thanks so much @Ammar
Got stucked at 11:59:12
I was unable to connect to the instance postgres dB created in Heroku after entering all dB credentials
Error message 👇
Unable to connect to sever: SSL error code 336151528
Will be glad to get help here
This course is just insane . Free code camp is just god level 🔥🔥🔥🔥🔥
This course is also free in his channel
I can't belive this is on youtube... This is basically a whole semester overview for me. I love it and I get to practice too... So grateful for this!
I don't know if anyone has answered this already or not, but at 4:23:47 where he talks about receiving an error for not including a comma is because in python single value tuples can only be created by including a comma after the singular value as we are passing a tuple in the second argument of execute command for singular values we need to include the comma for correct python syntax. Thanks for this amazing tutorial.
Bro just created an ultimate backend development course in the name of "Python API Development"
I finally finished this after almost two months Alhamdulillah... It was a long and enjoyable process for me but sometimes it was very challenging. I did all the things inside the course except a few parts in the testing section. I think I learned a looooot. I have to review some of the previous sections. Thank you, Mr. Sanjeev!
i appreciate you guys putting so much effort into videos like this.
Well, I did it. Just finished the course and I'm glad I did.
I came to learn FastAPI, and that section was straight forward along with the official documentation, which is fine, but where this course really shines is by introducing you to all the other technologies alongside it.
If you don't know anything about CI/CD, testing, or deployment, then I recommend sticking it through.
Thanks.
Project building based teaching method should be the teaching standard Fabulous tutorial succeeded to understand the Python apps concept despite being a totally newbie
Thank you!
This is one of the best tutorials I found for beginners to understand APIs from scratch, really like how you explain the JWT part, it makes thing so clear and easy to understand. Really appreciate your hard work hope to see your tutorial more so we all can learn more x)
have you completed the entire course? how is the course
@@akshayrr3061 haven't, I'm now at 7:28:00, and alr learnt lot of stuff like how to make a simple API, how to play with the API without a frontend and what is ORM, also he taught about the JWT stuff which is very interesting as well like how simple Web application can applied token based sign on and many more and I will continue watching it ltr on, it's really beginner friendly, if you have only learnt about basic programming and have 0 knowledge on things like Flask-mega, fast api, rest api, databases, sql, this is the right videos. As the timestamp mentioned at the description, I believe we can learn more about how deployment works how to make unit testing and etc, this is definitely worth the time. And what's more even better is, he will always show some error intended or accidentally, and will show the solution to it which is a good way for beginners to learn how a experienced programmer figure out and solved the problem 10/10
Ps: I have learnt about flask mega before through the "Microblog" tutorials, and it is very hard for me as the tutor are teaching in a way that I'm not a beginner (I was really new to Web applications that time), so I highly recommend this if u are a fresh beginner like me that time
Sorry for the long words, hope this will help you.
This course was very helpful!
I'm not a programmer but have spent the last 4 months teaching myself Python and SQL. I need to develop the phone app for me and subscribers to access my program remotely but had no clue where to start. This course has definitely helped me understand the next steps I need to take. Thank you so much!
All the best 🥳. How's it going ?
At 9:38:00 If you just want two values, you can use a custom validator
class Vote(BaseModel):
post_id:int
direction:int
@validator('direction')
def direction0or1(cls, d):
if (d == 0) or (d == 1):
return d
else:
raise ValueError('Integer must be 0 or 1')
This is a custom validator and it'll ensure if the given integer is only 0 or 1
from typing import Literal
direction: Literal[0, 1]
@@verevkin_a Thanks! I was looking for somthing simple that wouldn't have me creating a new function.
4:23:49 - what causes the issue, is that in python in order to declare a tuple it has to have at least one comma inside the parenthesis, otherwise it would be considered a simple variable as if there were no parenthesis. that's why you ran into this issue at first place. and you don't have to convert the argument into a string.
to fix the issue just write it like this: (id,)
or you can use named parameters
cursor.execute("SELECT * FROM posts WHERE id = %(id)s", ('id' = id))
09:38:05 for the vote model and new pydantic updates, it can be done in the following way,
make sure to import these:
from typing import Annotated
from pydantic import Field
class Vote(BaseModel):
post_id: int
dir: Annotated[int, Field(ge=0, le=1)]
According to pydantic, conint returns a new type which cause issues with static type checkers, while, Annotated allows to add metadata (like constraints) to existing types, thus making it more type-safe and clear.
Field(ge=0, le=1): this specifies that dir must be greater than or equal to 0 (inclusive), and less than or equal to 1 (inclusive).
Cheers
This is the most useful tutorial I've watched in a long while, 11 hours so far :)
I still can't understand, there are people like him who are doing this for free! You are contributing to this community, I hope one day I'll be in a position like you who can contribute like you! Thank you so much, next goal is to complete this video in a week!
same man... he could have easily chose the "buy my course because i know your company will pay for it" sector, but instead chose to give public access. The world is truly filled with kind and genuine people!
You guys are the real legends, hats off🍾
Best course I have ever seen, totally teach me most of the development knowledges.
This is a goldmine of knowledge. I learned a lot of new concepts. I can't thank Sajeev enough for doing a fantastic job of explaining everything. And thank you, FCC, for this video.
This is amazing, Sanjeev is really engaging and love his humour, the course is outstanding.
Great course, lots of valuable info. Also appreciate keeping things like 3:31:49 in, the random things that happen to everyone we don't always get. Here, for those wondering, he highlighted some text before running the query, that's why he got the syntax error, as it was only running the highlighted part.
I swear I looked for this exact topic not 6 hours ago. Thanks so much!
4:24:10 The execute() function expects some sequence type and this comma indicates that this is a tuple not just a string and it's better to put it there so you will not run into some unexpected behaviours later on (e.g. the code will run on some machines and on some it won't)
One of the best FastAPI course I've seen so far. Definitely recommend.
I love how this course isn't just about teaching us new skills, but also about how to go about teaching ourselves.
At 4:24:00 you wonder why you need the extra comma this is because the second argument has to be a sequence (iterable) . A quirk of python is that (id) is not a tuple. To create a tuple you have to do (id,) else it sees it as an int. Interesting thing is, because it expects an iterable you can use a list like this ("""SELECT * FROM posts WHERE id=%s""", [id]).fetchone().
And also this ("""INSERT INTO posts (title, content, published) VALUES (%s, %s, %s) RETURNING *""", [post.title, post.content, post.published])
This is a truly wonderful course. I actually completed this course a few months back and learnt so much! I am back again to revise everything I learned and to brush up on some difficult concepts. I have even recommended this course to my colleagues who were making a transition from front-end development to full stack. Great work, keep it going, and thank you so much for the hard work :)
This video is worth of my four year engineering fee... This man 👽got all my respect... He is an alien
Amazing course! Thanks a lot
10:25:00 issue was in inheritance from PostBase instead of BaseModel. Not in capital or lower letter. Hope will help someone
you are a god
Thanks it help me alot
You are the BEST. I spent almost an hour trying to figure it out until reading your comment. :(
Thank you, Thank you, Thank you.
thanks a lot
I tried to extend BaseModel instead of PostBase. It solved the content and the title issue but the votes part still giving me error. ( value_error.missing). ı tried to make votes an optional parameter. it worked but ı dont want it to be optional. Any ideas? My schemas are like the below:
class PostOut(BaseModel):
Post: Post
votes: int
class Config:
orm_mode = True