From f84c148e56431643d47868a7d5f8022784e8a0da Mon Sep 17 00:00:00 2001 From: Patrick Arminio Date: Mon, 1 Jul 2024 16:00:35 +0200 Subject: [PATCH 01/13] Add initial documentation for using the Django ORM --- docs/en/docs/advanced/django-orm.md | 99 +++++++++++++++++++++++++++++ docs/en/mkdocs.yml | 1 + 2 files changed, 100 insertions(+) create mode 100644 docs/en/docs/advanced/django-orm.md diff --git a/docs/en/docs/advanced/django-orm.md b/docs/en/docs/advanced/django-orm.md new file mode 100644 index 000000000..0ced1e611 --- /dev/null +++ b/docs/en/docs/advanced/django-orm.md @@ -0,0 +1,99 @@ +# Using the Django ORM with FastAPI + +In this guide we'll show you how to use Django's ORM with FastAPI. + +This can be extremely useful when migrating from Django to FastAPI, as you can reuse your existing Django models and queries. It's also a great way to take advantage of Django's powerful ORM while using FastAPI's modern features. + +This tutorial is based on the Django polls tutorial, but you can apply the same concepts to any Django project. + +## Prerequisites + +- A Django project like the one created from the [Django polls tutorial](https://docs.djangoproject.com/en/stable/intro/tutorial01/) +- Basic knowledge of FastAPI + +## Step 1: Install FastAPI + +First, let's install FastAPI in our Django project: + +```bash +# make sure to run this in your Django virtual environment +pip install fastapi +``` + +## Step 2: Set up a basic FastAPI application + +Create a `main.py` file: + +```python +from fastapi import FastAPI + +app = FastAPI() +``` + +In the next steps we'll import the `Question` model from Django, and create a FastAPI endpoint to list all questions. + +## Step 3: Import Django models + +In your `main.py` file, let's import the `Question` model: + +```python +from polls.models import Question +``` + +Make sure to replace `polls` with the name of your Django app. + +## Step 4: Create a FastAPI endpoint + +Now let's create a FastAPI endpoint to list all questions: + +```python +@app.get("/questions") +def get_questions(): + questions = Question.objects.all() + + return [{"question": question.question_text} for question in questions] +``` + +## Step 5: Run the FastAPI application + +No we can run the FastAPI application: + +```bash +fastapi dev main.py +``` + +If you go to `http://localhost:8000/questions` we should see the list of questions, right? 🤔 + +Unfortunately, we'll get an error: + +```text +django.core.exceptions.ImproperlyConfigured: Requested setting INSTALLED_APPS, but settings are not configured. You must either define the environment variable DJANGO_SETTINGS_MODULE or call settings.configure() before accessing settings. +``` + +This error happens because Django settings are not configured before importing the Django models. + +## Step 6: Configure Django settings + +To fix this error, we need to configure Django settings before importing the Django models. + +In the `main.py` add the following code **before** importing the Django models: + +```python +import os +import django + +os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mysite.settings") +django.setup() +``` + +This will configure Django settings before importing the Django models. + +## Step 7: Run the FastAPI application + +Now you can run the FastAPI application: + +```bash +fastapi dev main.py +``` + +And now if we go to `http://localhost:8000/questions` we should see a list of questions! 🎉 diff --git a/docs/en/mkdocs.yml b/docs/en/mkdocs.yml index 05dffb706..55e3efd8a 100644 --- a/docs/en/mkdocs.yml +++ b/docs/en/mkdocs.yml @@ -151,6 +151,7 @@ nav: - advanced/security/http-basic-auth.md - advanced/using-request-directly.md - advanced/dataclasses.md + - advanced/django-orm.md - advanced/middleware.md - advanced/sub-applications.md - advanced/behind-a-proxy.md From 88ba1f24c8754cd9a44d3057ecf77ebf3de12920 Mon Sep 17 00:00:00 2001 From: Patrick Arminio Date: Mon, 1 Jul 2024 17:19:35 +0200 Subject: [PATCH 02/13] Add async example --- docs/en/docs/advanced/django-orm.md | 30 +++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/docs/en/docs/advanced/django-orm.md b/docs/en/docs/advanced/django-orm.md index 0ced1e611..c6713b0ca 100644 --- a/docs/en/docs/advanced/django-orm.md +++ b/docs/en/docs/advanced/django-orm.md @@ -67,7 +67,8 @@ If you go to `http://localhost:8000/questions` we should see the list of questio Unfortunately, we'll get an error: ```text -django.core.exceptions.ImproperlyConfigured: Requested setting INSTALLED_APPS, but settings are not configured. You must either define the environment variable DJANGO_SETTINGS_MODULE or call settings.configure() before accessing settings. +django.core.exceptions.ImproperlyConfigured: Requested setting INSTALLED_APPS, but settings are not configured. +You must either define the environment variable DJANGO_SETTINGS_MODULE or call settings.configure() before accessing settings. ``` This error happens because Django settings are not configured before importing the Django models. @@ -88,7 +89,7 @@ django.setup() This will configure Django settings before importing the Django models. -## Step 7: Run the FastAPI application +## Step 7: Run the FastAPI application (again) Now you can run the FastAPI application: @@ -97,3 +98,28 @@ fastapi dev main.py ``` And now if we go to `http://localhost:8000/questions` we should see a list of questions! 🎉 + +## Using the ORM in async routes + +Django's support for async is currently limited, if you need to do run any query in an async route (or function), +you need to either use the async equivalent of the query or use `sync_to_async` from `asgiref.sync` to run the query: + +```python +from asgiref.sync import sync_to_async + +@app.get("/questions") +async def get_questions(): + def _fetch_questions(): + return list(Question.objects.all()) + + questions = await sync_to_async(_fetch_questions)() + + return [{"question": question.question_text} for question in questions] + + +@app.get("/questions/{question_id}") +async def get_question(question_id: int): + question = await Question.objects.filter(id=question_id).afirst() + + return {"question": question.question_text} +``` From a9465600af7af5e4c9232eaec6c40e166d0a9d37 Mon Sep 17 00:00:00 2001 From: Patrick Arminio Date: Wed, 3 Jul 2024 12:10:09 +0200 Subject: [PATCH 03/13] Add tests --- docs/en/docs/advanced/django-orm.md | 88 ++++++------------- docs_src/django_orm/mysite/__init__.py | 0 docs_src/django_orm/mysite/settings.py | 10 +++ docs_src/django_orm/mysite/urls.py | 1 + docs_src/django_orm/polls/__init__.py | 0 .../polls/migrations/0001_initial.py | 36 ++++++++ .../django_orm/polls/migrations/__init__.py | 0 docs_src/django_orm/polls/models.py | 29 ++++++ docs_src/django_orm/tutorial001.py | 37 ++++++++ .../test_tutorial/test_django_orm/__init__.py | 0 .../test_django_orm/test_tutorial001.py | 42 +++++++++ 11 files changed, 182 insertions(+), 61 deletions(-) create mode 100644 docs_src/django_orm/mysite/__init__.py create mode 100644 docs_src/django_orm/mysite/settings.py create mode 100644 docs_src/django_orm/mysite/urls.py create mode 100644 docs_src/django_orm/polls/__init__.py create mode 100644 docs_src/django_orm/polls/migrations/0001_initial.py create mode 100644 docs_src/django_orm/polls/migrations/__init__.py create mode 100644 docs_src/django_orm/polls/models.py create mode 100644 docs_src/django_orm/tutorial001.py create mode 100644 tests/test_tutorial/test_django_orm/__init__.py create mode 100644 tests/test_tutorial/test_django_orm/test_tutorial001.py diff --git a/docs/en/docs/advanced/django-orm.md b/docs/en/docs/advanced/django-orm.md index c6713b0ca..9c14e04cd 100644 --- a/docs/en/docs/advanced/django-orm.md +++ b/docs/en/docs/advanced/django-orm.md @@ -22,41 +22,29 @@ pip install fastapi ## Step 2: Set up a basic FastAPI application -Create a `main.py` file: +Let's create a basic FastAPI application in a new file called `main.py`: -```python -from fastapi import FastAPI +=== "Python 3.8+" -app = FastAPI() -``` + ```Python + {!> ../../../docs_src/django_orm/tutorial001.py[ln:5,13]!} + ``` In the next steps we'll import the `Question` model from Django, and create a FastAPI endpoint to list all questions. -## Step 3: Import Django models - -In your `main.py` file, let's import the `Question` model: - -```python -from polls.models import Question -``` - -Make sure to replace `polls` with the name of your Django app. +## Step 3: Import and use Django models -## Step 4: Create a FastAPI endpoint +In your `main.py` file, let's import the `Question` model and create a FastAPI endpoint to list all questions: -Now let's create a FastAPI endpoint to list all questions: +=== "Python 3.8+" -```python -@app.get("/questions") -def get_questions(): - questions = Question.objects.all() + ```Python + {!> ../../../docs_src/django_orm/tutorial001.py[ln:10,16-20]!} + ``` - return [{"question": question.question_text} for question in questions] -``` - -## Step 5: Run the FastAPI application +## Step 4: Run the FastAPI application -No we can run the FastAPI application: +Now, let's run the FastAPI application: ```bash fastapi dev main.py @@ -64,62 +52,40 @@ fastapi dev main.py If you go to `http://localhost:8000/questions` we should see the list of questions, right? 🤔 -Unfortunately, we'll get an error: +Unfortunately, we'll get this error: ```text django.core.exceptions.ImproperlyConfigured: Requested setting INSTALLED_APPS, but settings are not configured. You must either define the environment variable DJANGO_SETTINGS_MODULE or call settings.configure() before accessing settings. ``` -This error happens because Django settings are not configured before importing the Django models. +This error happens because Django needs to be configured before importing the models. -## Step 6: Configure Django settings +## Step 5: Configure Django settings To fix this error, we need to configure Django settings before importing the Django models. In the `main.py` add the following code **before** importing the Django models: -```python -import os -import django +=== "Python 3.8+" -os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mysite.settings") -django.setup() -``` + ```Python + {!> ../../../docs_src/django_orm/tutorial001.py[ln:1,7-10]!} + ``` -This will configure Django settings before importing the Django models. +Now, if you run the FastAPI application again, you should see the list of questions at `http://localhost:8000/questions`! 🎉 -## Step 7: Run the FastAPI application (again) +## Conclusion -Now you can run the FastAPI application: - -```bash -fastapi dev main.py -``` - -And now if we go to `http://localhost:8000/questions` we should see a list of questions! 🎉 +In this guide, we learned how to use Django's ORM with FastAPI. This can be extremely useful when migrating from Django to FastAPI, as you can reuse your existing Django models and queries. ## Using the ORM in async routes Django's support for async is currently limited, if you need to do run any query in an async route (or function), you need to either use the async equivalent of the query or use `sync_to_async` from `asgiref.sync` to run the query: -```python -from asgiref.sync import sync_to_async - -@app.get("/questions") -async def get_questions(): - def _fetch_questions(): - return list(Question.objects.all()) - - questions = await sync_to_async(_fetch_questions)() +=== "Python 3.8+" - return [{"question": question.question_text} for question in questions] - - -@app.get("/questions/{question_id}") -async def get_question(question_id: int): - question = await Question.objects.filter(id=question_id).afirst() - - return {"question": question.question_text} -``` + ```Python + {!> ../../../docs_src/django_orm/tutorial001.py[ln:23-37]!} + ``` diff --git a/docs_src/django_orm/mysite/__init__.py b/docs_src/django_orm/mysite/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/docs_src/django_orm/mysite/settings.py b/docs_src/django_orm/mysite/settings.py new file mode 100644 index 000000000..fbaada55c --- /dev/null +++ b/docs_src/django_orm/mysite/settings.py @@ -0,0 +1,10 @@ +INSTALLED_APPS = ["polls"] + +ROOT_URLCONF = "mysite.urls" + +DATABASES = { + "default": { + "ENGINE": "django.db.backends.sqlite3", + "NAME": ":memory:", + }, +} diff --git a/docs_src/django_orm/mysite/urls.py b/docs_src/django_orm/mysite/urls.py new file mode 100644 index 000000000..637600f58 --- /dev/null +++ b/docs_src/django_orm/mysite/urls.py @@ -0,0 +1 @@ +urlpatterns = [] diff --git a/docs_src/django_orm/polls/__init__.py b/docs_src/django_orm/polls/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/docs_src/django_orm/polls/migrations/0001_initial.py b/docs_src/django_orm/polls/migrations/0001_initial.py new file mode 100644 index 000000000..9d6420237 --- /dev/null +++ b/docs_src/django_orm/polls/migrations/0001_initial.py @@ -0,0 +1,36 @@ +# Generated by Django 2.1 on 2018-08-08 21:45 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ] + + operations = [ + migrations.CreateModel( + name='Choice', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('choice_text', models.CharField(max_length=200)), + ('votes', models.IntegerField(default=0)), + ], + ), + migrations.CreateModel( + name='Question', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('question_text', models.CharField(max_length=200)), + ('pub_date', models.DateTimeField(verbose_name='date published')), + ], + ), + migrations.AddField( + model_name='choice', + name='question', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='polls.Question'), + ), + ] diff --git a/docs_src/django_orm/polls/migrations/__init__.py b/docs_src/django_orm/polls/migrations/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/docs_src/django_orm/polls/models.py b/docs_src/django_orm/polls/models.py new file mode 100644 index 000000000..70f5466a0 --- /dev/null +++ b/docs_src/django_orm/polls/models.py @@ -0,0 +1,29 @@ +import datetime + +from django.db import models +from django.utils import timezone + + +class Question(models.Model): + question_text = models.CharField(max_length=200) + pub_date = models.DateTimeField('date published') + + def __str__(self): + return self.question_text + + def was_published_recently(self): + now = timezone.now() + return now - datetime.timedelta(days=1) <= self.pub_date <= now + + was_published_recently.admin_order_field = 'pub_date' + was_published_recently.boolean = True + was_published_recently.short_description = 'Published recently?' + + +class Choice(models.Model): + question = models.ForeignKey(Question, on_delete=models.CASCADE) + choice_text = models.CharField(max_length=200) + votes = models.IntegerField(default=0) + + def __str__(self): + return self.choice_text diff --git a/docs_src/django_orm/tutorial001.py b/docs_src/django_orm/tutorial001.py new file mode 100644 index 000000000..be9ba6919 --- /dev/null +++ b/docs_src/django_orm/tutorial001.py @@ -0,0 +1,37 @@ +import os + +import django +from asgiref.sync import sync_to_async +from fastapi import FastAPI + +os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mysite.settings") +django.setup() + +from polls.models import Question # noqa: I001 + + +app = FastAPI() + + +@app.get("/questions") +def get_questions(): + questions = Question.objects.all() + + return [{"question": question.question_text} for question in questions] + + +@app.get("/questions-async") +async def get_questions_async(): + def _fetch_questions(): + return list(Question.objects.all()) + + questions = await sync_to_async(_fetch_questions)() + + return [{"question": question.question_text} for question in questions] + + +@app.get("/questions/{question_id}") +async def get_question(question_id: int): + question = await Question.objects.filter(id=question_id).afirst() + + return {"question": question.question_text} diff --git a/tests/test_tutorial/test_django_orm/__init__.py b/tests/test_tutorial/test_django_orm/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests/test_tutorial/test_django_orm/test_tutorial001.py b/tests/test_tutorial/test_django_orm/test_tutorial001.py new file mode 100644 index 000000000..c9a6c1264 --- /dev/null +++ b/tests/test_tutorial/test_django_orm/test_tutorial001.py @@ -0,0 +1,42 @@ +import pytest +from django.core.management.color import no_style +from django.core.management.sql import sql_flush +from django.db import connection +from django.utils import timezone +from fastapi.testclient import TestClient + +from docs_src.django_orm.tutorial001 import Question, app + +client = TestClient(app) + + +@pytest.fixture(scope="session", autouse=True) +def django_db_setup(): + connection.creation.create_test_db(verbosity=0, autoclobber=True) + + yield + + connection.creation.destroy_test_db("default", verbosity=0) + + +@pytest.fixture(autouse=True) +def flush_db(): + sql_list = sql_flush(no_style(), connection, allow_cascade=False) + + connection.ops.execute_sql_flush(sql_list) + + +def test_get_questions(): + Question.objects.create(question_text="there goes my hero", pub_date=timezone.now()) + + response = client.get("/questions") + + assert response.status_code == 200, response.text + assert response.json() == [{"question": "there goes my hero"}] + + +def test_question_empty(): + response = client.get("/questions") + + assert response.status_code == 200, response.text + assert response.json() == [] From bd01cb9750e4bdf3a99a823712b21f7f0adf2e2d Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 3 Jul 2024 10:10:25 +0000 Subject: [PATCH 04/13] =?UTF-8?q?=F0=9F=8E=A8=20[pre-commit.ci]=20Auto=20f?= =?UTF-8?q?ormat=20from=20pre-commit.com=20hooks?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../polls/migrations/0001_initial.py | 46 +++++++++++++------ docs_src/django_orm/polls/models.py | 8 ++-- 2 files changed, 35 insertions(+), 19 deletions(-) diff --git a/docs_src/django_orm/polls/migrations/0001_initial.py b/docs_src/django_orm/polls/migrations/0001_initial.py index 9d6420237..ee462a84f 100644 --- a/docs_src/django_orm/polls/migrations/0001_initial.py +++ b/docs_src/django_orm/polls/migrations/0001_initial.py @@ -1,36 +1,52 @@ # Generated by Django 2.1 on 2018-08-08 21:45 -from django.db import migrations, models import django.db.models.deletion +from django.db import migrations, models class Migration(migrations.Migration): - initial = True - dependencies = [ - ] + dependencies = [] operations = [ migrations.CreateModel( - name='Choice', + name="Choice", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('choice_text', models.CharField(max_length=200)), - ('votes', models.IntegerField(default=0)), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("choice_text", models.CharField(max_length=200)), + ("votes", models.IntegerField(default=0)), ], ), migrations.CreateModel( - name='Question', + name="Question", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('question_text', models.CharField(max_length=200)), - ('pub_date', models.DateTimeField(verbose_name='date published')), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("question_text", models.CharField(max_length=200)), + ("pub_date", models.DateTimeField(verbose_name="date published")), ], ), migrations.AddField( - model_name='choice', - name='question', - field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='polls.Question'), + model_name="choice", + name="question", + field=models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, to="polls.Question" + ), ), ] diff --git a/docs_src/django_orm/polls/models.py b/docs_src/django_orm/polls/models.py index 70f5466a0..a0639e46c 100644 --- a/docs_src/django_orm/polls/models.py +++ b/docs_src/django_orm/polls/models.py @@ -6,7 +6,7 @@ from django.utils import timezone class Question(models.Model): question_text = models.CharField(max_length=200) - pub_date = models.DateTimeField('date published') + pub_date = models.DateTimeField("date published") def __str__(self): return self.question_text @@ -14,10 +14,10 @@ class Question(models.Model): def was_published_recently(self): now = timezone.now() return now - datetime.timedelta(days=1) <= self.pub_date <= now - - was_published_recently.admin_order_field = 'pub_date' + + was_published_recently.admin_order_field = "pub_date" was_published_recently.boolean = True - was_published_recently.short_description = 'Published recently?' + was_published_recently.short_description = "Published recently?" class Choice(models.Model): From 640baab2cbb9bc3b6f6f3b0ba6b85c9fa3e64a65 Mon Sep 17 00:00:00 2001 From: Patrick Arminio Date: Wed, 3 Jul 2024 13:59:49 +0200 Subject: [PATCH 05/13] Fix/workaround path --- .../test_tutorial/test_django_orm/test_tutorial001.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/tests/test_tutorial/test_django_orm/test_tutorial001.py b/tests/test_tutorial/test_django_orm/test_tutorial001.py index c9a6c1264..477a6e9cc 100644 --- a/tests/test_tutorial/test_django_orm/test_tutorial001.py +++ b/tests/test_tutorial/test_django_orm/test_tutorial001.py @@ -1,3 +1,6 @@ +import pathlib +import sys + import pytest from django.core.management.color import no_style from django.core.management.sql import sql_flush @@ -5,7 +8,12 @@ from django.db import connection from django.utils import timezone from fastapi.testclient import TestClient -from docs_src.django_orm.tutorial001 import Question, app +HERE = pathlib.Path(__file__).parent + +sys.path.append(str(HERE.parents[2] / "docs_src" / "django_orm")) + +from docs_src.django_orm.tutorial001 import Question, app # noqa: I001 E402 + client = TestClient(app) From edca20569f27a943212b167fd2aac576dafc481e Mon Sep 17 00:00:00 2001 From: Patrick Arminio Date: Wed, 3 Jul 2024 17:01:32 +0200 Subject: [PATCH 06/13] Add missing requirement --- requirements-docs-tests.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/requirements-docs-tests.txt b/requirements-docs-tests.txt index b82df4933..205c979d2 100644 --- a/requirements-docs-tests.txt +++ b/requirements-docs-tests.txt @@ -1,2 +1,3 @@ # For mkdocstrings and tests httpx >=0.23.0,<0.25.0 +django From 63212e6780101c8adde4f3bf0cf35db3152f05da Mon Sep 17 00:00:00 2001 From: Patrick Arminio Date: Wed, 3 Jul 2024 17:11:51 +0200 Subject: [PATCH 07/13] Fix warning --- docs_src/django_orm/mysite/settings.py | 1 + 1 file changed, 1 insertion(+) diff --git a/docs_src/django_orm/mysite/settings.py b/docs_src/django_orm/mysite/settings.py index fbaada55c..6340bda19 100644 --- a/docs_src/django_orm/mysite/settings.py +++ b/docs_src/django_orm/mysite/settings.py @@ -1,6 +1,7 @@ INSTALLED_APPS = ["polls"] ROOT_URLCONF = "mysite.urls" +USE_TZ = False DATABASES = { "default": { From 3768b3c01e15ef475cf57a9e994274547ab9d9e3 Mon Sep 17 00:00:00 2001 From: Patrick Arminio Date: Wed, 3 Jul 2024 17:18:44 +0200 Subject: [PATCH 08/13] Fix lint --- docs_src/django_orm/tutorial001.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs_src/django_orm/tutorial001.py b/docs_src/django_orm/tutorial001.py index be9ba6919..c931a9273 100644 --- a/docs_src/django_orm/tutorial001.py +++ b/docs_src/django_orm/tutorial001.py @@ -7,7 +7,7 @@ from fastapi import FastAPI os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mysite.settings") django.setup() -from polls.models import Question # noqa: I001 +from polls.models import Question # noqa: I001 E402 app = FastAPI() From d259c133805054408e7602392c548184c661b7fc Mon Sep 17 00:00:00 2001 From: Patrick Arminio Date: Wed, 3 Jul 2024 17:24:32 +0200 Subject: [PATCH 09/13] Add missing tests --- .../test_django_orm/test_tutorial001.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/tests/test_tutorial/test_django_orm/test_tutorial001.py b/tests/test_tutorial/test_django_orm/test_tutorial001.py index 477a6e9cc..1a68a3e38 100644 --- a/tests/test_tutorial/test_django_orm/test_tutorial001.py +++ b/tests/test_tutorial/test_django_orm/test_tutorial001.py @@ -48,3 +48,21 @@ def test_question_empty(): assert response.status_code == 200, response.text assert response.json() == [] + + +def test_get_questions_async(): + Question.objects.create(question_text="everlong", pub_date=timezone.now()) + + response = client.get("/questions-async") + + assert response.status_code == 200, response.text + assert response.json() == [{"question": "everlong"}] + + +def test_get_single_question(): + question = Question.objects.create(question_text="my hero", pub_date=timezone.now()) + + response = client.get(f"/questions/{question.id}") + + assert response.status_code == 200, response.text + assert response.json() == {"question": "my hero"} From 6320f4ba771b88760bfaae9db5b2d963f1b75933 Mon Sep 17 00:00:00 2001 From: Patrick Arminio Date: Wed, 3 Jul 2024 17:28:56 +0200 Subject: [PATCH 10/13] Remove unused code --- docs_src/django_orm/polls/models.py | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/docs_src/django_orm/polls/models.py b/docs_src/django_orm/polls/models.py index a0639e46c..8ac23fabb 100644 --- a/docs_src/django_orm/polls/models.py +++ b/docs_src/django_orm/polls/models.py @@ -8,22 +8,9 @@ class Question(models.Model): question_text = models.CharField(max_length=200) pub_date = models.DateTimeField("date published") - def __str__(self): - return self.question_text - - def was_published_recently(self): - now = timezone.now() - return now - datetime.timedelta(days=1) <= self.pub_date <= now - - was_published_recently.admin_order_field = "pub_date" - was_published_recently.boolean = True - was_published_recently.short_description = "Published recently?" - class Choice(models.Model): question = models.ForeignKey(Question, on_delete=models.CASCADE) choice_text = models.CharField(max_length=200) votes = models.IntegerField(default=0) - def __str__(self): - return self.choice_text From 5e49b3f7ffe5142e2c6064c3813cf0f2868831c1 Mon Sep 17 00:00:00 2001 From: Patrick Arminio Date: Wed, 3 Jul 2024 17:29:52 +0200 Subject: [PATCH 11/13] Lint --- docs_src/django_orm/polls/models.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/docs_src/django_orm/polls/models.py b/docs_src/django_orm/polls/models.py index 8ac23fabb..380716f93 100644 --- a/docs_src/django_orm/polls/models.py +++ b/docs_src/django_orm/polls/models.py @@ -1,7 +1,4 @@ -import datetime - from django.db import models -from django.utils import timezone class Question(models.Model): @@ -13,4 +10,3 @@ class Choice(models.Model): question = models.ForeignKey(Question, on_delete=models.CASCADE) choice_text = models.CharField(max_length=200) votes = models.IntegerField(default=0) - From 0daa2a6413109056643e368c5868811cf48cba54 Mon Sep 17 00:00:00 2001 From: svlandeg Date: Wed, 28 Aug 2024 11:19:19 +0200 Subject: [PATCH 12/13] formatting of code sections --- docs/en/docs/advanced/django-orm.md | 32 ++++++++++++++--------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/docs/en/docs/advanced/django-orm.md b/docs/en/docs/advanced/django-orm.md index 9c14e04cd..1992874dc 100644 --- a/docs/en/docs/advanced/django-orm.md +++ b/docs/en/docs/advanced/django-orm.md @@ -24,11 +24,11 @@ pip install fastapi Let's create a basic FastAPI application in a new file called `main.py`: -=== "Python 3.8+" +//// tab | Python 3.8+ - ```Python - {!> ../../../docs_src/django_orm/tutorial001.py[ln:5,13]!} - ``` +```Python +{!> ../../../docs_src/django_orm/tutorial001.py[ln:5,13]!} +``` In the next steps we'll import the `Question` model from Django, and create a FastAPI endpoint to list all questions. @@ -36,11 +36,11 @@ In the next steps we'll import the `Question` model from Django, and create a Fa In your `main.py` file, let's import the `Question` model and create a FastAPI endpoint to list all questions: -=== "Python 3.8+" +//// tab | Python 3.8+ - ```Python - {!> ../../../docs_src/django_orm/tutorial001.py[ln:10,16-20]!} - ``` + ```Python +{!> ../../../docs_src/django_orm/tutorial001.py[ln:10,16-20]!} +``` ## Step 4: Run the FastAPI application @@ -67,11 +67,11 @@ To fix this error, we need to configure Django settings before importing the Dja In the `main.py` add the following code **before** importing the Django models: -=== "Python 3.8+" +//// tab | Python 3.8+ - ```Python - {!> ../../../docs_src/django_orm/tutorial001.py[ln:1,7-10]!} - ``` +```Python +{!> ../../../docs_src/django_orm/tutorial001.py[ln:1,7-10]!} +``` Now, if you run the FastAPI application again, you should see the list of questions at `http://localhost:8000/questions`! 🎉 @@ -84,8 +84,8 @@ In this guide, we learned how to use Django's ORM with FastAPI. This can be extr Django's support for async is currently limited, if you need to do run any query in an async route (or function), you need to either use the async equivalent of the query or use `sync_to_async` from `asgiref.sync` to run the query: -=== "Python 3.8+" +//// tab | Python 3.8+ - ```Python - {!> ../../../docs_src/django_orm/tutorial001.py[ln:23-37]!} - ``` +```Python +{!> ../../../docs_src/django_orm/tutorial001.py[ln:23-37]!} +``` From a41a1651c68d50a2f935a8c09dc7a91c069da868 Mon Sep 17 00:00:00 2001 From: svlandeg Date: Wed, 28 Aug 2024 11:25:15 +0200 Subject: [PATCH 13/13] fix typo --- docs/en/docs/advanced/django-orm.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/en/docs/advanced/django-orm.md b/docs/en/docs/advanced/django-orm.md index 1992874dc..ad6fb4014 100644 --- a/docs/en/docs/advanced/django-orm.md +++ b/docs/en/docs/advanced/django-orm.md @@ -38,7 +38,7 @@ In your `main.py` file, let's import the `Question` model and create a FastAPI e //// tab | Python 3.8+ - ```Python +```Python {!> ../../../docs_src/django_orm/tutorial001.py[ln:10,16-20]!} ```