<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: spikelantern</title>
    <description>The latest articles on DEV Community by spikelantern (@spikelanterncom).</description>
    <link>https://dev.to/spikelanterncom</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F441283%2F65c9bb92-0e14-44d4-9105-8ffaed42e10b.jpg</url>
      <title>DEV Community: spikelantern</title>
      <link>https://dev.to/spikelanterncom</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/spikelanterncom"/>
    <language>en</language>
    <item>
      <title>Simple infinite scroll in Django</title>
      <dc:creator>spikelantern</dc:creator>
      <pubDate>Sun, 26 Jul 2020 00:00:00 +0000</pubDate>
      <link>https://dev.to/spikelanterncom/simple-infinite-scroll-in-django-31n5</link>
      <guid>https://dev.to/spikelanterncom/simple-infinite-scroll-in-django-31n5</guid>
      <description>&lt;p&gt;If you've used Twitter, Instagram, or Facebook, you would have used something called "infinite scroll", sometimes also called "infinite loading" or "endless pagination".&lt;/p&gt;

&lt;p&gt;Basically, it means that once you scroll down near the bottom of a list of items, the page fetches new items automatically and adds them to the page. That makes it a smoother experience compared to traditional pagination in some cases.&lt;/p&gt;

&lt;p&gt;You may have wondered how to do that in Django. I'm going to show you a very simple way to do this using no JavaScript libraries.&lt;/p&gt;

&lt;p&gt;Note: The solution here is inefficient for lists with a large number of items (e.g. thousands of items). Efficient infinite scroll uses windowing, and removes items not in view from the DOM. However, if you are only dealing with a few hundred items, this is a very simple way to achieve this, with no dependencies.&lt;/p&gt;

&lt;p&gt;Don't worry about the specific details of the code snippets here, just make sure you understand the basic concepts. At the end of the article, I will link to some example code.&lt;/p&gt;

&lt;h2&gt;
  
  
  Detecting when we've scrolled to the bottom
&lt;/h2&gt;

&lt;p&gt;In the frontend, we will need a way to detect when you've scrolled to the bottom.&lt;/p&gt;

&lt;p&gt;This used to be pretty difficult to do, but there is a new browser API or feature called &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API" rel="noopener noreferrer"&gt;Intersection Observer&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;We can think of it as having two components, the scrollable element, and a "sentinel":&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fspikelantern.com%2Fimages%2Finfinitescroll.svg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fspikelantern.com%2Fimages%2Finfinitescroll.svg" alt="Basic concept"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Basic concept&lt;/p&gt;

&lt;p&gt;The idea is that when the user scrolls down to where the sentinel element is visible, we fetch new items from the Django backend.&lt;/p&gt;

&lt;p&gt;First, let's look at how we can detect when this happens using the Intersection Observer API.&lt;/p&gt;

&lt;p&gt;First, the Django template, as you can see it's just a list of items and then a sentinel element:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;div id="scrollable-element"&amp;gt;
    {% for post in posts %}
        {% include "_post.html" with post=post %}
    {% endfor %}
&amp;lt;/div&amp;gt;

&amp;lt;div id="sentinel"&amp;gt;&amp;lt;/div&amp;gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now the JavaScript&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;document.addEventListener("DOMContentLoaded", () =&amp;gt; {
  let sentinel = document.getElementById("sentinel");

  let observer = new IntersectionObserver((entries) =&amp;gt; {
    entry = entries[0];
    if (entry.intersectionRatio &amp;gt; 0) {
        alert("This happened");
    }
  })
  observer.observe(sentinel);
})

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When you scroll to the bottom where the sentinel is visible, you should get a popup alert.&lt;/p&gt;

&lt;p&gt;That's great! Now we can replace that popup alert with an AJAX request to our backend. But let's add that functionality to our backend first.&lt;/p&gt;

&lt;p&gt;We can choose to have our backend return JSON, and render it client-side (e.g. using a templating library), but in this tutorial I have opted to have the backend return HTML, and appending this to the scrollable element through &lt;code&gt;innerHTML&lt;/code&gt;. This is a pretty old-fashioned AJAX technique that you sometimes still see in websites like GitHub. If you do this, you need to be very careful with XSS, but we'll discuss this later.&lt;/p&gt;

&lt;h2&gt;
  
  
  Django pagination
&lt;/h2&gt;

&lt;p&gt;You might be familiar with Django's pagination, if not check out &lt;a href="https://docs.djangoproject.com/en/3.0/topics/pagination/" rel="noopener noreferrer"&gt;the documentation on that topic here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Here's how it works. Let's say you have a simple list view like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from django.shortcuts import render
from django.views.decorators.http import require_GET, require_POST
from .models import Post

@require_GET
def post_list(request):
    posts = Post.objects.order_by('-created_at').all()
    context = {'posts': posts}
    return render(request, 'post_list.html', context)

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can paginate this by changing it like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from django.shortcuts import render
from django.core.paginator import Paginator
from django.http import Http404
from django.views.decorators.http import require_GET, require_POST
from .models import Post

@require_GET
def post_list(request):
    all_posts = Post.objects.order_by('-created_at').all()
    paginator = Paginator(all_posts, per_page=10)
    page_num = int(request.GET.get("page", 1))
    if page_num &amp;gt; paginator.num_pages:
        raise Http404
    posts = paginator.page(page_num)
    context = {'posts': posts}
    return render(request, 'post_list.html', context)

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;However, we want to have our backend return a short HTML snippet, rather than the full HTML page. So what we want to do is a bit of conditional processing.&lt;/p&gt;

&lt;p&gt;First we add another partial template like this, let's call it &lt;code&gt;_posts.html&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    {% for post in posts %}
        {% include "_post.html" with post=post %}
    {% endfor %}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And include that in our list view:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;div id="scrollable-element"&amp;gt;
    {% include "_posts.html" with posts=posts %}
&amp;lt;/div&amp;gt;

&amp;lt;div id="sentinel"&amp;gt;&amp;lt;/div&amp;gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then we need to conditionally change the response when the request is an AJAX request. We used to &lt;a href="https://docs.djangoproject.com/en/3.0/ref/request-response/#django.http.HttpRequest.is_ajax" rel="noopener noreferrer"&gt;be able to do this using &lt;code&gt;request.is_ajax()&lt;/code&gt;&lt;/a&gt;, but starting from &lt;a href="https://docs.djangoproject.com/en/3.1/releases/3.1/#id2" rel="noopener noreferrer"&gt;version 3.1 this is deprecated&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Luckily, it's easy to replicate that functionality:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;def is_ajax(request):
    """
    This utility function is used, as `request.is_ajax()` is deprecated.

    This implements the previous functionality. Note that you need to
    attach this header manually if using fetch.
    """
    return request.META.get("HTTP_X_REQUESTED_WITH") == "XMLHttpRequest"

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, we simply change the above paginated view to do this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@require_GET
def post_list(request):
    """
    List view for posts.
    """
    all_posts = Post.objects.order_by('-created_at').all()
    paginator = Paginator(all_posts, per_page=10)
    page_num = int(request.GET.get("page", 1))
    if page_num &amp;gt; paginator.num_pages:
        raise Http404
    posts = paginator.page(page_num)
    if is_ajax(request):
        return render(request, '_posts.html', {'posts': posts})
    return render(request, 'post_list.html', {'posts': posts})

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's all we need for the backend.&lt;/p&gt;

&lt;h2&gt;
  
  
  Making AJAX requests
&lt;/h2&gt;

&lt;p&gt;Now, we can update our JavaScript code to fetch the data from the backend when we scroll down to the sentinel.&lt;/p&gt;

&lt;p&gt;Note that we are using &lt;code&gt;fetch&lt;/code&gt; in this example, and it doesn't add the &lt;code&gt;X-Requested-With&lt;/code&gt; header by default (which is actually why it &lt;code&gt;request.is_ajax()&lt;/code&gt; was deprecated). So we need to manually add that header.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const fetchPage = async (url) =&amp;gt; {
  let headers = new Headers()
  headers.append("X-Requested-With", "XMLHttpRequest")
  return fetch(url, { headers })
}

document.addEventListener("DOMContentLoaded", () =&amp;gt; {
  let sentinel = document.getElementById("sentinel");
  let scrollElement = document.getElementById("scroll-element");
  let counter = 2;
  let end = false;

  let observer = new IntersectionObserver(async (entries) =&amp;gt; {
    entry = entries[0];
    if (entry.intersectionRatio &amp;gt; 0) {
        let url = `/posts/?page=${counter}`;
        let req = await fetchPage(url);
        if (req.ok) {
            let body = await req.text();
            // Be careful of XSS if you do this. Make sure
            // you remove all possible sources of XSS.
            scrollElement.innerHTML += body;
        } else {
            // If it returns a 404, stop requesting new items
            end = true;
        }
    }
  })
  observer.observe(sentinel);
})

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  A note about &lt;code&gt;innerHTML&lt;/code&gt; and XSS
&lt;/h2&gt;

&lt;p&gt;In this example, we appended HTML from the server's response to &lt;code&gt;innerHTML&lt;/code&gt;. This is a technique that used to be pretty common, and we still see in websites like GitHub. Try opening your "Network" tab in dev tools the next time you're on GitHub, and see the responses when you interact with the website!&lt;/p&gt;

&lt;p&gt;As mentioned, if you do this, you need to be very careful to remove sources of XSS in your HTTP response from the backend, otherwise an attacker can inject malicious JavaScript that runs on a user's browser.&lt;/p&gt;

&lt;p&gt;If you use Django templates, your template is escaped by default. However, if you use the &lt;code&gt;safe&lt;/code&gt; template filter (e.g. you're allowing user to input some HTML) this method is unsafe.&lt;/p&gt;

&lt;p&gt;First, you should re-evaluate whether you should be allowing users to enter untrusted HTML that you will display. In many cases you shouldn't need to.&lt;/p&gt;

&lt;p&gt;If you can't get around this, you will need to sanitise the HTML. You can do it in the backend using a library like &lt;a href="https://bleach.readthedocs.io/en/latest/" rel="noopener noreferrer"&gt;bleach&lt;/a&gt;, or a frontend library like &lt;a href="https://github.com/cure53/DOMPurify" rel="noopener noreferrer"&gt;DOMPurify&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Alternatively, you can return a JSON response from the backend, and render the HTML client-side. This is a more common way to do this today, as there are frontend frameworks and libraries to do exactly this. This is beyond the scope of this tutorial.&lt;/p&gt;

&lt;h2&gt;
  
  
  Example code
&lt;/h2&gt;

&lt;p&gt;If you want to see a full working example, I have pushed some sample code to my repository here:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/spikelantern/simple-infinite-scroll.git" rel="noopener noreferrer"&gt;https://github.com/spikelantern/simple-infinite-scroll.git&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;In this tutorial, we covered a very simple infinite scroll implementation that doesn't use any special libraries. This uses the new Intersection Observer API.&lt;/p&gt;

&lt;p&gt;As mentioned, this technique isn't ideal for very large lists. For an efficient solution, it's necessary to delete DOM elements to prevent the DOM from growing too much. However, for a few hundred items, this should work just fine.&lt;/p&gt;

&lt;p&gt;We also discussed the use of &lt;code&gt;innerHTML&lt;/code&gt; and its security implications, and recommended some possible mitigations and alternatives.&lt;/p&gt;

&lt;p&gt;Hopefully, this post helped you. If you liked this article, make sure to subscribe. I plan to post more articles about using JavaScript with Django, so make sure you subscribe to get notified!&lt;/p&gt;

</description>
      <category>django</category>
      <category>python</category>
      <category>javascript</category>
      <category>infinitescroll</category>
    </item>
    <item>
      <title>How much Python do I need to learn for Django?</title>
      <dc:creator>spikelantern</dc:creator>
      <pubDate>Wed, 15 Jul 2020 00:00:00 +0000</pubDate>
      <link>https://dev.to/spikelanterncom/how-much-python-do-i-need-to-learn-for-django-3nnj</link>
      <guid>https://dev.to/spikelanterncom/how-much-python-do-i-need-to-learn-for-django-3nnj</guid>
      <description>&lt;p&gt;Recently, someone on Reddit posted a question asking how much Python one needs to know before moving on to Django.&lt;/p&gt;

&lt;p&gt;That's a great question.&lt;/p&gt;

&lt;p&gt;Learning Python can take a long time! You wouldn't want to spend years "learning" Python before moving to the fun stuff.&lt;/p&gt;

&lt;p&gt;You want results much sooner than that!&lt;/p&gt;

&lt;p&gt;In fact, I would say one of the best ways to get better at Python (but not necessarily learning from scratch) is &lt;em&gt;through&lt;/em&gt; Django. People always recommend getting better at Python through doing. Using Django to build web applications is one way of "doing"!&lt;/p&gt;

&lt;p&gt;That being said, you do need to have some fundamentals in order to use Django at all, otherwise a lot of things won't make sense.&lt;/p&gt;

&lt;p&gt;But then how do you know when you've learned "enough"?&lt;/p&gt;

&lt;h2&gt;
  
  
  The bare minimum
&lt;/h2&gt;

&lt;p&gt;I will tell you what I recommended to do Django at a basic level.&lt;/p&gt;

&lt;p&gt;If this seems like a lot, don't worry. If you work at it, you &lt;em&gt;will&lt;/em&gt; learn everything here and more.&lt;/p&gt;

&lt;p&gt;You should ask yourself the following questions. If you say "yes" to all (or most of them), you are well equipped to move on to Django.&lt;/p&gt;

&lt;p&gt;If not, I suggest working at them in this specific order.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Basic program flow&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Can you write simple scripts that take basic input and output?&lt;/p&gt;

&lt;p&gt;Do you know how to write &lt;code&gt;if&lt;/code&gt; statements?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Working with collections&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Do you know the differences between a &lt;code&gt;list&lt;/code&gt;, a &lt;code&gt;tuple&lt;/code&gt;, a &lt;code&gt;dict&lt;/code&gt; and a &lt;code&gt;set&lt;/code&gt;? Do you know why each one is used?&lt;/p&gt;

&lt;p&gt;Do you know how to iterate through them using &lt;code&gt;for&lt;/code&gt; loops and &lt;code&gt;while&lt;/code&gt; loops?&lt;/p&gt;

&lt;p&gt;Do you know how to write basic list and generator comprehensions?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Working with strings&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Do you know that a &lt;code&gt;string&lt;/code&gt; is also something you can iterate over, like a &lt;code&gt;list&lt;/code&gt;? Do you know how to do that?&lt;/p&gt;

&lt;p&gt;Can you do basic string formatting? For example, can you take a variable and create a string that contains that variable?&lt;/p&gt;

&lt;p&gt;Do you know that a &lt;code&gt;string&lt;/code&gt; is also an object with its own methods?&lt;/p&gt;

&lt;p&gt;Do you know how to join strings together, and split them based on a delimiter?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Writing and using functions&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Can you write a function?&lt;/p&gt;

&lt;p&gt;Do you know how to specify arguments and keyword arguments in your function, and how they work?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. Using decorators&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Do you know what a decorator is, and how to use it?&lt;/p&gt;

&lt;p&gt;(Knowing how to write one is optional)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;6. Modules, packages, and libraries&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Do you know what Python modules and packages are?&lt;/p&gt;

&lt;p&gt;Do you know how to import something from a module or a package? Do you know that you can import variables, functions, classes, as well as other modules and packages?&lt;/p&gt;

&lt;p&gt;Do you know at least one way to install a Python library?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;7. Object-oriented programming&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Do you know what a class is?&lt;/p&gt;

&lt;p&gt;Do you know what an object is?&lt;/p&gt;

&lt;p&gt;Do you know how to write a class?&lt;/p&gt;

&lt;p&gt;Do you know what &lt;code&gt;__init__ ()&lt;/code&gt; does?&lt;/p&gt;

&lt;p&gt;Do you know the difference between a function and a method?&lt;/p&gt;

&lt;p&gt;Do you know how to instantiate a class to create an object?&lt;/p&gt;

&lt;p&gt;Do you know what inheritance is, and how to write a class that inherits from another class?&lt;/p&gt;

&lt;p&gt;Do you know what a mixin is and how to use it? (Optional)&lt;/p&gt;

&lt;h2&gt;
  
  
  That's all!
&lt;/h2&gt;

&lt;p&gt;That's the minimum, I believe, that you need to know about Python to work with Django at a basic level.&lt;/p&gt;

&lt;p&gt;I say "minimum", but don't let that fool you! Most of the time, everything contained in the list above is more than sufficient to write a Django application.&lt;/p&gt;

&lt;p&gt;In fact a lot of the production code I've seen rarely deviates from the list above.&lt;/p&gt;

&lt;p&gt;So, there's a lot of things there.&lt;/p&gt;

&lt;p&gt;If you already know everything there, congratulations!&lt;/p&gt;

&lt;p&gt;Otherwise, I recommend working on it step-by-step, as mentioned, in the same order as above.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping up
&lt;/h2&gt;

&lt;p&gt;I'm planning to make cheat sheets of useful tips like this. If you found this helpful, make sure to sign up for my mailing list to receive them!&lt;/p&gt;

</description>
      <category>django</category>
      <category>python</category>
    </item>
    <item>
      <title>Options for public facing IDs in Django</title>
      <dc:creator>spikelantern</dc:creator>
      <pubDate>Fri, 26 Jun 2020 00:00:00 +0000</pubDate>
      <link>https://dev.to/spikelanterncom/options-for-public-facing-ids-in-django-1i3c</link>
      <guid>https://dev.to/spikelanterncom/options-for-public-facing-ids-in-django-1i3c</guid>
      <description>&lt;p&gt;Django uses auto-incrementing integer columns as primary keys for models by default. If you've done some basic tutorials you may have used these integer IDs as identifiers in URLs or HTTP responses.&lt;/p&gt;

&lt;p&gt;For example, things like &lt;code&gt;/posts/23/&lt;/code&gt; where &lt;code&gt;23&lt;/code&gt; is the primary key of a &lt;code&gt;Post&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;At some point you may have read or received advice that it's probably not that good to use these auto-incrementing IDs publicly. One reason is that it leaks information about the size of database table, which may be undesirable for a few reasons (like leaking information to competitors, or even a potential attacker). Additionally, it's easy for a potential attacker to guess, and if you don't secure your endpoints properly you may be more vulnerable to some &lt;a href="https://portswigger.net/web-security/access-control/idor"&gt;IDOR-type situations&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Have you wondered what you can use instead? Luckily, you have a few good alternatives.&lt;/p&gt;

&lt;h2&gt;
  
  
  Maybe just use another unique field as an identifier
&lt;/h2&gt;

&lt;p&gt;Using another unique field is the most straightforward approach, assuming it's URL-safe. For example, for a profile page in a social networking platform, you could simply use the username.&lt;/p&gt;

&lt;p&gt;Both Twitter and Instagram does this, as well as most social networking sites I'm aware of, e.g.:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://twitter.com/spikelanterncom"&gt;https://twitter.com/spikelanterncom&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Slugs
&lt;/h2&gt;

&lt;p&gt;In many cases it may be appropriate to use something called a "slug". Django has a built-in field for this called &lt;a href="https://docs.djangoproject.com/en/3.0/ref/models/fields/#slugfield"&gt;&lt;code&gt;SlugField&lt;/code&gt;&lt;/a&gt;, and in their documentation they have a good definition for what a slug is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://docs.djangoproject.com/en/3.0/glossary/#term-slug"&gt;Slug&lt;/a&gt; is a newspaper term. A slug is a short label for something, containing only letters, numbers, underscores or hyphens. They’re generally used in URLs.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So, if you have something that can naturally fits well to slugs, such as articles, blog posts, and anything with a unique title, slugs might be a decent option.&lt;/p&gt;

&lt;h2&gt;
  
  
  UUIDs
&lt;/h2&gt;

&lt;p&gt;Another option is to use Django's &lt;a href="https://docs.djangoproject.com/en/3.0/ref/models/fields/#uuidfield"&gt;built-in &lt;code&gt;UUIDField&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;What does a UUID look like? You can generate one yourself by firing up the Python REPL and running this code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; import uuid
&amp;gt;&amp;gt;&amp;gt; my_uuid = uuid.uuid4()
&amp;gt;&amp;gt;&amp;gt; print(my_uuid)
f22db40f-3e1e-4ac2-9c10-62ecea301f5e

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;These are URL-safe, that means you can safely put them in URLs.&lt;/p&gt;

&lt;p&gt;So instead of &lt;code&gt;/products/23/&lt;/code&gt; you'll see &lt;code&gt;/products/f22db40f-3e1e-4ac2-9c10-62ecea301f5e/&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;It's kind of ugly, but not too bad. To make it shorter, you can run something like a base62 or base58 encoding on the UUID to produce a more compact string. The &lt;code&gt;django-extensions&lt;/code&gt; library does this in &lt;code&gt;ShortUUIDField&lt;/code&gt; (more on that later).&lt;/p&gt;

&lt;p&gt;Note that if you do this you should keep using &lt;code&gt;UUIDField&lt;/code&gt;, and not use &lt;code&gt;CharField&lt;/code&gt;, see &lt;a href="https://tomharrisonjr.com/uuid-or-guid-as-primary-keys-be-careful-7b2aa3dcb439"&gt;this blog post for a good discussion&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Base64 encode a few bytes from &lt;code&gt;/dev/urandom&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;You could also grab a few bytes from &lt;code&gt;/dev/urandom&lt;/code&gt; and do a url-safe base64 encoding.&lt;/p&gt;

&lt;p&gt;How many bytes are enough? I recently found this fantastic article from Neil Madden, titled &lt;a href="https://neilmadden.blog/2018/08/30/moving-away-from-uuids/"&gt;"Moving away from UUIDs"&lt;/a&gt; which compared this method to using UUIDs, and using some math, determined that using 160 bits (20 bytes) is a good option for general random strings like access tokens.&lt;/p&gt;

&lt;p&gt;For an identifier, you could probably use something much shorter, but I found that 160 bits works okay for URLs anyway, and is still shorter than the standard representation of UUIDs. UUIDs can also be shorter if you also encode them, as they are also just strings representing 128 bits. We'll see options for that later in this article.&lt;/p&gt;

&lt;p&gt;Here's some code to generate such a random string:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import os
from django.utils.http import urlsafe_base64_encode as b64encode

def generate_random_field(bytes=20):
    return b64encode(os.urandom(bytes))

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Try running that on your Python shell:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; generate_random_field()
'OVXxfipWi2VdPC8GGCKmlR6oDhc'
&amp;gt;&amp;gt;&amp;gt; generate_random_field()
'8ApcI0mvC_a_MTJN8Hj4um_DAsQ'
&amp;gt;&amp;gt;&amp;gt; generate_random_field()
'W9myCGsv93zo0vk5x9rLyd9cwI0'

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The result is a 27 character string, which you could just put in a &lt;code&gt;CharField&lt;/code&gt;, but you probably want to write a custom field like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import os
from django.db.models import CharField
from django.utils.http import urlsafe_base64_encode as b64encode

def generate_random_field():
    return b64encode(os.urandom(20))

class RandomIDField(CharField):
    description = "A random field meant for URL-safe identifiers"

    def __init__ (self, **kwargs):
        kwargs['max_length'] = 27

        super(). __init__ (**kwargs)

    def deconstruct(self):
        name, path, args, kwargs = super().deconstruct()
        del kwargs["max_length"]

        return name, path, args, kwargs

    def pre_save(self, model_instance, add):
        """
        This is used to ensure that we auto-set values if required.
        See CharField.pre_save
        """
        value = super().pre_save(model_instance, add)
        if not value:
            value = generate_random_field()
            setattr(model_instance, self.attname, value)
        return value

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Note that the above is for the specific case of 20 bytes, and I didn't bother including any configuration options. If you want to configure this field by passing in the number of bytes you want, you might want to modify the code.&lt;/p&gt;

&lt;p&gt;I would recommend just copying that code to your project directly and modifying as needed, but if for some reason you want it in a package, I have published it to PyPI. You can see the code here: &lt;a href="https://github.com/spikelantern/django-randomcharfield"&gt;https://github.com/spikelantern/django-randomcharfield&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The resulting string can have hyphens and underscores, which you might be okay with, or not. I've personally found that this is a very simple method that is acceptable for most of my needs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Use &lt;code&gt;django-extensions&lt;/code&gt; fields
&lt;/h2&gt;

&lt;p&gt;The popular package &lt;a href="https://django-extensions.readthedocs.io/en/latest/"&gt;&lt;code&gt;django-extensions&lt;/code&gt;&lt;/a&gt; has a few options for such fields.&lt;/p&gt;

&lt;p&gt;If you look at the documentation for &lt;a href="https://django-extensions.readthedocs.io/en/latest/field_extensions.html"&gt;field extensions&lt;/a&gt; you will find several options you can use.&lt;/p&gt;

&lt;p&gt;Particularly they have options for &lt;code&gt;ShortUUIDField&lt;/code&gt; and &lt;code&gt;RandomCharField&lt;/code&gt; (and &lt;code&gt;AutoSlugField&lt;/code&gt; if you want to automate the generation of slug fields).&lt;/p&gt;

&lt;p&gt;Their implementation of &lt;code&gt;RandomCharField&lt;/code&gt; chooses from a limited set of characters randomly, and thus can be configured to not use any hyphens or underscores.&lt;/p&gt;

&lt;h3&gt;
  
  
  Tip: You don't need to replace your primary key
&lt;/h3&gt;

&lt;p&gt;By the way, even if you choose any of these options, you don't need to replace your default primary key. An auto-incrementing integer as your primary key has some benefits, like being easy to sort (e.g. if you don't have a timestamp for when the entry is added). Also it's compact, and easy to work with in, say, the Django admin.&lt;/p&gt;

&lt;p&gt;What you can do is add a second field to your model which you use for anything external, and keep using &lt;code&gt;AutoField&lt;/code&gt; for your internal operations.&lt;/p&gt;

&lt;h3&gt;
  
  
  Tip: Look at your responses too
&lt;/h3&gt;

&lt;p&gt;Make sure you remove the auto-incrementing IDs from HTTP responses as well. It's pointless to just change your URLs to hide the IDs, only to leak them somewhere else!&lt;/p&gt;

&lt;h2&gt;
  
  
  Takeaways
&lt;/h2&gt;

&lt;p&gt;You have a number of options if you are concerned about revealing auto-incrementing IDs publicly (e.g. in URLs).&lt;/p&gt;

&lt;p&gt;If you already have an existing unique field that can be public (e.g. a username), then that is normally a good option to use. Slugs can be good options for when you have a resource that fits well such as articles or blog posts. Both of these options will give you nice, human-readable URLs.&lt;/p&gt;

&lt;p&gt;Some other alternatives discussed were UUIDs and random character fields, by either writing your own custom field, or using a library like &lt;code&gt;django-extensions&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Hope you found this post helpful! If you enjoyed this, please subscribe to my mailing list and receive some very occasional emails about Django.&lt;/p&gt;

</description>
      <category>django</category>
      <category>python</category>
    </item>
    <item>
      <title>How to choose your next Django project</title>
      <dc:creator>spikelantern</dc:creator>
      <pubDate>Sun, 14 Jun 2020 00:00:00 +0000</pubDate>
      <link>https://dev.to/spikelanterncom/how-to-choose-your-next-django-project-52fn</link>
      <guid>https://dev.to/spikelanterncom/how-to-choose-your-next-django-project-52fn</guid>
      <description>&lt;p&gt;Have you done a couple of Django tutorials? Maybe you've already done &lt;a href="https://docs.djangoproject.com/en/3.0/intro/tutorial01/"&gt;Django's official Polls tutorial&lt;/a&gt;, as well as the &lt;a href="https://tutorial.djangogirls.org/en/"&gt;DjangoGirls tutorial&lt;/a&gt;. You're now wondering what to do next to get better.&lt;/p&gt;

&lt;p&gt;So you go on the internet, and ask people what to do. More likely than not, they'll answer with some variation of "start doing projects" and "learn by doing".&lt;/p&gt;

&lt;p&gt;But if you're a fairly new to web development or even programming, it may be difficult to come up with project ideas.&lt;/p&gt;

&lt;p&gt;For example, you may be worried if a project idea may be beyond your abilities at this moment, and you might be worried that if it's too difficult you might just give up. Worse, you might give up forever.&lt;/p&gt;

&lt;p&gt;When you're new to web development, it's hard to gauge if a project idea is too difficult or not. In fact, even more experienced developers often underestimate the difficulty of some projects.&lt;/p&gt;

&lt;p&gt;So what should you do? Wouldn't it be great if there was a way to get better through "learning by doing" but not pick a project that may overwhelm you, potentially turning you away from web development?&lt;/p&gt;

&lt;h2&gt;
  
  
  Your goal is to get better
&lt;/h2&gt;

&lt;p&gt;The first thing is to examine your goals. Is your goal to finish a project, or to get better at Django and web development?&lt;/p&gt;

&lt;p&gt;There is a lot of value in completing a project. You get a sense of achievement, and can tell people "hey, look at this cool thing I built". It's definitely rewarding. If you're able to complete something, you definitely deserve to be applauded.&lt;/p&gt;

&lt;p&gt;But ultimately, that's just one project. It may be rewarding, but at some point you want to be able to build more than one type of web application.&lt;/p&gt;

&lt;p&gt;Think of a piano player who is only able to play one tune. Sure, they'd be able to impress people when they need to perform, and that's pretty cool. But at some point they will need to move beyond that. In order to learn other tunes and play them well, they will need to get better at playing the piano in general.&lt;/p&gt;

&lt;p&gt;People have known this for centuries, which is why many composers wrote didactic pieces – pieces of music meant to make you practice and get better. If you have any experience with the piano, you may have heard of compositions from Hanon and Czerny, and also etudes from many composers like Chopin.&lt;/p&gt;

&lt;p&gt;Each &lt;a href="https://en.wikipedia.org/wiki/The_Virtuoso_Pianist_in_60_Exercises"&gt;Hanon piece&lt;/a&gt;, for example, aims to train your hands to play a certain type of movement or phrase. Like arpeggios, or scales, or parallel thirds.&lt;/p&gt;

&lt;p&gt;It's helpful to learn how to play arpeggios, for instance, because many compositions have arpeggios.&lt;/p&gt;

&lt;p&gt;Nobody would want to be performing a Hanon piece at a concert. They're not very nice to listen to, and they're things you mostly play at home to practice. Once you get better at the areas they're meant to improve, they've served their purpose, and then you can move on to expanding your repertoire.&lt;/p&gt;

&lt;h2&gt;
  
  
  Maybe you should do some Hanon
&lt;/h2&gt;

&lt;p&gt;The equivalent for web development and Django, in my opinion, is to do some things I like to call "microprojects".&lt;/p&gt;

&lt;p&gt;They're extremely small projects, rather than a full web application, where the aim is to learn about a specific area, rather than to produce something useful.&lt;/p&gt;

&lt;p&gt;So rather than "build a Twitter clone", you can build parts or components of things you see on Twitter or other websites.&lt;/p&gt;

&lt;p&gt;Let me give you an example. You may have noticed many websites with "infinite scroll". That means when you scroll down to the end of a feed, or a list, you see that the website automatically fetches new items.&lt;/p&gt;

&lt;p&gt;No idea how to do that? Well, that's a great idea for your next project.&lt;/p&gt;

&lt;p&gt;Start a new Django project, with one model (e.g. a &lt;code&gt;Tweet&lt;/code&gt; model).&lt;/p&gt;

&lt;p&gt;Use Django Admin or the shell to create 50 or so tweets. Figure out how to display 5 tweets at first. Then figure out how to make it progressively load more tweets when you scroll to the bottom, or when you click "load more".&lt;/p&gt;

&lt;p&gt;Don't worry about authentication, user permissions, any of that other crap. Your goal is to get infinite scroll working. You can worry about that other stuff in other projects.&lt;/p&gt;

&lt;p&gt;If you've never built something with infinite scroll before, that may be just challenging enough for you, but with the advantage that it's small and focused, so that you never get overwhelmed.&lt;/p&gt;

&lt;p&gt;Now, consider this: once you're able to build this yourself, and understand how it works, you're now capable of doing infinite scroll in any web application. That's extremely valuable. &lt;em&gt;You're now able to play arpeggios in other compositions&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Does it matter if it's not a polished project? Nope, at this point it has served its purpose, and you can just shelve your project away for your own reference without ever having to show anyone.&lt;/p&gt;

&lt;p&gt;That also means the bar can be as low as you want. Is your design and CSS shitty? Who cares? You don't have to show anyone. If you just keep it hidden, there is no opportunity for embarrassment.&lt;/p&gt;

&lt;h2&gt;
  
  
  Examples of microprojects
&lt;/h2&gt;

&lt;p&gt;So here's a few more microproject ideas apart from infinite scroll:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;AJAX forms&lt;/li&gt;
&lt;li&gt;Multi-step forms or wizards&lt;/li&gt;
&lt;li&gt;An "add to cart" feature&lt;/li&gt;
&lt;li&gt;Generating a PDF invoice&lt;/li&gt;
&lt;li&gt;Sending an email in an automated fashion&lt;/li&gt;
&lt;li&gt;Searching for an item based on some keyword or criteria&lt;/li&gt;
&lt;li&gt;An auto-updating news feed&lt;/li&gt;
&lt;li&gt;An application and approval workflow&lt;/li&gt;
&lt;li&gt;Accepting payments via Stripe or Braintree for a single product&lt;/li&gt;
&lt;li&gt;A simple dashboard with relevant statistics (graphs, pivot table, etc.)&lt;/li&gt;
&lt;li&gt;Auto-processing a user-uploaded image&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That's just off the top of my head. By the way, these are all components of real projects I've done for money. I'd go out on a limb and predict that you will encounter at least one of the tasks in that list in your career as a software developer.&lt;/p&gt;

&lt;p&gt;But if you run out of ideas, you could always look for inspiration in any website or web application you use.&lt;/p&gt;

&lt;p&gt;Did you see a cool feature on Twitter, Instagram, or even JIRA? Try replicating it in a microproject!&lt;/p&gt;

&lt;p&gt;You don't have to replicate it fully, just try to do the simplest possible approximation of that feature.&lt;/p&gt;

&lt;h2&gt;
  
  
  When you should try microprojects
&lt;/h2&gt;

&lt;p&gt;Ultimately, everyone's learning style is different. It may be that you actually learn better and are able to keep your motivation better when you're doing a full project.&lt;/p&gt;

&lt;p&gt;If that's you, then please don't let this blog post deter you. By all means do a full project.&lt;/p&gt;

&lt;p&gt;But if you get stuck, you could always do some explorations with microprojects in the thing you're stuck on. I've found that helpful.&lt;/p&gt;

&lt;p&gt;Maybe you've already attempted doing full projects a couple of times but never completed them because you always found the experience overwhelming. I know when I started of as a programmer, that happened a lot, and was the source of a significant amount of personal frustration. Microprojects helped me get better.&lt;/p&gt;

&lt;p&gt;Ultimately, doing microprojects is just a tool I've used in the past to learn about new concepts in a safe manner. It's a tool to consider, if you find it useful. If you don't find it useful, by all means do what works better for you.&lt;/p&gt;

&lt;h2&gt;
  
  
  Takeaways
&lt;/h2&gt;

&lt;p&gt;So to summarise:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Doing a full blown project can be overwhelming if there are too many unfamiliar components&lt;/li&gt;
&lt;li&gt;Microprojects, or small focused projects aimed to increase your understanding of a certain area (e.g. infinite scroll) can be helpful&lt;/li&gt;
&lt;li&gt;For inspiration, you could always look at other web applications&lt;/li&gt;
&lt;li&gt;Micoprojects are helpful when you get stuck doing full projects too&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>django</category>
    </item>
  </channel>
</rss>
