Skip to content

Commit b754a45

Browse files
committed
chore: bump to 0.28.1 (fix utils.py)
1 parent 3929dd2 commit b754a45

23 files changed

Lines changed: 1228 additions & 2 deletions

docs/changelog.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
:description: falco release history
2+
3+
Changelog
4+
=========

docs/codeofconduct.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
Code of Conduct
2+
===============
3+
4+
.. include:: ../CODE_OF_CONDUCT.md
5+
:parser: myst_parser.sphinx_

docs/commands/copy_template.rst

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
copy_template
2+
=============
3+
4+
5+
.. exec_code::
6+
:language_output: shell
7+
8+
# --- hide: start ---
9+
from falco.management.commands.crud import Command
10+
11+
Command().print_help("manage.py", "copy_template")
12+
#hide:toggle

docs/commands/crud.rst

Lines changed: 186 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,186 @@
1+
:description: Faster prototyping with basic CRUD (Create, Read, Update, Delete) python views and HTML templates for your django models.
2+
3+
crud
4+
====
5+
6+
Accelerate prototyping with basic CRUD (Create, Read, Update, Delete) python views and HTML templates, enhanced with htmx and Tailwind CSS.
7+
8+
.. exec_code::
9+
:language_output: shell
10+
11+
# --- hide: start ---
12+
from falco.management.commands.crud import Command
13+
14+
Command().print_help("manage.py", "crud")
15+
#hide:toggle
16+
17+
This command generates htmx-powered create, read, update, and delete views for your model. It follows a similar idea
18+
as `neapolitan <https://github.com/carltongibson/neapolitan>`_, but with a completely different approach. Instead of inheriting
19+
from a class as you would with ``neapolitan``, this command generates basic ``views``, ``urls``, ``forms``, ``admin`` (thanks to `django-extensions <https://django-extensions.readthedocs.io/en/latest/admin_generator.html>`_)
20+
and HTML ``templates``, and updates or overrides the corresponding files in your project. I prefer this approach because, at the end, you'll have all the new code directly in front of you. It's easily
21+
accessible and you can update it as you see fit. The idea is to accelerate project prototyping. Write a model and you instantly have views ready for it.
22+
23+
24+
.. admonition:: Why function based views?
25+
:class: hint dropdown
26+
27+
I think class-based views get complex faster than function-based views. Both have their use cases, but function-based views
28+
stay simpler to manage longer in my experience. There is an excellent document on the topic, read `django views the right way <https://spookylukey.github.io/django-views-the-right-way/>`_.
29+
30+
.. If you want to see an example of the generated code, check out the `source code of the demo project <https://github.com/Tobi-De/falco/tree/main/demo/myjourney/entries>`_.
31+
32+
33+
Python code
34+
^^^^^^^^^^^
35+
36+
All Python code added by this command will be in **append** mode, meaning it won't override the content of your existing files.
37+
Instead, it will add code at the end or create the files if they are missing. The files that will be modified
38+
are ``forms.py``, ``urls.py``, ``admin.py`` (if you have `django-extension <https://django-extensions.readthedocs.io/en/latest/index.html>`_ installed),
39+
``views.py`` and your project root ``urls.py``.
40+
41+
For the sake brevity, I'll only show an example of what the ``urls.py`` file might look like for a model named ``Entry`` in a django app named ``entries``.
42+
43+
.. code-block:: bash
44+
45+
python -m myproject entry.entries
46+
47+
.. literalinclude:: /_static/snippets/urls.py
48+
49+
As you can see, the convention is quite simple: ``<model_name_lower>_<operation>``. Note that if you don't specify the model name and run
50+
``python -m myproject entries``, the same code with the described conventions will be generated for all the models in the ``entries`` app.
51+
52+
Now, if you're anything like me, the code above might have made you cringe due to the excessive repetitions of the word ``entry``.
53+
This wouldn't have been the case if the model was called ``Category``, for example. For these specific cases, there is an ``--entry-point`` option.
54+
55+
Let's try it.
56+
57+
.. code-block:: bash
58+
59+
python -m myproject entries.entry --entry-point
60+
61+
.. admonition:: Oops, I made a mistake
62+
:class: tip dropdown
63+
64+
If you made a mistake when running CRUD commands and want to discard the changes and restart, you can use the following commands instead of manually deleting all changes.
65+
Note that the commands below will discard all current changes. You can also specify a specific path to remove only a subset of the changes.
66+
67+
.. code-block:: shell
68+
69+
git checkout -- . # Remove changes in the working tree
70+
git clean -fd # Remove untracked files and directories from the working tree
71+
72+
.. code-block:: python
73+
:caption: entries/urls.py
74+
75+
from django.urls import path
76+
77+
from . import views
78+
79+
app_name = "entries"
80+
81+
urlpatterns = [
82+
path("", views.index, name="index"),
83+
path("create/", views.create, name="create"),
84+
path("<int:pk>/", views.detail, name="detail"),
85+
path("<int:pk>/update/", views.update, name="update"),
86+
path("<int:pk>/delete/", views.delete, name="delete"),
87+
]
88+
89+
Much cleaner, specifying that option means you consider the ``Entry`` model as the entry point of your ``entries`` app.
90+
So, instead of the base URL of the app looking like ``entries/entries/``, it will just be ``entries/``.
91+
92+
As previously mentioned, the command will also register your app in your project root URLs configuration. This occurs when
93+
you generate ``crud`` views for a model and there is no existing ``urls.py`` file for the app. In such cases, it is assumed
94+
that you haven't already registered the URLs for your app since the command just created the file.
95+
96+
Here is an example of how the ``entries`` app will be registered.
97+
98+
.. code-block:: python
99+
:caption: config/urls.py
100+
:linenos:
101+
:emphasize-lines: 4
102+
103+
urlpatterns = [
104+
path("admin/", admin.site.urls),
105+
...
106+
path("entries/", include("entries.urls", namespace="entries"))
107+
]
108+
109+
110+
111+
HTML templates
112+
^^^^^^^^^^^^^^
113+
114+
Unlike the Python code, the generated HTML templates will overwrite any existing ones. If you want to avoid this, you should commit
115+
your changes before running this command or use the ``--only-python`` option to generate only Python code. The files are generated
116+
with minimal styling (using Tailwind CSS) and are reasonably presentable.
117+
Four files are generated:
118+
119+
* ``<model_name_lower>_list.html``
120+
* ``<model_name_lower>_create.html``
121+
* ``<model_name_lower>_detail.html``
122+
* ``<model_name_lower>_update.html``
123+
124+
There is no ``<model_name_lower>_delete.html`` file because deletion is handled in the ``<model_name_lower>_list.html``.
125+
Each generated HTML file extends a ``base.html`` template. Therefore, make sure you have a top-level ``base.html`` file in
126+
your templates directory.
127+
128+
129+
.. note::
130+
131+
If you use the ``--entry-point`` option, the files will be named ``index.html``, ``create.html``, ``detail.html``, and ``update.html``.
132+
133+
To determine where to place the generated files, we check the ``DIRS`` key in the ``TEMPLATES`` settings of your Django project.
134+
If it is populated, we take the first value in the list and generate the template files in ``<templates_dir>/<app_label>``.
135+
If it is not populated, we use the classic Django layout, which is ``<app_label>/templates/<app_label>``.
136+
137+
.. If you want an overview of what the templates look like, check out the `demo project <https://github.com/Tobi-De/falco/tree/main/demo/templates/entries>`_.
138+
139+
Custom Templates
140+
****************
141+
142+
The ``crud`` command supports the ability to specify your own HTML templates using the ``--blueprints`` option.
143+
This option only takes into account HTML files and will completely override the default templates. The HTML templates
144+
use the `jinja2 <https://jinja.palletsprojects.com/en/3.1.x/>`_ syntax. To see examples of what the templates look like,
145+
check out the base templates `here <https://github.com/falcopackages/falco-cli/tree/main/src/falco_cli/templates/crud>`_.
146+
147+
.. Below is an example of the context each template will receive.
148+
149+
150+
.. .. jupyter-execute::
151+
.. :hide-code:
152+
153+
.. from falco_cli.management.commands.crud import DjangoModel
154+
.. from pprint import pprint
155+
156+
.. dj_model = DjangoModel(
157+
.. name = "Entry",
158+
.. name_plural = "Entries",
159+
.. verbose_name = "Entry",
160+
.. verbose_name_plural = "Entries",
161+
.. has_file_field = False,
162+
.. has_editable_date_field = False,
163+
.. fields = {
164+
.. "name": {"verbose_name": "Name", "editable": True, "class_name": "CharField", "accessor": "{{entry.name}}"},
165+
.. "price": {"verbose_name": "Price", "editable": True, "class_name": "DecimalField", "accessor": "{{entry.price}}"},
166+
.. }
167+
.. )
168+
169+
.. pprint(get_html_blueprint_context(app_label="entries", django_model=dj_model), sort_dicts=False, compact=True, width=120)
170+
171+
172+
Examples
173+
^^^^^^^^
174+
175+
Some usage examples.
176+
177+
.. code:: bash
178+
179+
$ python -m myproject entries.entry
180+
$ python -m myproject entries
181+
$ python -m myproject entries.entry -e="secret_field1" -e="secret_field2"
182+
$ python -m myproject entries.entry --only-html
183+
$ python -m myproject entries.entry --only-python
184+
$ python -m myproject entries.entry --entry-point
185+
$ python -m myproject entries.entry --entry-point --login
186+
$ python -m myproject entries.entry --blueprints /path/to/blueprints

docs/commands/htmx.rst

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
:description: A set of handy utilities for easily obtaining the htmx library and its extensions locally on your computer.
2+
3+
htmx
4+
====
5+
6+
.. exec_code::
7+
:language_output: shell
8+
9+
# --- hide: start ---
10+
from falco.management.commands.crud import Command
11+
12+
Command().print_help("manage.py", "htmx")
13+
#hide:toggle
14+
15+
Download the htmx javascript library. You won’t have to download htmx or its extensions often but at least if you need it, I think this
16+
is an easy way to get the file available locally.
17+
This command also utilizes your ``pyproject.toml`` file (if available) to store the path where the file was downloaded. This information is
18+
saved in the ``[tool.falco]`` section. The purpose of this is to streamline future downloads: if you attempt to download the htmx file again,
19+
it will recognize the existing path and update the existing file, eliminating the need for you to specify the path again.
20+
21+
Here is what this configuration looks like:
22+
23+
.. code-block:: toml
24+
25+
[tool.falco]
26+
htmx = "path/to/htmx.min.js:1.9.10"
27+
28+
The value is a string that specifies the path to the file along with the version htmx. The version specification is optional. If you wish to modify this configuration
29+
without mentioning the version, you can do so as follows:
30+
31+
.. code-block:: toml
32+
33+
[tool.falco]
34+
htmx = "path/to/htmx.min.js"
35+
36+
Upon subsequent download, the configuration file will be updated with the version of the file.
37+
38+

docs/commands/htmx_ext.rst

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
htmx_ext
2+
========
3+
4+
This command downloads an htmx extension. The list of extensions is pulled from `htmx-extensions.oluwatobi.dev <https://htmx-extensions.oluwatobi.dev/>`_. If you run
5+
the command without specifying any arguments, it will list all the available extensions instead.
6+
Similar to the `htmx` commands, this will also use your ``pyproject.toml`` file if it's found. However,
7+
it's solely for downloading the extensions file next to your ``htmx.min.js`` file, in case no path was specified in the command.
8+
9+
.. exec_code::
10+
:language_output: shell
11+
12+
# --- hide: start ---
13+
from falco.management.commands.crud import Command
14+
15+
Command().print_help("manage.py", "htmx_ext")
16+
#hide:toggle
17+
18+
**Example**
19+
20+
.. code-block:: bash
21+
22+
falco htmx-ext sse

docs/commands/index.rst

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
Commands
2+
========
3+
4+
.. toctree::
5+
:maxdepth: 2
6+
:hidden:
7+
8+
start_app
9+
crud
10+
copy_template
11+
list_templates
12+
reset_migrations
13+
rm_migrations
14+
htmx
15+
htmx_ext
16+
work

docs/commands/list_templates.rst

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
list_templates
2+
==============
3+
4+
5+
.. exec_code::
6+
:language_output: shell
7+
8+
# --- hide: start ---
9+
from falco.management.commands.crud import Command
10+
11+
Command().print_help("manage.py", "list_templates")
12+
#hide:toggle

docs/commands/reset_migrations.rst

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
:description: Learn how to manage your Django migrations with Falco.
2+
3+
reset_migrations
4+
================
5+
6+
.. exec_code::
7+
:language_output: shell
8+
9+
# --- hide: start ---
10+
from falco.management.commands.crud import Command
11+
12+
Command().print_help("manage.py", "reset_migrations")
13+
#hide:toggle
14+
15+
.. warning::
16+
Before running this command, make sure you have applied any pending migrations, ``makemigrations && migrate``. The idea is to reset the migrations while keeping the data. If your current database does not have up to date migrations, it will fail.
17+
18+
19+
This command works exactly like the ``rm_migration`` command but goes a bit further. Here's how it works:
20+
21+
1. First, it runs ``rm_migrations``.
22+
2. Then, it clears your django migrations table:
23+
24+
.. code-block:: python
25+
26+
from django.db import connection
27+
28+
with connection.cursor() as cursor:
29+
cursor.execute("DELETE FROM django_migrations")
30+
31+
3. Next, it runs ``python -m myproject makemigrations`` to recreate migrations.
32+
4. Lastly, it executes ``python -m myproject migrate --fake`` add the new migrations to the migrations table so that your migrations are in sync with the current database schema state.
33+
34+
The `migrate fake <https://docs.djangoproject.com/en/5.0/ref/django-admin/#cmdoption-migrate-fake>`_ command apply migrations without running
35+
the actual SQL.
36+
Since the ``reset_migrations`` depends on the ``rm_migrations`` command, it performs the same checks: it checks your Django ``DEBUG`` value and your Git
37+
repo needs to be in a clean state unless you use the ``--skip-git-check`` option.
38+
This command allows you to restore your migrations to their initial state without losing any existing data.

docs/commands/rm_migrations.rst

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
:description: Remove all migrations in all applications.
2+
3+
rm_migrations
4+
=============
5+
6+
.. exec_code::
7+
:language_output: shell
8+
9+
# --- hide: start ---
10+
from falco.management.commands.crud import Command
11+
12+
Command().print_help("manage.py", "rm_migrations")
13+
#hide:toggle
14+
15+
.. warning::
16+
This command will delete all your migrations files, be sure to commit your changes before running this command.
17+
18+
19+
It is a good idea to delete all migrations and recreate them from scratch when deploying your django project for the first time.
20+
This ensures a clean base without any remnants of testing or experimentation from the initial development phase. Even during development,
21+
when exploring new ideas, it is often necessary to delete all migrations and start over. This command is designed for these scenarios,
22+
as it deletes all migrations in your project.
23+
The command checks the debug value of your project using the ``manage.py`` file. If the debug value is set to ``False``, the command will fail.
24+
It takes an optional argument, ``apps_dir``, which specifies the directory containing your apps. If no argument is provided, it assumes that the apps
25+
directory has the same name as the current parent directory. For example, if your project is named ``my_awesome_project``, the command will assume that
26+
the apps directory is a subdirectory with the same name, i.e., ``my_awesome_project/my_awesome_project``. This is the default project layout created
27+
by the `falco startproject </the_cli/start_project.html>`_ command.
28+
29+
**Example**
30+
31+
.. code:: shell
32+
33+
falco rm-migrations
34+
# or
35+
falco rm-migrations my_apps_dir
36+
37+
After deleting all your migrations, your next step might likely be to reset your database using a command like ``reset-db``
38+
from `django-extensions <https://django-extensions.readthedocs.io/en/latest/>`_. However, if you want to preserve your data,
39+
then the following command might be a better option than running ``rm-migrations`` altogether.

0 commit comments

Comments
 (0)