-
-
Notifications
You must be signed in to change notification settings - Fork 21
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Deploying to gh-pages from @ 0ec1cc6 🚀
- Loading branch information
0 parents
commit 10f23e7
Showing
175 changed files
with
1,657 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
www.django-antipatterns.com |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
<!doctype html><html lang=en><head><meta name=viewport content="width=device-width,initial-scale=1"><meta charset=utf-8><meta http-equiv=content-security-policy content="frame-src https://www.buymeacoffee.com; style-src 'unsafe-inline' https://cdn.jsdelivr.net https://cdnjs.cloudflare.com https://cdn.rawgit.com 'self'; script-src 'sha256-imF8GK2COF0FH3k9XZpauIkklApKaavS3S5BhNoXbio=' 'sha256-cZF+Uee35x4Ntz8KyGTRwEq74vIlvLgxfBw7ARDKY0o=' 'sha256-nP0EI9B9ad8IoFUti2q7EQBabcE5MS5v0nkvRfUbYnM=' https://cdn.jsdelivr.net https://cdnjs.buymeacoffee.com https://code.jquery.com https://cdnjs.cloudflare.com https://cdn.rawgit.com https://pagead2.googlesyndication.com 'self'; img-src https://repository-images.githubusercontent.com https://cdn.buymeacoffee.com https://img.shields.io 'self'"><meta name=keywords content="Django,web,programming,antipattern,pattern,troubleshooting,software design "><meta name=author content="Willem Van Onsem"><meta name=description content="A set of Django (anti)patterns: patterns and things to avoid when building a web application with Django."><meta name=twitter:image:src content="https://repository-images.githubusercontent.com/257009680/7a954900-2f5d-11eb-8d0a-c8af0596107f"><meta name=og:title content="Antipatterns"><meta name=og:image content="https://repository-images.githubusercontent.com/257009680/7a954900-2f5d-11eb-8d0a-c8af0596107f"><meta name=og:image:alt content="A prohibition sign in the Django color scheme."><meta name=og:image:type content="image/png"><meta name=og:type content="website"><link rel=stylesheet href=https://cdn.rawgit.com/diversen/pandoc-bootstrap-adaptive-template/959c3622/template.css><link rel=stylesheet href=https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.3.2/styles/default.min.css><link rel=stylesheet href=https://cdnjs.cloudflare.com/ajax/libs/github-fork-ribbon-css/0.2.3/gh-fork-ribbon.min.css><script src=https://code.jquery.com/jquery-3.5.1.min.js></script> | ||
<script src=https://cdn.rawgit.com/diversen/pandoc-bootstrap-adaptive-template/959c3622/menu/js/jquery.cookie.js></script> | ||
<script src=https://cdn.rawgit.com/diversen/pandoc-bootstrap-adaptive-template/959c3622/menu/js/jquery.hoverIntent.minified.js></script> | ||
<script src=https://cdn.rawgit.com/diversen/pandoc-bootstrap-adaptive-template/959c3622/menu/js/jquery.dcjqaccordion.2.7.min.js></script> | ||
<link rel=stylesheet href=https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.3/css/all.min.css integrity="sha512-iBBXm8fW90+nuLcSKlbmrPcLa0OT92xO1BIsZ+ywDWZCvqsWgccV3gFoRBv0z+8dLJgyAHIhR35VZc2oM/gI1w==" crossorigin=anonymous referrerpolicy=no-referrer><link href=/style.css rel=stylesheet><link href=https://cdn.rawgit.com/ryangrose/easy-pandoc-templates/948e28e5/css/elegant_bootstrap.css rel=stylesheet><script src=https://cdn.rawgit.com/diversen/pandoc-bootstrap-adaptive-template/959c3622/jquery.sticky-kit.js></script> | ||
<script data-ad-client=ca-pub-9962024266760159 async src=https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js></script> | ||
<script src=/script.js></script> | ||
<link rel=icon href=/favicon.ico type=image/x-icon><meta name=generator content="pandoc"><title>Antipatterns ‹ Django antipatterns</title><link rel=stylesheet href></head><body><a class=github-fork-ribbon href=https://github.com/hapytex/django-antipatterns data-ribbon="Fork me on GitHub" title="Fork me on GitHub">Fork me on GitHub</a><div class="navbar navbar-static-top"><div class=navbar-inner><div class=container><nav aria-label=section><ol class=breadcrumb><li class=breadcrumb-item><a href=/><i class="fas fa-home"></i></a><li class="breadcrumb-item active" aria-current=page>Antipatterns</ol></nav><ul class="nav pull-right doc-info"></ul></div></div></div><article><div class=container><div class=row><div class=span12><div class=twocolumns><ol><li><a href=/antipattern/a-get-request-with-side-effects.html>A GET request with side-effects</a><li><a href=/antipattern/a-model-with-a-model-suffix.html>A model with a <code>…Model</code> suffix</a><li><a href=/antipattern/calling-all-before-count-or-filter.html>calling <code>all()</code> before <code>count()</code> or <code>filter()</code> etc.</a><li><a href=/antipattern/chaining-querysets-together.html><code>Chain</code>ing querysets together</a><li><a href=/antipattern/checking-ownership-through-the-userpassestestmixin.html>Checking ownership through the <code>UserPassesTestMixin</code></a><li><a href=/antipattern/checking-request-method-with-if-request-post.html>Checking request method with <code>if request.POST</code></a><li><a href=/antipattern/constructing-a-new-form-when-validation-fails.html>Constructing a new form when validation fails</a><li><a href=/antipattern/fetching-the-logged-in-user-with-a-query.html>Fetching the logged in user with a query</a><li><a href=/antipattern/fill-the-primary-key-gaps.html>Fill the primary key gaps</a><li><a href=/antipattern/filter-on-arbitrary-input-like-request-get.html>Filter on arbitrary input like request.GET</a><li><a href=/antipattern/filtering-in-the-template.html>Filtering in the template</a><li><a href=/antipattern/foreign-key-with-id-suffix.html>Foreign key with <code>_id</code> suffix</a><li><a href=/antipattern/giving-related-name-the-same-name-as-the-relation.html>Giving <code>related_name=…</code> the same name as the relation</a><li><a href=/antipattern/imports.html>Imports</a><li><a href=/antipattern/manually-constructing-a-slug.html>Manually constructing a slug</a><li><a href=/antipattern/modifying-slugs-and-primary-keys-of-model-objects.html>Modifying slugs and primary keys of model objects</a><li><a href=/antipattern/non-atomic-jsonfield-s.html>non-atomic <code>JSONField</code>s</a><li><a href=/antipattern/over-use-of-values.html>(Over)use of <code>.values()</code></a><li><a href=/antipattern/passing-function-references-to-reverse.html>passing function references to reverse</a><li><a href=/antipattern/passing-parameters-directly-in-the-query-string-of-a-url.html>Passing parameters directly in the query string of a URL</a><li><a href=/antipattern/plural-model-class-names.html>Plural model class names</a><li><a href=/antipattern/refer-to-the-user-model-directly.html>Refer to the <code>User</code> model directly</a><li><a href=/antipattern/rendering-content-after-a-successful-post-request.html>Rendering content after a successful POST request</a><li><a href=/antipattern/rendering-into-javascript.html>Rendering into JavaScript</a><li><a href=/antipattern/return-a-jsonresponse-with-safe-false.html>Return a <code>JsonResponse</code> with <code>safe=False</code></a><li><a href=/antipattern/signals.html>Signals</a><li><a href=/antipattern/use-datetime-now-as-default-for-a-created-on-field.html>Use <code>datetime.now</code> as <code>default=…</code> for a <code>created_on</code> field</a><li><a href=/antipattern/use-get-to-retrieve-the-object-in-a-view.html>Use <code>.get(…)</code> to retrieve the object in a view</a><li><a href=/antipattern/using-a-floatfield-for-currencies.html>Using a <code>FloatField</code> for currencies</a><li><a href=/antipattern/using-commit-false-when-altering-the-instance-in-a-modelform.html>Using <code>commit=False</code> when altering the instance in a <code>ModelForm</code></a><li><a href=/antipattern/using-len-on-a-queryset-with-no-further-use.html>Using <code>len(…)</code> on a <code>QuerySet</code> with no further use</a><li><a href=/antipattern/using-multiple-forms-on-the-same-page-without-prefixing.html>Using multiple forms on the same page without prefixing</a><li><a href=/antipattern/using-regular-html-comments-instead-of-django-template-comments.html>Using regular HTML comments instead of Django template comments</a><li><a href=/antipattern/using-request-post-or-none.html>Using <code>request.POST or None</code></a></ol></div><script nonce data-name=BMC-Widget src=https://cdnjs.buymeacoffee.com/1.0.0/widget.prod.min.js data-id=hapytex data-description="Support me on Buy me a coffee!" data-message="Thank you for visiting." data-color=#FFDD00 data-position=Right data-x_margin=18 data-y_margin=18></script></div></div></div><script src=https://cdnjs.cloudflare.com/ajax/libs/anchor-js/4.3.1/anchor.min.js integrity="sha512-zPB79j2C+3sFS9zcA3vg/z6bVKzJVEyu9pY5w89akQRys76zpAT2t6S3wZKla3QQ14O5l/Yt0RUQ/DHXx82Y5g==" crossorigin=anonymous referrerpolicy=no-referrer></script> | ||
<script src=https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.3.2/highlight.min.js></script> | ||
<script>hljs.initHighlightingOnLoad()</script></article></body></html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
<!doctype html><html lang=en><head><meta name=viewport content="width=device-width,initial-scale=1"><meta charset=utf-8><meta http-equiv=content-security-policy content="frame-src https://www.buymeacoffee.com; style-src 'unsafe-inline' https://cdn.jsdelivr.net https://cdnjs.cloudflare.com https://cdn.rawgit.com 'self'; script-src 'sha256-imF8GK2COF0FH3k9XZpauIkklApKaavS3S5BhNoXbio=' 'sha256-cZF+Uee35x4Ntz8KyGTRwEq74vIlvLgxfBw7ARDKY0o=' 'sha256-nP0EI9B9ad8IoFUti2q7EQBabcE5MS5v0nkvRfUbYnM=' https://cdn.jsdelivr.net https://cdnjs.buymeacoffee.com https://code.jquery.com https://cdnjs.cloudflare.com https://cdn.rawgit.com https://pagead2.googlesyndication.com 'self'; img-src https://repository-images.githubusercontent.com https://cdn.buymeacoffee.com https://img.shields.io 'self'"><meta name=keywords content="Django,web,programming,antipattern,pattern,troubleshooting,software design,http,get-request,side-effects,query-string,django-views "><meta name=author content="Willem Van Onsem"><meta name=description content="A set of Django (anti)patterns: patterns and things to avoid when building a web application with Django."><meta name=twitter:image:src content="https://repository-images.githubusercontent.com/257009680/7a954900-2f5d-11eb-8d0a-c8af0596107f"><meta name=og:title content="A GET request with side-effects"><meta name=og:image content="https://repository-images.githubusercontent.com/257009680/7a954900-2f5d-11eb-8d0a-c8af0596107f"><meta name=og:image:alt content="A prohibition sign in the Django color scheme."><meta name=og:image:type content="image/png"><meta name=og:type content="website"><link rel=stylesheet href=https://cdn.rawgit.com/diversen/pandoc-bootstrap-adaptive-template/959c3622/template.css><link rel=stylesheet href=https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.3.2/styles/default.min.css><link rel=stylesheet href=https://cdnjs.cloudflare.com/ajax/libs/github-fork-ribbon-css/0.2.3/gh-fork-ribbon.min.css><script src=https://code.jquery.com/jquery-3.5.1.min.js></script> | ||
<script src=https://cdn.rawgit.com/diversen/pandoc-bootstrap-adaptive-template/959c3622/menu/js/jquery.cookie.js></script> | ||
<script src=https://cdn.rawgit.com/diversen/pandoc-bootstrap-adaptive-template/959c3622/menu/js/jquery.hoverIntent.minified.js></script> | ||
<script src=https://cdn.rawgit.com/diversen/pandoc-bootstrap-adaptive-template/959c3622/menu/js/jquery.dcjqaccordion.2.7.min.js></script> | ||
<link rel=stylesheet href=https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.3/css/all.min.css integrity="sha512-iBBXm8fW90+nuLcSKlbmrPcLa0OT92xO1BIsZ+ywDWZCvqsWgccV3gFoRBv0z+8dLJgyAHIhR35VZc2oM/gI1w==" crossorigin=anonymous referrerpolicy=no-referrer><link href=/style.css rel=stylesheet><link href=https://cdn.rawgit.com/ryangrose/easy-pandoc-templates/948e28e5/css/elegant_bootstrap.css rel=stylesheet><script src=https://cdn.rawgit.com/diversen/pandoc-bootstrap-adaptive-template/959c3622/jquery.sticky-kit.js></script> | ||
<script data-ad-client=ca-pub-9962024266760159 async src=https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js></script> | ||
<script src=/script.js></script> | ||
<link rel=icon href=/favicon.ico type=image/x-icon><meta name=generator content="pandoc"><title>A GET request with side-effects ‹ antipattern ‹ Django antipatterns</title><link rel=stylesheet href></head><body><a class=github-fork-ribbon href=https://github.com/hapytex/django-antipatterns data-ribbon="Fork me on GitHub" title="Fork me on GitHub">Fork me on GitHub</a><div class="navbar navbar-static-top"><div class=navbar-inner><div class=container><nav aria-label=section><ol class=breadcrumb><li class=breadcrumb-item><a href=/><i class="fas fa-home"></i></a><li class=breadcrumb-item><a href=/antipattern.html><i class="fas fa-ban"></i> | ||
antipattern</a><li class="breadcrumb-item active" aria-current=page>A GET request with side-effects</ol></nav><ul class="nav pull-right doc-info"><li><div class=rating data-rating=4>severity: | ||
<i class=star-1>★</i> | ||
<i class=star-2>★</i> | ||
<i class=star-3>★</i> | ||
<i class=star-4>★</i> | ||
<i class=star-5>★</i></div></ul></div></div></div><article><div class=container><div class=row><div class=span12><p>Often people construct views that have side, effects, for example:<pre class=python><code>def remove_comment(request, comment_pk): | ||
Comment.objects.<b>filter(</b> | ||
comment_id=comment_pk | ||
)<b>.delete()</b> | ||
# …</code></pre><h1 id=why-is-it-a-problem>Why is it a problem?</h1><p>Because this violates the HTTP standard. In the section <a href=https://www.rfc-editor.org/rfc/rfc9110.html#name-safe-methods><em>safe methods</em> of the HTTP specifications <sup>[w3.org]</sup></a> it specifies that:<blockquote><p>In particular, the convention has been established <strong>that the GET</strong> and HEAD methods <strong>SHOULD NOT have the significance</strong> of taking an action <strong>other than retrieval</strong>. These methods <strong>ought to be considered "safe"</strong>.</blockquote><p>A GET request should thus not create, update, or delete entities.<p>This is important because other actors on the internet assume that a GET request is safe. For example if a browser will not give a warning if you refresh the browser with an additional GET request, whereas most browsers will do that for a POST request.<p>Search engines have web crawlers that look for URLs on pages, and will make GET requests to these pages to analyze the page that is returned and look for more URLs. This thus means that a GET request of such crawler might accidentally create, remove and update entities.<p>Django also does not offer security mechanisms like a CSRF-token for GET requests. This thus makes <a href=https://en.wikipedia.org/wiki/Cross-site_request_forgery>cross-site request forgery (CSRF) <sup>[wiki]</sup></a> easier.<h1 id=what-can-be-done-to-resolve-the-problem>What can be done to resolve the problem?</h1><p>One should use POST, PUT, PATCH, or DELETE requests to update entities. These are the HTTP methods designed for this. One can use for example the <a href=https://docs.djangoproject.com/en/dev/topics/http/decorators/#django.views.decorators.http.require_http_methods><strong><code>@require_http_methods</code></strong> decorator <sup>[Django-doc]</sup></a> to restrict a view to certain HTTP methods. For a POST request, we can make use of the <a href=https://docs.djangoproject.com/en/dev/topics/http/decorators/#django.views.decorators.http.require_POST><strong><code>@require_POST</code></strong> decorator <sup>[Django-doc]</sup></a>. This will return a <a href=https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#4xx_client_errors>HTTP 405 "<em>Method Not Allowed</em>" response <sup>[wiki]</sup></a> to warn the client that this request was not allowed:<pre class=python><code>from django.views.decorators.http import <b>require_POST</b> | ||
|
||
<b>@require_POST</b> | ||
def remove_comment(request, comment_pk): | ||
Comment.objects.<b>filter(</b> | ||
comment_id=comment_pk | ||
<b>).delete()</b> | ||
# …</code></pre><p>The HTML page should thus use a mini <code><form></code> to produce the POST request, or an AJAX call.</p><script nonce data-name=BMC-Widget src=https://cdnjs.buymeacoffee.com/1.0.0/widget.prod.min.js data-id=hapytex data-description="Support me on Buy me a coffee!" data-message="Thank you for visiting." data-color=#FFDD00 data-position=Right data-x_margin=18 data-y_margin=18></script></div></div></div><script src=https://cdnjs.cloudflare.com/ajax/libs/anchor-js/4.3.1/anchor.min.js integrity="sha512-zPB79j2C+3sFS9zcA3vg/z6bVKzJVEyu9pY5w89akQRys76zpAT2t6S3wZKla3QQ14O5l/Yt0RUQ/DHXx82Y5g==" crossorigin=anonymous referrerpolicy=no-referrer></script> | ||
<script src=https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.3.2/highlight.min.js></script> | ||
<script>hljs.initHighlightingOnLoad()</script><script>anchors.options={placement:'left',visible:'hover',icon:'¶'},anchors.add('h1,h2,h3')</script></article></body></html> |
Oops, something went wrong.