@@ -703,94 +703,18 @@ environment?
703
703
Ah, we forgot that we need to install Django.
704
704
705
705
706
- === Virtualenv and requirements.txt
707
-
708
- // TODO: move to next chapter
706
+ === Installing Django into our Virtualenv
709
707
710
708
Just like on our own machine,
711
709
a virtualenv is useful in a deployed environment to make
712
710
sure we have full control over the packages installed for a particular
713
711
project.
714
712
715
- To reproduce our local virtualenv,
716
- rather than just manually pip installing things
717
- one by one, and having to remember to sync things
718
- between local dev and docker,
719
- we can "save" the list of packages we're using
720
- by creating a 'requirements.txt' file.footnote:[
721
- There are many other dependency management tools these days
722
- so requirements.txt is not the only way to do it,
723
- although it is one of the oldest and best established.
724
- As you continue your Python adventures
725
- I'm sure you'll come across many others.]
726
-
727
-
728
- [subs="specialcharacters,quotes"]
729
- ----
730
- $ *pip freeze*
731
- asgiref==3.7.2
732
- attrs==23.1.0
733
- certifi==2023.7.22
734
- Django==4.2.7
735
- h11==0.14.0
736
- idna==3.4
737
- outcome==1.3.0.post0
738
- PySocks==1.7.1
739
- selenium==4.15.2
740
- sniffio==1.3.0
741
- sortedcontainers==2.4.0
742
- sqlparse==0.4.4
743
- trio==0.23.1
744
- trio-websocket==0.11.1
745
- urllib3==2.1.0
746
- wsproto==1.2.0
747
- ----
748
-
749
- That shows _all_ the packages in our virtualenv. Let's find Django,
750
- and then add it as a single item to our requirements.txt,
751
- with its exact version specified:
752
-
753
-
754
- //004
755
- [subs="specialcharacters,quotes"]
756
- ----
757
- $ *pip freeze | grep -i django*
758
- Django==4.2.7
759
- $ *pip freeze | grep -i django== >> requirements.txt*
760
- # that's a good first cut, let's commit it:
761
- $ *git add requirements.txt*
762
- $ *git commit -m "Add requirements.txt for virtualenv"*
763
- ----
764
-
765
- You may be wondering why we didn't add our other dependency,
766
- Selenium, to our requirements,
767
- or why we didn't just add _all_ the dependencies,
768
- including the "transitive" ones (eg, Django has its own dependencies of `asgiref` and `sqlparse`).
769
-
770
- As always, I have to gloss over some nuance and tradeoffs,
771
- but the short answer is first, Selenium is only a dependency for the tests,
772
- not the application code;
773
- we're never going to run the tests directly on our production servers.
774
- As to transitive dependencies, they're fiddly to manage without bringing
775
- in more tools, and I didn't want to do that for this book.footnote:[
776
- When you have a moment, you might want to do some further reading
777
- on "lockfiles", pyproject.toml, hard pinning vs soft pining,
778
- and immediate vs transitive dependencies. If I absolutely _had_
779
- to recommend a python dependency management tool,
780
- it would be https://github.com/jazzband/pip-tools[pip-tools],
781
- which is a fairly minimal one.]
782
-
783
-
784
- TIP: Itamar Turner-Traurig has a great guide to
785
- https://pythonspeed.com/docker/[Docker Packaging for Python Developers],
786
- which I cannot recommend highly enough. Read that before you're too much older.
787
-
788
- In any case, back in our Dockerfile, we can create a virtualenv
713
+ We can create a virtualenv in our Dockerfile
789
714
just like we did on our own machine with `python -m venv`,
790
- and then we can use the special `-r` flag for `pip install`,
791
- to point it at our requirements file:
715
+ and then we can use `pip install` to get Django:
792
716
793
- .Dockerfile (ch09l005 )
717
+ .Dockerfile (ch09l004 )
794
718
====
795
719
[source,dockerfile]
796
720
----
@@ -799,8 +723,7 @@ FROM python:slim
799
723
RUN python -m venv /venv <1>
800
724
ENV PATH="/venv/bin:$PATH" <2>
801
725
802
- COPY requirements.txt requirements.txt <3>
803
- RUN pip install -r requirements.txt <4>
726
+ RUN pip install "django<5" <3>
804
727
805
728
COPY src /src
806
729
@@ -817,17 +740,8 @@ CMD python manage.py runserver
817
740
of `pip` and `python` become the default ones
818
741
(this is actually one of the things that `activate` does, under the hood).
819
742
820
- <3> We copy our requirements file in, just like the src folder.
821
-
822
- <4> Now we install our dependencies with `pip`,
823
- pointing it at our _requirements.txt_.
824
- Notice the `-r`.
743
+ <3> We install Django with `pip install`, just like we do locally.
825
744
826
- TIP: Forgetting the `-r` and running `pip install requirements.txt`
827
- is such a common error, that I recommend you do it _right now_
828
- and get familiar with the error message
829
- (which is thankfully much more helpful than it used to be).
830
- It's a mistake I still make, _all the time_.
831
745
832
746
833
747
==== Successful Run
@@ -846,14 +760,13 @@ $ *docker build -t superlists . && docker run -it superlists*
846
760
=> [internal] load build definition from Dockerfile 0.0s
847
761
=> => transferring dockerfile: 246B 0.0s
848
762
=> [internal] load metadata for docker.io/library/python:slim 0.0s
849
- => CACHED [1/6 ] FROM docker.io/library/python:slim 0.0s
763
+ => CACHED [1/5 ] FROM docker.io/library/python:slim 0.0s
850
764
=> [internal] load build context 0.0s
851
765
=> => transferring context: 4.75kB 0.0s
852
- => [2/6] RUN python -m venv /venv 0.0s
853
- => [3/6] COPY requirements.txt requirements.txt 0.0s
854
- => [4/6] RUN pip install -r requirements.txt 0.0s
855
- => [5/6] COPY src /src 0.0s
856
- => [6/6] WORKDIR /src 0.0s
766
+ => [2/5] RUN python -m venv /venv 0.0s
767
+ => [3/5] pip install "django<5" 0.0s
768
+ => [4/5] COPY src /src 0.0s
769
+ => [5/5] WORKDIR /src 0.0s
857
770
=> exporting to image 0.0s
858
771
=> => exporting layers 0.0s
859
772
=> => writing image sha256:[...] 0.0s
@@ -959,7 +872,7 @@ that we specified in the `TEST_SERVER` env var.
959
872
Let's fix that by amending the `CMD` instruction in the Dockerfile:
960
873
961
874
962
- .Dockerfile (ch09l006 )
875
+ .Dockerfile (ch09l005 )
963
876
====
964
877
[source,dockerfile]
965
878
----
@@ -1393,11 +1306,9 @@ CMD python manage.py runserver
1393
1306
----
1394
1307
====
1395
1308
1396
- The extra flag to add is `--mount`,
1397
- where we specify `type=bind`, the `source` path on our machine,
1398
- and the `target` path _inside_ the container:
1309
+ Let's start by re-creating the database with `migrate`
1310
+ (when we moved everything into `./src`, we left the database file behind):
1399
1311
1400
- [role="small-code"]
1401
1312
[subs="specialcharacters,quotes"]
1402
1313
----
1403
1314
$ *./src/manage.py migrate --noinput*
@@ -1407,20 +1318,33 @@ Running migrations:
1407
1318
Applying contenttypes.0001_initial... OK
1408
1319
[...]
1409
1320
Applying sessions.0001_initial... OK
1321
+ ----
1322
+
1323
+ Let's make sure to .gitignore the new location of the DB file:
1324
+
1325
+ [subs="specialcharacters,quotes"]
1326
+ ----
1327
+ $ *echo src/db.sqlite3 >> .gitignore*
1328
+ ----
1329
+
1330
+ Now let's try mounting our database file.
1331
+ The extra flag to add to the Docker run command is `--mount`,
1332
+ where we specify `type=bind`, the `source` path on our machine,
1333
+ and the `target` path _inside_ the container:
1334
+
1335
+ [subs="specialcharacters,quotes"]
1336
+ ----
1410
1337
$ *docker build -t superlists . && docker run \
1411
1338
-p 8888:8888 \
1412
1339
--mount type=bind,source=./src/db.sqlite3,target=/src/db.sqlite3 \
1413
1340
-it superlists*
1414
1341
----
1415
1342
1416
- // TODO: db.sqlite3 will actually be missing at this point because we did *not* mv it earlier
1417
-
1418
1343
TIP: The old syntax for mounts was `-v`.
1419
1344
One of the advantages of the new `--mount` syntax is that it will fail hard
1420
1345
if the path you're trying to mount into the container does not exist
1421
1346
(it says something like `bind source path does not exist`)
1422
- This avoids a lot of pain, ask me how I now this.
1423
-
1347
+ This avoids a lot of pain, ask me how I know this.
1424
1348
1425
1349
1426
1350
And we check the FTs again.
0 commit comments