From df2e02917a63a003edbabc231618fc54b7b6fd1e Mon Sep 17 00:00:00 2001 From: Willem Van Onsem Date: Mon, 14 Oct 2024 10:59:32 +0200 Subject: [PATCH 1/2] more code highlighting --- antipattern/fill-the-primary-key-gaps.md | 4 ++-- antipattern/filter-on-arbitrary-input-like-request-get.md | 2 +- antipattern/imports.md | 4 ++-- antipattern/manually-constructing-a-slug.md | 2 +- antipattern/non-atomic-jsonfield-s.md | 6 +++--- antipattern/passing-function-references-to-reverse.md | 2 +- antipattern/plural-model-class-names.md | 6 +++--- antipattern/run-makemigrations-in-production.md | 4 ++-- antipattern/signals.md | 4 ++-- ...ing-multiple-forms-on-the-same-page-without-prefixing.md | 2 +- pattern/dictionary-lookups-for-the-database.md | 4 ++-- .../match-multiple-strings-in-a-case-insensitive-manner.md | 4 ++-- pattern/querying-in-the-opposite-direction.md | 6 +++--- ...ues-to-a-created-updated-object-in-a-class-based-view.md | 4 ++-- 14 files changed, 27 insertions(+), 27 deletions(-) diff --git a/antipattern/fill-the-primary-key-gaps.md b/antipattern/fill-the-primary-key-gaps.md index 092a2ab..aa1b5db 100644 --- a/antipattern/fill-the-primary-key-gaps.md +++ b/antipattern/fill-the-primary-key-gaps.md @@ -13,7 +13,7 @@ A frequently asked question is how to "*fill the gaps*" in the primary key range It is understandable that people want to automatically reassign the primary keys of records that have been reassigned. Strictly speaking a database could easily do that, and since the database does not do that, we could run a query to automatically look for the "first" gap. Indeed, we can find the primary key we want with: -```python3 +```python # do not use this from django.db.models import Exists, F, OuterRef @@ -31,7 +31,7 @@ But a more severe problem is that now the URL `/article/2` no longer points to t But the most severe problem is that there can still be a lot of items referring to the old article, that now perhaps refer to the new article. Indeed, imagine that you have a [**`GenericForeignKey`** \[Django-doc\]](https://docs.djangoproject.com/en/stable/ref/contrib/contenttypes/#django.contrib.contenttypes.fields.GenericForeignKey), if there is no [**`GenericRelation`** \[Django-doc\]](https://docs.djangoproject.com/en/stable/ref/contrib/contenttypes/#django.contrib.contenttypes.fields.GenericRelation), it will *not* be triggered to remove the objects. Indeed, imagine that we have a `Tag` model with: -```python3 +```python class TaggedItem(models.Model): tag = models.SlugField() content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE) diff --git a/antipattern/filter-on-arbitrary-input-like-request-get.md b/antipattern/filter-on-arbitrary-input-like-request-get.md index 50ff938..84d9320 100644 --- a/antipattern/filter-on-arbitrary-input-like-request-get.md +++ b/antipattern/filter-on-arbitrary-input-like-request-get.md @@ -13,7 +13,7 @@ solinks: [] A "lazy" way to allow filtering on options is to pass `request.GET`, `request.POST`, `request.query_params` as named parameters to the filter clause. For example with: -```python3 +```python MyModel.objects.filter(**request.GET) ``` diff --git a/antipattern/imports.md b/antipattern/imports.md index d56e30e..32c43b8 100644 --- a/antipattern/imports.md +++ b/antipattern/imports.md @@ -13,7 +13,7 @@ solinks: [] Often it's necessary to import modules used in your code and often you see them imported as below: -```python3 +```python from projects.models import Project from django.views.generic import * @@ -33,7 +33,7 @@ Secondly, you are importing everything from `django.views.generic` using `*` whi The code above can be re-written thus: -```python3 +```python from django.views.generic import ListView from .models import Project diff --git a/antipattern/manually-constructing-a-slug.md b/antipattern/manually-constructing-a-slug.md index 190cb3d..1c88ca0 100644 --- a/antipattern/manually-constructing-a-slug.md +++ b/antipattern/manually-constructing-a-slug.md @@ -13,7 +13,7 @@ solinks: [] Sometimes, people construct slugs manually, for example in a view with: -```python3 +```python model_object.slug = model_object.title.replace(' ', '-') ``` diff --git a/antipattern/non-atomic-jsonfield-s.md b/antipattern/non-atomic-jsonfield-s.md index 6e15eb2..5d4014a 100644 --- a/antipattern/non-atomic-jsonfield-s.md +++ b/antipattern/non-atomic-jsonfield-s.md @@ -25,7 +25,7 @@ A final reason not to use JSON blobs is that validation of the structure of JSON If the field has a certain structure, convert that structure into models, and *linearize* data. Indeed, imagine that we have a model with: -```python3 +```python from django.conf import settings from django.db import models @@ -47,7 +47,7 @@ where `lines` for example look like: we can convert this to an extra model that has a `ForeignKey` to a `Product` and where we store the quantity, like: -```python3 +```python class Order(models.Model): customer = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.PROTECT) @@ -60,7 +60,7 @@ class OrderLine(models.Model): here we can efficiently filter for orders with a `product_id=14` in it with: -```python3 +```python Order.objects.filter(lines__product_id=14) ``` diff --git a/antipattern/passing-function-references-to-reverse.md b/antipattern/passing-function-references-to-reverse.md index 03ef0ef..c0dd20e 100644 --- a/antipattern/passing-function-references-to-reverse.md +++ b/antipattern/passing-function-references-to-reverse.md @@ -11,7 +11,7 @@ solinks: ['https://stackoverflow.com/questions/78035103/in-django-is-it-possible The [**reverse(…)** function \[Django-doc\]](https://docs.djangoproject.com/en/stable/ref/urlresolvers/#reverse) allows to pass the names of views as well as references to functions. Indeed, for example with: -```python3 +```python #app_name/urls.py from app_name.views import some_view diff --git a/antipattern/plural-model-class-names.md b/antipattern/plural-model-class-names.md index 96e1309..d29f968 100644 --- a/antipattern/plural-model-class-names.md +++ b/antipattern/plural-model-class-names.md @@ -10,7 +10,7 @@ solinks: [] Often people write model classes with a plural name. For example: -```python3 +```python from django.db import models class Cars(models.Model): @@ -39,7 +39,7 @@ and incorrect plural nouns. It also makes queries look grammatically incorrect English, for example, one queries with: -```python3 +```python Cars.objects.all() ``` @@ -53,7 +53,7 @@ well. For related models, this results in ugly looking names as well, for example one queries with: -```python3 +```python ford.cars_set.all() ``` diff --git a/antipattern/run-makemigrations-in-production.md b/antipattern/run-makemigrations-in-production.md index 433e3c8..a73f501 100644 --- a/antipattern/run-makemigrations-in-production.md +++ b/antipattern/run-makemigrations-in-production.md @@ -17,7 +17,7 @@ Occasionally people think it is a good idea to also run `makemigrations` in the Migrating the database is a *non-trivial problem*. There are multiple ways how you can migrate a database to get the model in sync with the database. Indeed, imagine that you have a model: -```python3 +```python from django.db import models @@ -27,7 +27,7 @@ class MyModel(models.Model): and we now change the model to: -```python3 +```python from django.db import models diff --git a/antipattern/signals.md b/antipattern/signals.md index f3a6d2e..283e083 100644 --- a/antipattern/signals.md +++ b/antipattern/signals.md @@ -138,7 +138,7 @@ predictable. One can construct a [*data migration* [Django-doc]](https://docs.djangoproject.com/en/dev/howto/writing-migrations/#how-to-create-database-migrations), such migration could populate a database table, for example: -```python3 +```python from django.apps import apps as global_apps from django.db import migrations @@ -201,7 +201,7 @@ and `Author`s grows, then this can become a performance bottleneck. Another option might be to encapsulate the handler logic in a specific function. For example if we want to count the number of books of an `Author` each time we save/update a `Book`, we can implement the logic: -```python3 +```python def update_book(book): author = book.author author.num_books = author.books.count() diff --git a/antipattern/using-multiple-forms-on-the-same-page-without-prefixing.md b/antipattern/using-multiple-forms-on-the-same-page-without-prefixing.md index 49134f5..4044467 100644 --- a/antipattern/using-multiple-forms-on-the-same-page-without-prefixing.md +++ b/antipattern/using-multiple-forms-on-the-same-page-without-prefixing.md @@ -18,7 +18,7 @@ each process their part of the composite form. For example one can make two forms to fill in data about the father and the mother with: -```python3 +```python from django import forms class FatherForm(forms.Form): diff --git a/pattern/dictionary-lookups-for-the-database.md b/pattern/dictionary-lookups-for-the-database.md index ad7475d..4c979c7 100644 --- a/pattern/dictionary-lookups-for-the-database.md +++ b/pattern/dictionary-lookups-for-the-database.md @@ -10,7 +10,7 @@ solinks: [] It happens occasionally we want to perform a lookup with a dictionary for model records. Indeed, imagine we have a dictionary: -```python3 +```python prices = { 13: 2.0, 14: 25.0, @@ -25,7 +25,7 @@ In an ideal scenario, we store the prices in the database, for example with as a In a seldom scenario, it might however not be possible, for example because there is no such table, or because we are not allowed to make modifications to the database, or because we want to calculate a price changes, without storing the prices. In that case we thus want to work with a dictionary lookup. The following will however *not* work: -```python3 +```python # will *not* work Product.objects.annotate(price=prices.get(F('pk'))) ``` diff --git a/pattern/match-multiple-strings-in-a-case-insensitive-manner.md b/pattern/match-multiple-strings-in-a-case-insensitive-manner.md index 9b13aa2..94380d9 100644 --- a/pattern/match-multiple-strings-in-a-case-insensitive-manner.md +++ b/pattern/match-multiple-strings-in-a-case-insensitive-manner.md @@ -15,7 +15,7 @@ Often this is also checked in a case-*in*sensitive way, such that `'apple'` and Usually we have a list of items that we want to match with that field, for example: -```python3 +```python fruits = ['apple', 'blueberry', 'coconut', 'dragonfruit'] ``` @@ -28,7 +28,7 @@ We can not make use of the [**`__in`** lookup [Django-doc]](http since this will only match items that contain exactly the name of one fruit in case-sensitive way. This thus means that the content should be `'apple'`, not `'APPLE'`, `'Apple'`, `'An apple'`, etc.: -```python3 +```python Post.objects.filter( content__in=fruits ) diff --git a/pattern/querying-in-the-opposite-direction.md b/pattern/querying-in-the-opposite-direction.md index 6b1ae1a..eb67707 100644 --- a/pattern/querying-in-the-opposite-direction.md +++ b/pattern/querying-in-the-opposite-direction.md @@ -13,7 +13,7 @@ solinks: ["https://stackoverflow.com/questions/78132711/i-need-a-django-filter-q Django's ORM is quite expressive, and lookups can be used to filter in a specific way, for example: -```python3 +```python MyModel.objects.filter(title__regex='^[0-9]+$') ``` @@ -25,7 +25,7 @@ At the moment of writing there is no reverse lookup: we can not perform a `MyMod A simple, but a bit "*ugly*" way to solve this is by using [**.alias(…)** \[Django-doc\]](https://docs.djangoproject.com/en/stable/ref/models/querysets/#alias) to "inject" the value as a field in the queryset and then thus query with that "field", we can then use an [**`F`** expression \[Django-doc\]](https://docs.djangoproject.com/en/stable/ref/models/expressions/#django.db.models.F) to refer to the `pattern` field. This thus then looks like: -```python3 +```python from django.db.models import F, Value MyModel.objects.alias(val=Value('test_string')).filter(val__regex=F('pattern')) @@ -35,7 +35,7 @@ Since we use .alias(…) the value will not appear in the `SEL But probably a more robust, and clearer way to show what we are doing, is building a query object like Django does behind the curtains when we perform lookups. Indeed, if we write `pattern__regex`, it makes a lookup for a field named `pattern`, and inspects what type of field it is. For a `CharField` a different set of lookups will be "registered". If we then write `__regex`, it will start looking for a lookup registered at this field with the name `regex`. These lookups typically reside in the `django.db.models.lookups` module. For this specific case, this is the `Regex` class. We thus can construct such query with: -```python3 +```python from django.db.models import F, Value from django.db.models.lookups import Regex diff --git a/pattern/set-values-to-a-created-updated-object-in-a-class-based-view.md b/pattern/set-values-to-a-created-updated-object-in-a-class-based-view.md index c5a8c99..3031f31 100644 --- a/pattern/set-values-to-a-created-updated-object-in-a-class-based-view.md +++ b/pattern/set-values-to-a-created-updated-object-in-a-class-based-view.md @@ -11,7 +11,7 @@ Often not all fields specified in a model are specified through a form. These for example originate for example through the path, or we make use of the logged in user. Take for example the following model: -```python3 +```python from django.conf import settings from django.db import models @@ -26,7 +26,7 @@ The form will normally only take the `comment` as field, not the `post` and `author`. We can for example specify the primary key of the post in the path, and the author is normally the logged in user. The form thus looks like: -```python3 +```python from django import forms class CommentForm(forms.ModelForm): From dacd0b9e99310c88c90d567fdae8669ddc6b20a1 Mon Sep 17 00:00:00 2001 From: Willem Van Onsem Date: Mon, 14 Oct 2024 11:00:47 +0200 Subject: [PATCH 2/2] add check --- .github/workflows/build-site.yml | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build-site.yml b/.github/workflows/build-site.yml index d7bb1ba..1a7bd18 100644 --- a/.github/workflows/build-site.yml +++ b/.github/workflows/build-site.yml @@ -33,10 +33,19 @@ jobs: - name: look for todos run: "! grep -i -P '|TODO|[?]{3,}' */*.md" + linux3: + name: Look for code not highlighted + runs-on: ubuntu-latest + steps: + - name: checkout code + uses: actions/checkout@v2.3.1 + - name: look for unhighlighted code + run: "! grep -Pz '\\n\\n```\\n' */*.md" + linux3: name: Deploy website runs-on: ubuntu-latest - needs: [linux1, linux2] + needs: [linux1, linux2, linux3] if: github.ref == 'refs/heads/master' steps: - name: update package database