<?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: Idiomatic Programmers</title>
    <description>The latest articles on DEV Community by Idiomatic Programmers (@idiomprog).</description>
    <link>https://dev.to/idiomprog</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%2Forganization%2Fprofile_image%2F4722%2Faa91805d-5eed-4e69-852a-706409ad2e59.png</url>
      <title>DEV Community: Idiomatic Programmers</title>
      <link>https://dev.to/idiomprog</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/idiomprog"/>
    <language>en</language>
    <item>
      <title>Ultimate Redis Cheatsheet</title>
      <dc:creator>Idiomatic Programmers</dc:creator>
      <pubDate>Thu, 27 Jul 2023 11:44:02 +0000</pubDate>
      <link>https://dev.to/idiomprog/ultimate-redis-cheatsheet-484d</link>
      <guid>https://dev.to/idiomprog/ultimate-redis-cheatsheet-484d</guid>
      <description>&lt;h2&gt;
  
  
  What is Redis?
&lt;/h2&gt;

&lt;p&gt;Redis, which stands for Remote Dictionary Server, is an open-source, in-memory data structure store that serves as a highly efficient and versatile database solution. Developed by Salvatore Sanfilippo, Redis is designed to offer lightning-fast data access and retrieval by keeping all the data in memory rather than on disk, ensuring remarkable performance and responsiveness.&lt;/p&gt;

&lt;p&gt;One of the key features that sets Redis apart is its support for various data structures, including strings, lists, sets, sorted sets, and hashes. This versatility enables Redis to serve multiple purposes, such as acting as a key-value store, a message broker, or a caching layer.&lt;/p&gt;

&lt;p&gt;Redis utilizes an in-memory approach, making it exceptionally fast for read and write operations. With its optimized data structures and efficient algorithms, Redis can process data in sub-millisecond response times, making it an ideal choice for real-time applications and use cases that require high-performance data manipulation.&lt;/p&gt;

&lt;p&gt;Furthermore, Redis offers persistence options, allowing users to store their data on disk periodically or whenever specific conditions are met. This feature ensures data durability and makes Redis suitable for applications that require both speed and data persistence.&lt;/p&gt;

&lt;p&gt;In addition to its exceptional performance, Redis provides advanced features like pub/sub messaging, transactions, and Lua scripting, which empower developers to build complex applications and systems with ease.&lt;/p&gt;

&lt;p&gt;Redis has become immensely popular due to its simplicity, versatility, and extensive support for multiple programming languages. It offers client libraries for various languages, making it accessible and easy to integrate into different software stacks.&lt;/p&gt;

&lt;p&gt;Whether you need to cache frequently accessed data, build real-time applications, implement a messaging system, or store and process complex data structures, Redis provides a robust and efficient solution that continues to be widely adopted across industries.&lt;/p&gt;

&lt;p&gt;In conclusion, Redis is a powerful and flexible database solution that excels in performance, versatility, and ease of use. Its in-memory nature, support for various data structures, and extensive feature set make it a go-to choice for developers looking to build high-performance applications and systems.&lt;/p&gt;

&lt;h2&gt;
  
  
  How Redis is different from other Databases?
&lt;/h2&gt;

&lt;p&gt;Redis differs from other databases in several key aspects:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;In-Memory Data Storage&lt;/strong&gt;: Redis primarily stores data in memory, allowing for extremely fast read and write operations. This design choice sets Redis apart from traditional disk-based databases that incur disk I/O overhead. By keeping data in memory, Redis can achieve high throughput and low latency, making it well-suited for applications that require real-time data processing and high-performance caching.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Data Structures&lt;/strong&gt;: Redis supports a wide range of data structures, including strings, lists, sets, hashes, and sorted sets. This flexibility allows developers to model complex data scenarios efficiently. Unlike many other databases that offer a fixed schema, Redis provides dynamic and versatile data structures that can be manipulated and combined to suit specific application needs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Built-in Caching Mechanisms&lt;/strong&gt;: Redis has native support for caching, making it an excellent choice for scenarios that require frequent access to frequently accessed data. With features like key expiration and eviction policies, Redis can efficiently manage cache storage and ensure that the most relevant data remains readily available.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pub/Sub Messaging&lt;/strong&gt;: Redis includes built-in publish/subscribe messaging capabilities. This feature allows applications to implement real-time messaging and event-driven architectures. Publishers can send messages to specific channels, and subscribers receive messages from those channels in real-time. This makes Redis a suitable choice for building chat systems, real-time analytics, and other applications that require event-based communication.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Lua Scripting&lt;/strong&gt;: Redis supports Lua scripting, which enables developers to execute server-side scripts directly within the database. This allows for complex operations and transactional logic to be performed within Redis, reducing the need for round-trips between the application and the database. Lua scripting enhances Redis's flexibility and extensibility by enabling custom behaviour and complex data manipulations.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Replication and Persistence&lt;/strong&gt;: Redis provides built-in replication mechanisms for creating multiple copies of the database. This replication ensures high availability and fault tolerance by propagating changes from a master node to one or more slave nodes. Redis also offers persistence options through snapshotting and append-only file (AOF) logging, allowing data to be saved to disk for recovery in the event of a system failure.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Simplicity and Performance&lt;/strong&gt;: Redis is known for its simplicity and performance. It offers a straightforward set of commands that are easy to understand and use. The focus on in-memory storage and the absence of complex query languages or indexing mechanisms simplify the database's design and contribute to its exceptional performance.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Overall, Redis stands out among other databases due to its in-memory storage, versatile data structures, caching capabilities, pub/sub messaging, Lua scripting, replication, and performance-oriented design. These features make Redis a popular choice for applications that require speed, flexibility, and real-time data processing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Installing Redis and Redis CLI
&lt;/h2&gt;

&lt;p&gt;Here are the steps to install Redis on Linux, macOS, and Windows:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Linux:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open a terminal window.&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Update the package manager:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt update
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Install Redis:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;redis-server
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Start the Redis service:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl start redis-server
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;To access the Redis command-line interface (redis-cli):&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;redis-cli
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;macOS:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open a terminal window.&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Install Homebrew (if not already installed):&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;/bin/bash &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;curl &lt;span class="nt"&gt;-fsSL&lt;/span&gt; https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Install Redis using Homebrew:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;brew &lt;span class="nb"&gt;install &lt;/span&gt;redis
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Start the Redis service:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;brew services start redis
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;To access the Redis command-line interface (redis-cli):&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;redis-cli
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Windows:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Download the latest Redis for Windows from the Microsoft Open Tech GitHub repository: &lt;strong&gt;&lt;a href="https://github.com/microsoftarchive/redis/releases"&gt;https://github.com/microsoftarchive/redis/releases&lt;/a&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Extract the downloaded archive to a directory of your choice, e.g., &lt;strong&gt;&lt;code&gt;C:\Redis&lt;/code&gt;&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Open a Command Prompt window.&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Navigate to the Redis installation directory:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;C:&lt;span class="se"&gt;\R&lt;/span&gt;edis
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Start the Redis server:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;redis-server.exe
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Open another Command Prompt window to access the Redis command-line interface (redis-cli):&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;C:&lt;span class="se"&gt;\R&lt;/span&gt;edis
redis-cli.exe
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Please note that for Linux and macOS, the installation steps assume the usage of package managers like &lt;strong&gt;&lt;code&gt;apt&lt;/code&gt;&lt;/strong&gt; and Homebrew, respectively. If you are using a different package manager or distribution, you may need to adjust the installation commands accordingly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Commands
&lt;/h2&gt;

&lt;h3&gt;
  
  
  SET manipulation
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;SET&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Command: &lt;strong&gt;&lt;code&gt;SET&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Syntax: &lt;strong&gt;&lt;code&gt;SET key value&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Usage: &lt;strong&gt;&lt;code&gt;SET myset "Hello Redis"&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Description: Sets the value of a key with the provided string value. If the key already exists, it overwrites the existing value. This command is also used to create a new key-value pair if the key doesn't exist.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;GET&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Command: &lt;strong&gt;&lt;code&gt;GET&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Syntax: &lt;strong&gt;&lt;code&gt;GET key&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Usage: &lt;strong&gt;&lt;code&gt;GET myset&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Description: Retrieves the value associated with the specified key. If the key exists, the command returns the value; otherwise, it returns &lt;strong&gt;&lt;code&gt;nil&lt;/code&gt;&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;SADD&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Command: &lt;strong&gt;&lt;code&gt;SADD&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Syntax: &lt;strong&gt;&lt;code&gt;SADD key member [member ...]&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Usage: &lt;strong&gt;&lt;code&gt;SADD myset "value1" "value2"&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Description: Adds one or more members to a set. If the members already exist, they are ignored. If the key doesn't exist, a new set is created with the specified members.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;SMEMBERS&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Command: &lt;strong&gt;&lt;code&gt;SMEMBERS&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Syntax: &lt;strong&gt;&lt;code&gt;SMEMBERS key&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Usage: &lt;strong&gt;&lt;code&gt;SMEMBERS myset&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Description: Returns all the members of a set. If the key doesn't exist, an empty set is returned.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;SISMEMBER&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Command: &lt;strong&gt;&lt;code&gt;SISMEMBER&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Syntax: &lt;strong&gt;&lt;code&gt;SISMEMBER key member&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Usage: &lt;strong&gt;&lt;code&gt;SISMEMBER myset "value1"&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Description: Checks if a member exists in a set. Returns &lt;strong&gt;&lt;code&gt;1&lt;/code&gt;&lt;/strong&gt; if the member is present; otherwise, returns &lt;strong&gt;&lt;code&gt;0&lt;/code&gt;&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;SREM&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Command: &lt;strong&gt;&lt;code&gt;SREM&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Syntax: &lt;strong&gt;&lt;code&gt;SREM key member [member ...]&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Usage: &lt;strong&gt;&lt;code&gt;SREM myset "value1" "value2"&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Description: Removes one or more members from a set. If the members don't exist, they are ignored. If the key becomes empty after removing members, the key is also removed.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;SCARD&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Command: &lt;strong&gt;&lt;code&gt;SCARD&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Syntax: &lt;strong&gt;&lt;code&gt;SCARD key&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Usage: &lt;strong&gt;&lt;code&gt;SCARD myset&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Description: Returns the cardinality (number of members) of a set. If the key doesn't exist, &lt;strong&gt;&lt;code&gt;0&lt;/code&gt;&lt;/strong&gt; is returned.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;SINTER&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Command: &lt;strong&gt;&lt;code&gt;SINTER&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Syntax: &lt;strong&gt;&lt;code&gt;SINTER key [key ...]&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Usage: &lt;strong&gt;&lt;code&gt;SINTER myset1 myset2&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Description: Returns the intersection of multiple sets. Only the members that exist in all the specified sets are included in the result set.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;SUNION&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Command: &lt;strong&gt;&lt;code&gt;SUNION&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Syntax: &lt;strong&gt;&lt;code&gt;SUNION key [key ...]&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Usage: &lt;strong&gt;&lt;code&gt;SUNION myset1 myset2&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Description: Returns the union of multiple sets. All the members from the specified sets are included in the result set.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;SDIFF&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Command: &lt;strong&gt;&lt;code&gt;SDIFF&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Syntax: &lt;strong&gt;&lt;code&gt;SDIFF key [key ...]&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Usage: &lt;strong&gt;&lt;code&gt;SDIFF myset1 myset2&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Description: Returns the difference between two sets. The members that exist in the first set but not in any other specified sets are included in the result set.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Sorted Sets manipulation&lt;/strong&gt;
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;ZADD&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Command: &lt;strong&gt;&lt;code&gt;ZADD&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Syntax: &lt;strong&gt;&lt;code&gt;ZADD key [NX|XX] [CH] [INCR] score member [score member ...]&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Usage: &lt;strong&gt;&lt;code&gt;ZADD mysortedset 1 "value1" 2 "value2"&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Description: Adds one or more members with scores to a sorted set. If a member already exists, its score is updated. Additional options like &lt;strong&gt;&lt;code&gt;NX&lt;/code&gt;&lt;/strong&gt; (only add new elements), &lt;strong&gt;&lt;code&gt;XX&lt;/code&gt;&lt;/strong&gt; (only update existing elements), &lt;strong&gt;&lt;code&gt;CH&lt;/code&gt;&lt;/strong&gt; (return the number of changed elements), and &lt;strong&gt;&lt;code&gt;INCR&lt;/code&gt;&lt;/strong&gt; (increment the score of existing member) can be specified.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;ZSCORE&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Command: &lt;strong&gt;&lt;code&gt;ZSCORE&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Syntax: &lt;strong&gt;&lt;code&gt;ZSCORE key member&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Usage: &lt;strong&gt;&lt;code&gt;ZSCORE mysortedset "value1"&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Description: Returns the score of a member in a sorted set. If the member doesn't exist, &lt;strong&gt;&lt;code&gt;nil&lt;/code&gt;&lt;/strong&gt; is returned.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;ZRANGE&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Command: &lt;strong&gt;&lt;code&gt;ZRANGE&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Syntax: &lt;strong&gt;&lt;code&gt;ZRANGE key start stop [WITHSCORES]&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Usage: &lt;strong&gt;&lt;code&gt;ZRANGE mysortedset 0 -1&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Description: Returns a range of members from a sorted set based on their position. The &lt;strong&gt;&lt;code&gt;start&lt;/code&gt;&lt;/strong&gt; and &lt;strong&gt;&lt;code&gt;stop&lt;/code&gt;&lt;/strong&gt; arguments specify the inclusive range of positions. The optional &lt;strong&gt;&lt;code&gt;WITHSCORES&lt;/code&gt;&lt;/strong&gt; flag includes the scores in the result.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;ZREVRANGE&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Command: &lt;strong&gt;&lt;code&gt;ZREVRANGE&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Syntax: &lt;strong&gt;&lt;code&gt;ZREVRANGE key start stop [WITHSCORES]&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Usage: &lt;strong&gt;&lt;code&gt;ZREVRANGE mysortedset 0 -1 WITHSCORES&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Description: Returns a range of members from a sorted set in reverse order based on their position. The &lt;strong&gt;&lt;code&gt;start&lt;/code&gt;&lt;/strong&gt; and &lt;strong&gt;&lt;code&gt;stop&lt;/code&gt;&lt;/strong&gt; arguments specify the inclusive range of positions. The optional &lt;strong&gt;&lt;code&gt;WITHSCORES&lt;/code&gt;&lt;/strong&gt; flag includes the scores in the result.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;ZREM&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Command: &lt;strong&gt;&lt;code&gt;ZREM&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Syntax: &lt;strong&gt;&lt;code&gt;ZREM key member [member ...]&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Usage: &lt;strong&gt;&lt;code&gt;ZREM mysortedset "value1" "value2"&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Description: Removes one or more members from a sorted set. If a member doesn't exist, it is ignored. If the key becomes empty after removing members, the key is also removed.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;ZCARD&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Command: &lt;strong&gt;&lt;code&gt;ZCARD&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Syntax: &lt;strong&gt;&lt;code&gt;ZCARD key&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Usage: &lt;strong&gt;&lt;code&gt;ZCARD mysortedset&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Description: Returns the cardinality (number of members) of a sorted set. If the key doesn't exist, &lt;strong&gt;&lt;code&gt;0&lt;/code&gt;&lt;/strong&gt; is returned.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;ZCOUNT&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Command: &lt;strong&gt;&lt;code&gt;ZCOUNT&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Syntax: &lt;strong&gt;&lt;code&gt;ZCOUNT key min max&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Usage: &lt;strong&gt;&lt;code&gt;ZCOUNT mysortedset 1 10&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Description: Returns the count of members in a sorted set within the specified score range (&lt;strong&gt;&lt;code&gt;min&lt;/code&gt;&lt;/strong&gt; and &lt;strong&gt;&lt;code&gt;max&lt;/code&gt;&lt;/strong&gt; inclusive).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;ZRANK&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Command: &lt;strong&gt;&lt;code&gt;ZRANK&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Syntax: &lt;strong&gt;&lt;code&gt;ZRANK key member&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Usage: &lt;strong&gt;&lt;code&gt;ZRANK mysortedset "value1"&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Description: Returns the position (rank) of a member in a sorted set when sorted in ascending order. The lowest rank is &lt;strong&gt;&lt;code&gt;0&lt;/code&gt;&lt;/strong&gt;. If the member doesn't exist, &lt;strong&gt;&lt;code&gt;nil&lt;/code&gt;&lt;/strong&gt; is returned.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;ZREVRANK&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Command: &lt;strong&gt;&lt;code&gt;ZREVRANK&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Syntax: &lt;strong&gt;&lt;code&gt;ZREVRANK key member&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Usage: &lt;strong&gt;&lt;code&gt;ZREVRANK mysortedset "value1"&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Description: Returns the position (rank) of a member in a sorted set when sorted in descending order. The highest rank is &lt;strong&gt;&lt;code&gt;0&lt;/code&gt;&lt;/strong&gt;. If the member doesn't exist, &lt;strong&gt;&lt;code&gt;nil&lt;/code&gt;&lt;/strong&gt; is returned.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;ZINCRBY&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Command: &lt;strong&gt;&lt;code&gt;ZINCRBY&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Syntax: &lt;strong&gt;&lt;code&gt;ZINCRBY key increment member&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Usage: &lt;strong&gt;&lt;code&gt;ZINCRBY mysortedset 5 "value1"&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Description: Increments the score of a member in a sorted set by the specified increment. If the member doesn't exist, it is added with the initial score as the increment value.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  String, Number and Bit Manipulation
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;APPEND&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Command: &lt;strong&gt;&lt;code&gt;APPEND&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Syntax: &lt;strong&gt;&lt;code&gt;APPEND key value&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Usage: &lt;strong&gt;&lt;code&gt;APPEND mykey "world"&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Description: Appends the specified value to the string value already stored at the key. If the key doesn't exist, a new key is created with the specified value.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;BITCOUNT&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Command: &lt;strong&gt;&lt;code&gt;BITCOUNT&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Syntax: &lt;strong&gt;&lt;code&gt;BITCOUNT key [start end]&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Usage: &lt;strong&gt;&lt;code&gt;BITCOUNT mykey&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Description: Counts the number of set bits (1s) in a string value. Optionally, a range can be specified to count the bits within that range.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;BITOP&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Command: &lt;strong&gt;&lt;code&gt;BITOP&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Syntax: &lt;strong&gt;&lt;code&gt;BITOP operation destkey key [key ...]&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Usage: &lt;strong&gt;&lt;code&gt;BITOP AND destkey key1 key2&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Description: Performs a bitwise operation (AND, OR, XOR, NOT) between multiple keys and stores the result in the destination key.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;BITPOS&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Command: &lt;strong&gt;&lt;code&gt;BITPOS&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Syntax: &lt;strong&gt;&lt;code&gt;BITPOS key bit [start] [end]&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Usage: &lt;strong&gt;&lt;code&gt;BITPOS mykey 1 0 10&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Description: Finds the position of the first set bit (1) or clear bit (0) in a string value. Optionally, a range can be specified to search for the bit within that range.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;DECR&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Command: &lt;strong&gt;&lt;code&gt;DECR&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Syntax: &lt;strong&gt;&lt;code&gt;DECR key&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Usage: &lt;strong&gt;&lt;code&gt;DECR mykey&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Description: Decrements the value of the key by 1. If the key doesn't exist, it is initialized with the value of 0 before decrementing.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;DECRBY&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Command: &lt;strong&gt;&lt;code&gt;DECRBY&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Syntax: &lt;strong&gt;&lt;code&gt;DECRBY key decrement&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Usage: &lt;strong&gt;&lt;code&gt;DECRBY mykey 5&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Description: Decrements the value of the key by the specified decrement. If the key doesn't exist, it is initialized with the value of 0 before decrementing.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;GET&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Command: &lt;strong&gt;&lt;code&gt;GET&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Syntax: &lt;strong&gt;&lt;code&gt;GET key&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Usage: &lt;strong&gt;&lt;code&gt;GET mykey&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Description: Retrieves the value associated with the specified key. If the key exists, the command returns the value; otherwise, it returns &lt;strong&gt;&lt;code&gt;nil&lt;/code&gt;&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;GETBIT&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Command: &lt;strong&gt;&lt;code&gt;GETBIT&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Syntax: &lt;strong&gt;&lt;code&gt;GETBIT key offset&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Usage: &lt;strong&gt;&lt;code&gt;GETBIT mykey 5&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Description: Returns the bit value at the specified offset in a string value. The offset is zero-based.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;GETRANGE&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Command: &lt;strong&gt;&lt;code&gt;GETRANGE&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Syntax: &lt;strong&gt;&lt;code&gt;GETRANGE key start end&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Usage: &lt;strong&gt;&lt;code&gt;GETRANGE mykey 0 3&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Description: Retrieves a substring of the string value stored at the key, starting from the specified start index to the end index (inclusive).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;GETSET&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Command: &lt;strong&gt;&lt;code&gt;GETSET&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Syntax: &lt;strong&gt;&lt;code&gt;GETSET key value&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Usage: &lt;strong&gt;&lt;code&gt;GETSET mykey "newvalue"&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Description: Sets the value of the key with the provided string value and returns the old value. If the key doesn't exist, it is initialized with the specified value.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;INCR&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Command: &lt;strong&gt;&lt;code&gt;INCR&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Syntax: &lt;strong&gt;&lt;code&gt;INCR key&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Usage: &lt;strong&gt;&lt;code&gt;INCR mykey&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Description: Increments the value of the key by 1. If the key doesn't exist, it is initialized with the value of 0 before incrementing.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;INCRBY&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Command: &lt;strong&gt;&lt;code&gt;INCRBY&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Syntax: &lt;strong&gt;&lt;code&gt;INCRBY key increment&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Usage: &lt;strong&gt;&lt;code&gt;INCRBY mykey 5&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Description: Increments the value of the key by the specified increment. If the key doesn't exist, it is initialized with the value of 0 before incrementing.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;INCRBYFLOAT&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Command: &lt;strong&gt;&lt;code&gt;INCRBYFLOAT&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Syntax: &lt;strong&gt;&lt;code&gt;INCRBYFLOAT key increment&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Usage: &lt;strong&gt;&lt;code&gt;INCRBYFLOAT mykey 2.5&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Description: Increments the value of the key by the specified float increment. If the key doesn't exist, it is initialized with the value of 0 before incrementing.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;MGET&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Command: &lt;strong&gt;&lt;code&gt;MGET&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Syntax: &lt;strong&gt;&lt;code&gt;MGET key [key ...]&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Usage: &lt;strong&gt;&lt;code&gt;MGET key1 key2 key3&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Description: Retrieves the values associated with multiple keys. It returns an array of values corresponding to the provided keys.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;MSET&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Command: &lt;strong&gt;&lt;code&gt;MSET&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Syntax: &lt;strong&gt;&lt;code&gt;MSET key value [key value ...]&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Usage: &lt;strong&gt;&lt;code&gt;MSET key1 "value1" key2 "value2"&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Description: Sets multiple keys to their respective values. It allows setting multiple key-value pairs in a single command.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;MSETNX&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Command: &lt;strong&gt;&lt;code&gt;MSETNX&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Syntax: &lt;strong&gt;&lt;code&gt;MSETNX key value [key value ...]&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Usage: &lt;strong&gt;&lt;code&gt;MSETNX key1 "value1" key2 "value2"&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Description: Sets multiple keys to their respective values, only if none of the keys already exist. It allows atomic setting of multiple keys.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;PSETEX&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Command: &lt;strong&gt;&lt;code&gt;PSETEX&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Syntax: &lt;strong&gt;&lt;code&gt;PSETEX key milliseconds value&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Usage: &lt;strong&gt;&lt;code&gt;PSETEX mykey 1000 "Hello"&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Description: Sets the value of the key with the provided string value and a specified expiration time in milliseconds.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;SET&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Command: &lt;strong&gt;&lt;code&gt;SET&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Syntax: &lt;strong&gt;&lt;code&gt;SET key value [EX seconds|PX milliseconds] [NX|XX]&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Usage: &lt;strong&gt;&lt;code&gt;SET mykey "Hello" EX 60 NX&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Description: Sets the value of a key with the provided string value. Additional options like expiration time, conditional set (&lt;strong&gt;&lt;code&gt;NX&lt;/code&gt;&lt;/strong&gt; - only if the key doesn't exist, &lt;strong&gt;&lt;code&gt;XX&lt;/code&gt;&lt;/strong&gt; - only if the key exists) can be specified.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;SETBIT&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Command: &lt;strong&gt;&lt;code&gt;SETBIT&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Syntax: &lt;strong&gt;&lt;code&gt;SETBIT key offset value&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Usage: &lt;strong&gt;&lt;code&gt;SETBIT mykey 5 1&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Description: Sets the bit at the specified offset in a string value to either 0 or 1.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;SETEX&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Command: &lt;strong&gt;&lt;code&gt;SETEX&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Syntax: &lt;strong&gt;&lt;code&gt;SETEX key seconds value&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Usage: &lt;strong&gt;&lt;code&gt;SETEX mykey 60 "Hello"&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Description: Sets the value of the key with the provided string value and a specified expiration time in seconds.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;SETNX&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Command: &lt;strong&gt;&lt;code&gt;SETNX&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Syntax: &lt;strong&gt;&lt;code&gt;SETNX key value&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Usage: &lt;strong&gt;&lt;code&gt;SETNX mykey "Hello"&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Description: Sets the value of a key with the provided string value, only if the key doesn't exist.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;SETRANGE&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Command: &lt;strong&gt;&lt;code&gt;SETRANGE&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Syntax: &lt;strong&gt;&lt;code&gt;SETRANGE key offset value&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Usage: &lt;strong&gt;&lt;code&gt;SETRANGE mykey 5 "Redis"&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Description: Overwrites a substring of the string value stored at the key, starting from the specified offset with the provided value.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;STRLEN&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Command: &lt;strong&gt;&lt;code&gt;STRLEN&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Syntax: &lt;strong&gt;&lt;code&gt;STRLEN key&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Usage: &lt;strong&gt;&lt;code&gt;STRLEN mykey&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Description: Returns length&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;In conclusion, we have discussed Redis, a popular in-memory data structure store, and explored its unique characteristics that set it apart from other databases. Redis offers exceptional performance and versatility, making it suitable for various use cases, such as caching, real-time analytics, messaging systems, and more.&lt;/p&gt;

&lt;p&gt;We have also covered the installation process of Redis on Linux, macOS, and Windows, including how to access the Redis command-line interface (redis-cli) for interacting with the database.&lt;/p&gt;

&lt;p&gt;Furthermore, we have delved into the major commands related to set manipulation, providing syntax, usage examples, and descriptions for each command. These commands enable users to perform various operations like adding, retrieving, modifying, and removing elements from sets in Redis.&lt;/p&gt;

&lt;p&gt;Additionally, we have explored the major commands related to sorted set manipulation, including operations such as adding members with scores, retrieving ranges, finding positions, incrementing scores, and more. Sorted sets in Redis provide an ordered collection of unique elements, allowing efficient operations based on both element values and scores.&lt;/p&gt;

&lt;p&gt;Redis commands like APPEND, GET, SET, INCR, and many others offer powerful functionality for string manipulation, bit operations, and key-value management.&lt;/p&gt;

&lt;p&gt;Redis, with its versatility, performance, and rich set of commands, continues to be a preferred choice for developers and architects when it comes to handling data-intensive applications and solving various data storage and retrieval challenges.&lt;/p&gt;

</description>
      <category>redis</category>
      <category>database</category>
    </item>
    <item>
      <title>Celery Alternative for Django - Huey</title>
      <dc:creator>Idiomatic Programmers</dc:creator>
      <pubDate>Fri, 13 May 2022 13:56:49 +0000</pubDate>
      <link>https://dev.to/idiomprog/celery-alternative-for-django-huey-1ca8</link>
      <guid>https://dev.to/idiomprog/celery-alternative-for-django-huey-1ca8</guid>
      <description>&lt;h2&gt;
  
  
  Background
&lt;/h2&gt;

&lt;p&gt;So today I will be talking about a Celery alternative named &lt;a href="https://huey.readthedocs.io/en/latest/index.html"&gt;Huey&lt;/a&gt;, which comes with a much easier setup than &lt;a href="https://docs.celeryq.dev/"&gt;Celery&lt;/a&gt; and is much smaller in size compared to Celery.&lt;/p&gt;

&lt;p&gt;The reason why I decided to try out Huey is because I have faced some issues with Celery sometimes for doing some common tasks because the documentation isn't too great.&lt;/p&gt;

&lt;p&gt;For those who don't know what Celery is or haven't used it before, Huey is an asynchronous task queue which allows you to perform scheduled tasks or long running tasks in the background.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;We will be installing the following packages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;redis&lt;/li&gt;
&lt;li&gt;django&lt;/li&gt;
&lt;li&gt;huey&lt;/li&gt;
&lt;li&gt;requests (optional, needed for the demo)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Github Repo
&lt;/h2&gt;

&lt;p&gt;The following blog comes accompanied with a github repo, that you can use to test out the demo project that we will be creating.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/Idiomatic-Programmers/huey-demo"&gt;Click here to view repo.&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Project Setup
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Create Project Directory
&lt;/h3&gt;

&lt;p&gt;Open the terminal and type the following to create a directory, you can skip this step and do it from File Explorer itself.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir &lt;/span&gt;huey_demo
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Virtual Environment
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Let us create a virtualenv first to install our project dependencies:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python &lt;span class="nt"&gt;-m&lt;/span&gt; venv venv
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Activate the virtualenv (Linux):&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;source &lt;/span&gt;venv/bin/activate
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Installing dependencies
&lt;/h3&gt;

&lt;p&gt;Type the following command in the terminal to install all the dependencies:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;&lt;span class="nv"&gt;Django&lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;4.0.4 &lt;span class="nv"&gt;redis&lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;4.2.2 &lt;span class="nv"&gt;huey&lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;2.4.3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At the time of writing this article, these were the versions I tested out this setup with, keep an eye on the Github Repo for any updates as per the latest version in the future.&lt;/p&gt;

&lt;h3&gt;
  
  
  Create Project
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Create the django project by typing the following command in terminal:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;django-admin startproject django_huey_demo
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Change directory into Django project directory:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;django_huey_demo
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Create the app under our project:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python manage.py startapp demo
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Include the created app into project &lt;code&gt;settings.py&lt;/code&gt;, make the following changes:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;INSTALLED_APPS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
&lt;span class="c1"&gt;# Existing Apps
&lt;/span&gt;&lt;span class="s"&gt;"demo.apps.DemoConfig"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="c1"&gt;# &amp;lt;== Add this line
&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Set debug mode to &lt;code&gt;False&lt;/code&gt; in &lt;code&gt;settings.py&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;DEBUG&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;False&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Project Overview
&lt;/h2&gt;

&lt;p&gt;Now that we are done setting up our project, it is a good time to take you over what we will be building today. We will fetch "Word of the Day" daily from &lt;a href="https://developer.wordnik.com/"&gt;Wordnik API&lt;/a&gt;. Then we will store the word, its definition, and an example of the word in a sentence to our database.&lt;/p&gt;

&lt;p&gt;We will setup a periodic task using Huey which will fetch the Word of the Day and store it.&lt;/p&gt;

&lt;p&gt;For storing the word we will be creating a Django Model of the same.&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting Wordnik API Key
&lt;/h2&gt;

&lt;p&gt;You can follow &lt;a href="https://developer.wordnik.com/gettingstarted"&gt;this guide&lt;/a&gt; to obtain the API key.&lt;/p&gt;

&lt;h2&gt;
  
  
  Coding our project
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Add Huey to our Project
&lt;/h3&gt;

&lt;p&gt;We need to add Huey to installed apps of our project, so make the following changes in &lt;code&gt;settings.py&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;INSTALLED_APPS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="c1"&gt;# Existing apps
&lt;/span&gt;    &lt;span class="s"&gt;'huey.contrib.djhuey'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;# &amp;lt;== Add this line
&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Install Redis
&lt;/h3&gt;

&lt;p&gt;We need to install Redis for Huey to store information about queued tasks in it, like we used to do with Celery as well. You can refer to the following &lt;a href="https://redis.io/download/#redis-downloads"&gt;link&lt;/a&gt; to install redis based on your specific operating system.&lt;/p&gt;

&lt;p&gt;If you're comfortable with using Docker, you can use the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;--name&lt;/span&gt; redis_huey &lt;span class="nt"&gt;-p&lt;/span&gt; 6379:6379 &lt;span class="nt"&gt;-d&lt;/span&gt; redis
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By default, Huey will try connecting to Redis server running on &lt;code&gt;localhost:6379&lt;/code&gt;. If it isn't present, it will raise an error.&lt;/p&gt;

&lt;h3&gt;
  
  
  Model Definition
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Add the following code to your &lt;code&gt;demo/models.py&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;django.db&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Word&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Model&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;word&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CharField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;max_length&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;part_of_speech&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CharField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;max_length&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;definition&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TextField&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;example&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TextField&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__str__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;word&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Make migrations:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python manage.py makemigrations demo
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Apply migrations:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python manage.py migrate demo
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Task Definition
&lt;/h3&gt;

&lt;p&gt;Create a file named &lt;code&gt;tasks.py&lt;/code&gt; in demo app directory. The reason why we named our file &lt;code&gt;tasks.py&lt;/code&gt; is to help Huey auto discover the tasks present in our registered apps, if we named our file anything other than that, we would have to manually register our task. If you would like to know more you can check out the Huey documentation &lt;a href="https://huey.readthedocs.io/en/latest/imports.html#imports"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Before we write the task definition we need to install an additional dependency &lt;code&gt;requests&lt;/code&gt;. Install it by typing the following in your terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;&lt;span class="nv"&gt;requests&lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;2.27.1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now comes the code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;requests&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;django.conf&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;settings&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;huey&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;crontab&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;huey.contrib.djhuey&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;db_periodic_task&lt;/span&gt;

&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;demo.models&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Word&lt;/span&gt;

&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;db_periodic_task&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;crontab&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hour&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"18"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;minute&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"00"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;fetch_daily_word&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s"&gt;"https://api.wordnik.com/v4/words.json/wordOfTheDay?api_key=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;settings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WORDNIK_API_KEY&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;Word&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;objects&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_or_create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;word&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"word"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="n"&gt;part_of_speech&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"definitions"&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="s"&gt;"partOfSpeech"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="n"&gt;definition&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"definitions"&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="n"&gt;example&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"examples"&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add the following line in your project settings:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;WORDNIK_API_KEY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"api-key-here"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This codeblock might be a lot to take in, so let's go over the things in it one by one:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Huey Decorator&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;huey.contrib.djhuey&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;db_periodic_task&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;This is a decorator provided by Huey to register periodic task that involve working with database, this decorator automatically closes the database connection upon task completion, for more details, you can refer &lt;a href="https://huey.readthedocs.io/en/latest/contrib.html#tasks-that-execute-queries"&gt;here.&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Crontab Schedule&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;db_periodic_task&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;crontab&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hour&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"18"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;minute&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"00"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;We are passing the argument &lt;code&gt;crontab(hour="18", minute="00")&lt;/code&gt; to our periodic task decorator, this tells Huey to run our task at 6pm everyday. You can make use of &lt;a href="https://crontab.guru/"&gt;this website&lt;/a&gt; to create your crontab schedules, I use it everytime.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Wordnik API Key&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;django.conf&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;settings&lt;/span&gt;

&lt;span class="c1"&gt;# Usage
## settings.WORDNIK_API_KEY
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;&lt;code&gt;from django.conf import settings&lt;/code&gt; is the standard way to import any data from our project settings, it is useful in cases where we have multiple settings files setup for different environment so it will know which file to pick from without us having to worry about it. It finds out which settings file we are using from the &lt;code&gt;DJANGO_SETTINGS_MODULE&lt;/code&gt; environment variable. But you don't have to worry about these details.&lt;/p&gt;

&lt;p&gt;Then we are using the key in our wordnik API call.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Wordnik API Call&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s"&gt;"https://api.wordnik.com/v4/words.json/wordOfTheDay?api_key=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;settings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WORDNIK_API_KEY&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;Here we are making use of the requests module to make a GET request to the wordnik API while passing our API Key for authentication.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Storing word in database&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;Word&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;objects&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_or_create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;word&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"word"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="n"&gt;part_of_speech&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"definitions"&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="s"&gt;"partOfSpeech"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="n"&gt;definition&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"definitions"&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="n"&gt;example&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"examples"&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;After parsing the API response we are storing the word definition in our database. We are making use of &lt;code&gt;get_or_create&lt;/code&gt; method instead of &lt;code&gt;create&lt;/code&gt; method here so that we don't create multiple copies of the same word in our database if that word is ever repeated by the Wordnik API.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Wordnik API Response&lt;/strong&gt;&lt;br&gt;
Here is what the Wordnik API response for Word of the Day endpoint looks like. Some of the irrelevant sections of the response has been truncated for brevity purposes.&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"word"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"stolon"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"definitions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"source"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ahd-5"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"text"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"A long thin stem that usually grows horizontally along the ground and produces roots and shoots at widely spaced nodes, as in a strawberry plant."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"note"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"partOfSpeech"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"noun"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;More&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;definitions&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;here...&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"publishDate"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2022-05-08T03:00:00.000Z"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"examples"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"title"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"4.1 Nursery establishment"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"text"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"A stolon is a stem that grows along the ground, producing at its nodes new plants with roots and upright stems."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Additional&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;data&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;here...&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;More&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;examples&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;here...&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Additional&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;fields&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;here...&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Here is what the Wordnik API response for Word of the Day endpoint looks like. Some of the irrelevant sections of the response has been truncated for brevity purposes.&lt;/p&gt;

&lt;h3&gt;
  
  
  Running Huey Worker
&lt;/h3&gt;

&lt;p&gt;You can start the Huey worker by typing the following command in your terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python manage.py run_huey
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can pass multiple flags to the above command which will change what gets logged to the console, such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;-v, --verbose&lt;/code&gt; - verbose logging (includes DEBUG level)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-q, --quiet&lt;/code&gt; - minimal logging&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-S, --simple&lt;/code&gt; - simple logging format (“time message”)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To look at various other options for logging, checkout the docs &lt;a href="https://huey.readthedocs.io/en/latest/guide.html#logging"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What else can you do with Huey?
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Task Decorators
&lt;/h3&gt;

&lt;p&gt;Huey comes with multiple task decorators depending on what operations you are performing within the task. I'll explain in brief what all of those do below. Here is the import statement for all the decorators:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;huey.contrib.djhuey&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;periodic_task&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;db_task&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;db_periodic_task&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;task&lt;/code&gt;: A regular task&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;periodic_task&lt;/code&gt; : When you want to run a task periodically based on a schedule&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;db_task&lt;/code&gt; : When you want to perform db operations within your task&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;db_periodic_task&lt;/code&gt; : When you want to perform db operations in a periodic task&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Crontab Examples
&lt;/h3&gt;

&lt;p&gt;Let me show you some more examples of how you can use crontab to schedule your tasks.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;crontab(minute='*/3')&lt;/code&gt; would schedule the task to run every three minute&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;crontab(hour='*/3', minute='5')&lt;/code&gt; would create a task that will run at 5 minute past every third hour.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;crontab(minute='00', hour='10', month='*/2', day_of_week='*/5')&lt;/code&gt; would create a task that would run on every 5th day of the week, of every 2nd month at 10:00 AM.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Scheduling Tasks
&lt;/h3&gt;

&lt;p&gt;For example, you have the following task defined inside &lt;code&gt;tasks.py&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;huey.contrib.djhuey&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;task&lt;/span&gt;

&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;count&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now you want to call this task, but want it to run after 5 seconds, you can do the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;schedule&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;delay&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;delay&lt;/code&gt; parameter takes values in seconds, so if you want it to execute after 5 minutes specify 300 seconds.&lt;/p&gt;

&lt;h3&gt;
  
  
  Retrying tasks that fail
&lt;/h3&gt;

&lt;p&gt;Suppose you add the following logic to our existing task:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;db_periodic_task&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;crontab&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hour&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"18"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;minute&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"00"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;retries&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;fetch_daily_word&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s"&gt;"https://api.wordnik.com/v4/words.json/wordOfTheDay?api_key=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;settings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WORDNIK_API_KEY&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status_code&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nb"&gt;Exception&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Unable to fetch data from Wordnik API"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;## Add this logic
&lt;/span&gt;    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;Word&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;objects&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_or_create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;word&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"word"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
            &lt;span class="n"&gt;part_of_speech&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"definitions"&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="s"&gt;"partOfSpeech"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
            &lt;span class="n"&gt;definition&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"definitions"&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
            &lt;span class="n"&gt;example&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"examples"&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So we added the logic to check for status code of the response, and if it is something other than 200, it will retry that task upto 2 times. But these retries would happen without any time gap between the two attempts. Now what if you want to delay out multiple attempts of this task, we can do that by passing the &lt;code&gt;retry_delay&lt;/code&gt; argument, it accepts values in seconds.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;db_periodic_task&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;crontab&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hour&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"18"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;minute&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"00"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;retries&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;retry_delay&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will cause a 10 second delay between multiple attempts.&lt;/p&gt;

&lt;h3&gt;
  
  
  Development Mode
&lt;/h3&gt;

&lt;p&gt;Huey comes with a default setting which makes working with Huey during development in Django easier. So whenever you have &lt;code&gt;DEBUG=True&lt;/code&gt; present in your &lt;code&gt;settings.py&lt;/code&gt; file, tasks will be executed synchronously just like regular function calls. The purpose of this is to avoid running both Redis and an additional consumer process while developing or running tests. You can read more about this &lt;a href="https://huey.readthedocs.io/en/latest/contrib.html#debug-and-synchronous-execution"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;For this, we need to add the following line in &lt;code&gt;settings.py&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;HUEY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;However, if you want to override this behaviour, you can add the following Huey config instead:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;HUEY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="s"&gt;"immediate"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you have the above config mentioned in &lt;code&gt;settings.py&lt;/code&gt; while having &lt;code&gt;DEBUG=True&lt;/code&gt; Huey will require you to setup Redis and run huey worker using &lt;code&gt;run_huey&lt;/code&gt; command.&lt;/p&gt;

&lt;h2&gt;
  
  
  Celery vs Huey
&lt;/h2&gt;

&lt;p&gt;Some observations about Huey as compared to Celery are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Smaller footprint of dependencies as compared to Celery. Celery installs kombu and billiards along with it. Meanwhile, huey doesn't have any dependencies.&lt;/li&gt;
&lt;li&gt;Lesser services needed to be run for periodic tasks, Celery requires running beat service and a worker service to work with periodic task meanwhile we only need to run one service using the &lt;code&gt;run_huey&lt;/code&gt; command.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://huey.readthedocs.io/en/latest/index.html"&gt;Huey Docs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.wordnik.com/gettingstarted"&gt;Wordnik API&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/Idiomatic-Programmers/huey-demo"&gt;Associated Github Repo&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>django</category>
      <category>celery</category>
      <category>python</category>
    </item>
    <item>
      <title>How to save Base64 encoded image to Django ImageField?</title>
      <dc:creator>Idiomatic Programmers</dc:creator>
      <pubDate>Sat, 17 Jul 2021 12:47:50 +0000</pubDate>
      <link>https://dev.to/idiomprog/how-to-save-base64-encoded-image-to-django-imagefield-43o9</link>
      <guid>https://dev.to/idiomprog/how-to-save-base64-encoded-image-to-django-imagefield-43o9</guid>
      <description>&lt;p&gt;I had to create an API that had to accept an image in Base64 encoded format and save it to Django image field, which requires an image file. So today I learned how to do this.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: B64 to PIL
&lt;/h2&gt;

&lt;p&gt;The first step will be to convert this B64 image to an image file in memory, I will be using Pillow for this. You can install Pillow using this bash command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;pillow
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Make sure you have pip installed. If you're using Linux or Mac OS, then you might have to use &lt;code&gt;pip3&lt;/code&gt; instead of &lt;code&gt;pip&lt;/code&gt;. But I'm using virtual env, so who cares.&lt;/p&gt;

&lt;p&gt;after that, write this function.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;base64&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;io&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;PIL&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Image&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;decodeDesignImage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;base64&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;b64decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'UTF-8'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="n"&gt;buf&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;io&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;BytesIO&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;img&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Image&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;img&lt;/span&gt;
    &lt;span class="k"&gt;except&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This function will return a PIL image if the B64 data is valid, or it will return None.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: PIL to Django ImageField
&lt;/h2&gt;

&lt;p&gt;After getting the PIL image, wrote a function that will take this PIL image, convert it into a JPEG file buffer and then inserted it to Database instance using &lt;code&gt;InMemoryUploadedFile&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;sources: &lt;a href="https://kite.com/python/docs/django.core.files.uploadedfile.InMemoryUploadedFile"&gt;InMemoryUploadedFile&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;What is InMemoryUploadedFile? This is basically a representation of the image in memory, that's as simple as it is.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;django.core.files.uploadedfile&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;InMemoryUploadedFile&lt;/span&gt;

&lt;span class="n"&gt;img&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;decodeDesignImage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;img_io&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;io&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;BytesIO&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;img&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;save&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;img_io&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;format&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'JPEG'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;design&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;image&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;InMemoryUploadedFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;img_io&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;field_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="s"&gt;".jpg"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;content_type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'image/jpeg'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;img_io&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tell&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;charset&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;design&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;save&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;The InMemoryUploadedFile class takes 6 parameters:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;File buffer&lt;/code&gt;: This is the JPEG format IO buffer I created in line 5.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;field_name&lt;/code&gt;: There wasn't much information about this, if you have any idea then please comment below.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;name&lt;/code&gt;: This is the name of the file, make sure you add .jpg at the end.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;content_type&lt;/code&gt;: This is pretty self explanatory.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;size&lt;/code&gt;: The size in bytes of the file.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;charset&lt;/code&gt;: The character set, the file data is using. In this case None.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Now if you check your Media folder, you'll see that image as if you've uploaded it via a form.&lt;/p&gt;

&lt;p&gt;So that's it for today's "Today I Learned"&lt;/p&gt;

</description>
      <category>django</category>
      <category>base64</category>
      <category>python</category>
    </item>
    <item>
      <title>How to download Pandas Dataframe as Excel or CSV in Django?</title>
      <dc:creator>Idiomatic Programmers</dc:creator>
      <pubDate>Sat, 27 Mar 2021 03:00:00 +0000</pubDate>
      <link>https://dev.to/idiomprog/how-to-download-pandas-dataframe-as-excel-or-csv-in-django-59l5</link>
      <guid>https://dev.to/idiomprog/how-to-download-pandas-dataframe-as-excel-or-csv-in-django-59l5</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Pandas is an essential tool used by Python developers used for data analysis purposes, but what is the point of the analysis if we are not able to provide that insight to the end user. When Django and Pandas are used in conjunction we can create applications that are not only developed faster, but are also smart in utilizing the data that is collected from the user. I recently stumbled on one such use case, where the user interacts with the frontend and turns some filters and then the backend processes that data, and then provide the aggregated data as an Excel or CSV file to the user. I will be describing how I went about doing that below.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;In order to follow along this article, I am assuming you already have a Django project that is using Pandas library ready.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://www.djangoproject.com/start/"&gt;Django Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://pandas.pydata.org/docs/"&gt;Pandas Documentation&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Requirements
&lt;/h2&gt;

&lt;p&gt;In addition to Django and Pandas project ready, you would need to install Openpyxl.&lt;/p&gt;

&lt;h3&gt;
  
  
  Openpyxl
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://openpyxl.readthedocs.io/en/stable/"&gt;Openpyxl&lt;/a&gt; is a tool that allows to read and write Open Office XML formats such as Excel 2010 xlsx/xlsm/xltx/xltm files.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;openpyxl
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once installed, you can create Excel files natively from Python using a simple code like this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;openpyxl&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Workbook&lt;/span&gt;

&lt;span class="n"&gt;workbook&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Workbook&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;sheet&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;workbook&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;active&lt;/span&gt;

&lt;span class="n"&gt;sheet&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"A1"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"ID"&lt;/span&gt;
&lt;span class="n"&gt;sheet&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"B1"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Key"&lt;/span&gt;

&lt;span class="n"&gt;sheet&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"A2"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="n"&gt;sheet&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"B2"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Test Key"&lt;/span&gt;

&lt;span class="n"&gt;workbook&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;save&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;filename&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"test.xlsx"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will create a file called &lt;strong&gt;"test.xlsx".&lt;/strong&gt; Try it out yourself.&lt;/p&gt;

&lt;h2&gt;
  
  
  HTTP Response
&lt;/h2&gt;

&lt;p&gt;As you know, Django uses HTTP Request and Response to communicate with the client. Therefore all data must be converted to Byte String before sending it over to the client.&lt;/p&gt;

&lt;p&gt;A Typical HTTP Response looks something like this.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ovf_yUkQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://res.cloudinary.com/idiomprog/image/upload/v1616226497/httpmsgstructure2_htshjp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ovf_yUkQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://res.cloudinary.com/idiomprog/image/upload/v1616226497/httpmsgstructure2_htshjp.png" alt="https://res.cloudinary.com/idiomprog/image/upload/v1616226497/httpmsgstructure2_htshjp.png" width="800" height="238"&gt;&lt;/a&gt;For more information, checkout this article by Mozilla about &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Messages"&gt;HTTP Messages&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;As you can see in the above picture, every HTTP response has a body section which is a Byte Array and a Header called &lt;strong&gt;Content-Type&lt;/strong&gt; specifies what type of content it is and which character set the browser should use in order to decode the bytes. In the above case, the server is sending a text/html data and the browser need to use iso-8859-1 charset.&lt;/p&gt;

&lt;p&gt;In our case, we are sending bytes that are related to Excel spreadsheets. So googling for a bit I found the content-type header for that is this. Source: Mozilla article about &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types/Common_types"&gt;Common MIME Types&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;application&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;vnd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;openxmlformats&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;officedocument&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;spreadsheetml&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sheet&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  What are MIME Types?
&lt;/h3&gt;

&lt;p&gt;MIME is short for &lt;strong&gt;Multipurpose Internet Mail Extensions&lt;/strong&gt; which is a standard that indicates the nature and format of a document sent via the Internet.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Important&lt;/strong&gt; : Browsers use the MIME type, not the file extension, to determine how to process a URL, so it's important that web servers send the correct MIME type in the response's &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Type"&gt;Content-Type header&lt;/a&gt;. If this is not correctly configured, browsers are likely to misinterpret the contents of files and sites will not work correctly, and downloaded files may be mishandled.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;For more information, checkout MDN Article about &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types"&gt;MIME Types&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The structure of a MIME Type is according to &lt;a href="https://www.iana.org/"&gt;IANA (Internet Assigned Numbers Authority)&lt;/a&gt; is like this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;subtype&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Therefore, in the MIME Type for Excel files, the type is " &lt;strong&gt;application",&lt;/strong&gt; which belongs to any kind of binary data that cannot be directly decoded to a human-readable form (text, HTML, etc.). Files with type application require some sort of external or third party software to decode and read such as PDFs, Zip files, Excel files, etc.&lt;/p&gt;

&lt;h2&gt;
  
  
  Download Excel Files using Django and Pandas
&lt;/h2&gt;

&lt;p&gt;Finally, we will see how we can send the Pandas dataframe to client as an excel file.&lt;/p&gt;

&lt;p&gt;I am assuming that you already have the code for pandas so I will do some abstraction in a variable called data.&lt;/p&gt;

&lt;p&gt;First we will import to the inbuilt library, &lt;a href="https://docs.python.org/3/library/io.html#binary-i-o"&gt;BytesIO&lt;/a&gt; so that we can write the excel file as a Byte array.&lt;/p&gt;

&lt;p&gt;BytesIO is a library using which we can write data onto system memory instead of writing them as a file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;io&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;BytesIO&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then we will use Python &lt;a href="https://book.pythontips.com/en/latest/context_managers.html"&gt;context manager&lt;/a&gt; to open a Byte buffer on which we can write the excel file. Context Managers allow you to allocate and release memory precisely when you want it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;BytesIO&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;
    &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;pd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ExcelWriter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;writer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="c1"&gt;# You can add multiple Dataframes to an excel file
&lt;/span&gt;        &lt;span class="c1"&gt;# Using the sheet_name attribute
&lt;/span&gt;      &lt;span class="n"&gt;data1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;to_excel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;writer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sheet_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"DATA 1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;data2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;to_excel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;writer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sheet_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"DATA 2"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;filename&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"analytics_data.xlsx"&lt;/span&gt;

    &lt;span class="c1"&gt;# imported from django.http
&lt;/span&gt;    &lt;span class="n"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;HttpResponse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getvalue&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="c1"&gt;# Gives the Byte string of the Byte Buffer object
&lt;/span&gt;        &lt;span class="n"&gt;content_type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'Content-Disposition'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s"&gt;'attachment; filename=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;filename&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;res&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We will be using context managers to open and close files because that's more efficient than manually closing and releasing the memory after use. If you already know how to &lt;a href="https://pandas.pydata.org/docs/reference/api/pandas.ExcelWriter.html"&gt;export a set of data frames as an excel file&lt;/a&gt;, that code should look like this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;pd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ExcelWriter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'data.xlsx'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;writer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;data1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;to_excel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;writer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sheet_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"DATA 1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;data2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;to_excel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;writer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sheet_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"DATA 2"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We will simply take this code and wrap it around a BytesIO context manager which gives us a memory buffer &lt;code&gt;b&lt;/code&gt; as a file to work with. We will simply take that memory buffer and pass it to &lt;code&gt;pd.ExcelWriter()&lt;/code&gt; class and the rest of the code will be the same this that context manager.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;BytesIO&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;
    &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;pd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ExcelWriter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;writer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="n"&gt;data1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;to_excel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;writer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sheet_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"DATA 1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;data2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;to_excel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;writer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sheet_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"DATA 2"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now that we have our Excel data written in a memory buffer, we can simply convert that to ByteArray using the method &lt;code&gt;b.getvalue()&lt;/code&gt; which we will pass as a parameter in Django &lt;code&gt;HttpResponse&lt;/code&gt; with appropriate &lt;code&gt;content_type&lt;/code&gt; that we discussed earlier.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;filename&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"analytics_data.xlsx"&lt;/span&gt;

&lt;span class="c1"&gt;# imported from django.http
&lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;HttpResponse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getvalue&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="c1"&gt;# Gives the Byte string of the Byte Buffer object
&lt;/span&gt;  &lt;span class="n"&gt;content_type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In addition to the Content-Type header, we also need to provide another header called &lt;strong&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Disposition"&gt;Content-Disposition&lt;/a&gt;&lt;/strong&gt; that tells the browser if we want to show the data in the browser download and save it as a local file as an attachment. We can also pass a filename with this header.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'Content-Disposition'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s"&gt;'attachment; filename=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;filename&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;res&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here is the complete code snippet for Django view to download the excel file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;download_analytics_endpoint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;BytesIO&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;get_analytics_data&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

        &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;pd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ExcelWriter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;writer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;to_excel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;writer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sheet_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Data"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="n"&gt;filename&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s"&gt;"analytics_data.xlsx"&lt;/span&gt;
        &lt;span class="n"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;HttpResponse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getvalue&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
            &lt;span class="n"&gt;content_type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'Content-Disposition'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s"&gt;'attachment; filename=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;filename&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;res&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is all, now you just have to create a Django URL for this function and you can download any file you want, just convert that file to a Byte string and use the correct Content-Type header.&lt;/p&gt;

</description>
      <category>django</category>
      <category>pandas</category>
    </item>
    <item>
      <title>Generative Adversarial Networks</title>
      <dc:creator>Idiomatic Programmers</dc:creator>
      <pubDate>Thu, 11 Feb 2021 08:56:15 +0000</pubDate>
      <link>https://dev.to/idiomprog/generative-adversarial-networks-238m</link>
      <guid>https://dev.to/idiomprog/generative-adversarial-networks-238m</guid>
      <description>&lt;p&gt;In 2014, Ian Goodfellow, who is currently working as Director of Machine Learning for Apple, published a paper called "Generative Adversarial Networks" or GAN for short. Which basically talked about a system of two neural networks, Generator and Discriminator, that can generate images or any data that is similar to provided datasets from essentially random noise.&lt;/p&gt;

&lt;p&gt;The diagram below shows the basic architecture of a GAN.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Ra2rxEDB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://res.cloudinary.com/idiomprog/image/upload/v1613042386/gan_diagram_jhuerz.svg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Ra2rxEDB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://res.cloudinary.com/idiomprog/image/upload/v1613042386/gan_diagram_jhuerz.svg" alt="https://res.cloudinary.com/idiomprog/image/upload/v1613042386/gan_diagram_jhuerz.svg" width="577" height="253"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Source: &lt;a href="https://developers.google.com/"&gt;https://developers.google.com/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Generative Network takes some random noise and outputs some random noise. This output noise is passed to a discriminator along with the real image or data as a ground truth based on that both Discriminator and Generator is trained.&lt;/p&gt;

&lt;p&gt;As you can see, the concept of GAN is very simple. When I started learning about GANs I thought I can easily implement one of those. But boy I was wrong. In reality training a GAN is extremely hard both Generator and Discriminator must be trained side by side if one overpowers the other it won't work, we will talk about all the problems you might face while training a GAN. But now let's look at a simple GAN in Pytorch. We will be using the MNIST Dataset for this post.&lt;/p&gt;

&lt;h2&gt;
  
  
  Understanding the Dataset
&lt;/h2&gt;

&lt;p&gt;The MNIST dataset is a huge database of handwritten numbers from 0 to 9 used for Optical Character Recognition or reading numbers from an image.&lt;/p&gt;

&lt;p&gt;This dataset consists of 28x28 images of handwritten numbers where each pixel contains either a zero or a one.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--OkKBgwmT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://res.cloudinary.com/idiomprog/image/upload/v1613042427/687474703a2f2f692e7974696d672e636f6d2f76692f3051493378675875422d512f687164656661756c742e6a7067_rx3nur.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--OkKBgwmT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://res.cloudinary.com/idiomprog/image/upload/v1613042427/687474703a2f2f692e7974696d672e636f6d2f76692f3051493378675875422d512f687164656661756c742e6a7067_rx3nur.jpg" alt="https://res.cloudinary.com/idiomprog/image/upload/v1613042427/687474703a2f2f692e7974696d672e636f6d2f76692f3051493378675875422d512f687164656661756c742e6a7067_rx3nur.jpg" width="480" height="360"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The computer vision extension of PyTorch, Torchvision, provides this dataset which we can download using the following code snippet.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;mnist&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;datasets&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MNIST&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;root&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'datasets'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;train&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;transform&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;transformations&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;download&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But before we can run this code, we need to import some libraries.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;torchvision.datasets&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;datasets&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;torch.utils.data&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;DataLoader&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;torchvision.transforms&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;transforms&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can install the torchvision library using this pip command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;torchvision
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;strong&gt;DataLoader&lt;/strong&gt; class is used to load the data to memory in batches, this prevents your system from running out of memory while training.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Transforms&lt;/strong&gt; class is used to make random augmentations to the image such as random rotation, resize, crop, etc. but for now we will only normalise the images to range from -1 to 1.&lt;/p&gt;

&lt;p&gt;The entire function that you can copy paste is this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;load_dataset&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;transformations&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;transforms&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Compose&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
        &lt;span class="n"&gt;transforms&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ToTensor&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
        &lt;span class="n"&gt;transforms&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Normalize&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="mf"&gt;0.5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;0.5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="n"&gt;mnist&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;datasets&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MNIST&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;root&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'datasets'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;train&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;transform&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;transformations&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;download&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;DataLoader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mnist&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;batch_size&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;shuffle&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Implementing the Generator
&lt;/h2&gt;

&lt;p&gt;In this section, we will implement a generator network which will take a random noise vector of size 100 and convert it into a vector of size 784 which we will then convert to 28x28&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Generator&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Module&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__init__&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="nb"&gt;super&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt; &lt;span class="n"&gt;__init__&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;gen&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;nn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sequential&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;nn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Linear&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;256&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="n"&gt;nn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;LeakyReLU&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;0.01&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="n"&gt;nn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Linear&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;256&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;784&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="n"&gt;nn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Tanh&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="c1"&gt;# make outputs [-1, 1]
&lt;/span&gt;        &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;forward&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;gen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We will be implementing the original GAN created by Ian Goodfellow in this paper &lt;a href="https://arxiv.org/abs/1406.2661"&gt;Generative Adversarial Networks&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Implemeting the Discriminator
&lt;/h2&gt;

&lt;p&gt;Next, we will implement a discriminator that will take the vector of size 784 that may be generated or from a real image.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Discriminator&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Module&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__init__&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="nb"&gt;super&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt; &lt;span class="n"&gt;__init__&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;disc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;nn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sequential&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;nn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Linear&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;784&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;128&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="n"&gt;nn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;LeakyReLU&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;0.01&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="n"&gt;nn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Linear&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;128&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="n"&gt;nn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sigmoid&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="c1"&gt;# make outputs [0, 1]
&lt;/span&gt;        &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;forward&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;disc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Hyperparameters
&lt;/h2&gt;

&lt;p&gt;As I mentioned earlier, GANs are extremely hard to train, one of the reasons is that a GAN is very sensitive to the initial values or hyperparameters. You have to follow the original papers to get the training right. Otherwise, you might have to spend many days optimizing the hyperparameters.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="s"&gt;'device'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"cuda"&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;torch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cuda&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;is_available&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="s"&gt;"cpu"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;'lr'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;3e-4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;'epochs'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;'batch_size'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;32&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In our case, we will be using the same parameters as it was said in the paper, that is, a learning rate of 0.0003 and 50 epochs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What is a learning rate?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Simple answer, it's the rate at which a machine learning model learns. Smaller the number, the slower it learns and higher the number the faster it learns. For more info, check out our post about &lt;a href="https://dev.to/post/perceptrons/#perceptron-algorithm"&gt;Perceptrons&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Training Time
&lt;/h2&gt;

&lt;p&gt;Finally, it's time to actually generate some handwritten numbers, that is, train our GAN. First let's create the objects for Generator, Discriminator, and their optimizers, we will be using the Adam optimizers.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;ADAM&lt;/strong&gt; or &lt;strong&gt;ADA&lt;/strong&gt; ptive &lt;strong&gt;M&lt;/strong&gt; oment optimiser is an algorithm used to update the weights such that the overall error goes down.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;disc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Discriminator&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;to&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'device'&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="n"&gt;gen&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Generator&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;to&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'device'&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

&lt;span class="n"&gt;optimiser_g&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;optim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Adam&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;gen&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parameters&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;lr&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'lr'&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="n"&gt;optimiser_d&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;optim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Adam&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;disc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parameters&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;lr&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'lr'&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We also need to define a loss function before we train, we will be using the Binary Cross Entropy loss function to calculate the error of our model.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Binary Cross Entropy (BCE) Loss&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This loss formula is used to calculate the distance between two probability distributions.&lt;/p&gt;

&lt;p&gt;BCE=ℓ(x,y)=L=(l1​,…,lN​),ln​=−wn​[yn​⋅logxn​+(1−yn​)⋅log(1−xn​)]&lt;/p&gt;

&lt;p&gt;BCE = ℓ(x,y)=L=(l_1​,…,l_N​), l_n​=−w_n​[y_n​⋅logx_n​+(1−y_n​)⋅log(1−x_n​)]&lt;/p&gt;

&lt;p&gt;BCE=ℓ(x,y)=L=(l1​​,…,lN​​),ln​​=−wn​​[yn​​⋅logxn​​+(1−yn​​)⋅log(1−xn​​)]&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;loss_fn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;nn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;BCELoss&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we will write our training step which is one cycle of generating and discriminating a handwritten number compare with an original number and update the models.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;epoch&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'epoch'&lt;/span&gt;&lt;span class="p"&gt;]):&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;batch_idx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;real&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;label&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;enumerate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;train_data&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;

        &lt;span class="n"&gt;noise&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;torch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;randn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'batch_size'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;to&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'device'&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="c1"&gt;# Create a random probability distribution
&lt;/span&gt;        &lt;span class="n"&gt;fake&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;gen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;noise&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# Generate a fake number
&lt;/span&gt;        &lt;span class="n"&gt;disc_real&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;disc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;real&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;view&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# pass the real number through the discriminator
&lt;/span&gt;        &lt;span class="n"&gt;lossD_real&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;loss_fn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;disc_real&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;torch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ones_like&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;disc_real&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="c1"&gt;# calculate the loss for real image
&lt;/span&gt;        &lt;span class="n"&gt;disc_fake&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;disc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fake&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;view&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# pass the fake number through the discriminator
&lt;/span&gt;        &lt;span class="n"&gt;lossD_fake&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;loss_fn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;disc_fake&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;torch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;zeros_like&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;disc_fake&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="c1"&gt;# calculate the loss for fake image
&lt;/span&gt;        &lt;span class="n"&gt;lossD&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lossD_real&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;lossD_fake&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="c1"&gt;# calculate the average loss
&lt;/span&gt;
        &lt;span class="c1"&gt;# update the weights for the discriminator
&lt;/span&gt;        &lt;span class="n"&gt;disc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;zero_grad&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;lossD&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;backward&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;retain_graph&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;optimiser_d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;step&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

        &lt;span class="n"&gt;output&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;disc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fake&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;view&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;lossG&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;loss_fn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;torch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ones_like&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="c1"&gt;# calculate the error between the fake image and the true image
&lt;/span&gt;
        &lt;span class="c1"&gt;# update the weights for the generator
&lt;/span&gt;        &lt;span class="n"&gt;gen&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;zero_grad&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;lossG&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;backward&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;optimiser_g&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;step&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This code is heavily inspired by a youtube video by Aladdin Persson.&lt;/p&gt;



&lt;p&gt;Find the complete code at our &lt;a href="https://github.com/Idiomatic-Programmers/SimpleGAN"&gt;Github Repo&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you have any questions, feel free to comment below.&lt;/p&gt;

&lt;h3&gt;
  
  
  References
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Goodfellow, Ian J., et al. “Generative Adversarial Networks.” &lt;a href="http://arxiv.org/"&gt;ArXiv.org&lt;/a&gt;, 10 June 2014, &lt;a href="http://arxiv.org/abs/1406.2661v1"&gt;arxiv.org/abs/1406.2661v1&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Kingma, Diederik P., and Jimmy Ba. “Adam: A Method for Stochastic Optimization.” &lt;a href="http://arxiv.org/"&gt;ArXiv.org&lt;/a&gt;, 30 Jan. 2017, &lt;a href="http://arxiv.org/abs/1412.6980"&gt;arxiv.org/abs/1412.6980&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;“THE MNIST DATABASE.” MNIST Handwritten Digit Database, Yann LeCun, Corinna Cortes and Chris Burges, &lt;a href="http://yann.lecun.com/exdb/mnist/"&gt;yann.lecun.com/exdb/mnist/&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Understanding Categorical Cross-Entropy Loss, Binary Cross-Entropy Loss, Softmax Loss, Logistic Loss, Focal Loss and All Those Confusing Names, &lt;a href="http://gombru.github.io/2018/05/23/cross_entropy_loss/"&gt;gombru.github.io/2018/05/23/cross_entropy_loss/&lt;/a&gt;.&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>gan</category>
      <category>vision</category>
      <category>machinelearning</category>
    </item>
    <item>
      <title>5 techniques to Idiomatic Python (Loops)</title>
      <dc:creator>Idiomatic Programmers</dc:creator>
      <pubDate>Fri, 21 Aug 2020 06:44:53 +0000</pubDate>
      <link>https://dev.to/idiomprog/5-techniques-to-idiomatic-python-loops-3h85</link>
      <guid>https://dev.to/idiomprog/5-techniques-to-idiomatic-python-loops-3h85</guid>
      <description>&lt;p&gt;Python is, in my opinion, one of the easiest and most versatile languages in computer science. If you write python code correctly, it is difficult to differentiate a python code from pseudo-code. But sometimes, in the process of writing the most beautiful python code, most developers forget one thing: the execution speed of the code.&lt;/p&gt;

&lt;p&gt;You can write code that is so readable and a layman can confuse it as English written by someone with bad grammar skills, yet it is understandable. But that code takes more than 300ms to run. That might not be that much of a delay but in the programming world, it is a serious problem.&lt;/p&gt;

&lt;p&gt;On the other hand, one can write the same code in a different idiom that it takes less than 10ms to run. But, even expert python developers undergo a hard time understanding it.&lt;/p&gt;

&lt;p&gt;It is thus very imported, for a developer to strike a balance between these two extremes. These kinds of code are known as Idiomatic Code in the industry.&lt;/p&gt;

&lt;p&gt;Idiomatic Code, by definition, is a code that does a common task in a common way for your language. In other words, idiomatic code is any code that is easy to read and at the same time, is extremely efficient.&lt;/p&gt;

&lt;p&gt;I follow Raymond Hettinger (&lt;a href="https://twitter.com/raymondh"&gt;@raymondh&lt;/a&gt;) a lot on twitter, he is one of the core developers in the Python community and he has contributed a lot of code in the Python repository to make the python language more idiomatic.&lt;/p&gt;

&lt;p&gt;In this blog, I will go through some of the techniques that will help you improve your python code. Starting with:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. range()
&lt;/h3&gt;

&lt;p&gt;Let's start from the obvious, say you need to iterate from 2 to 10. So if you're like an absolute beginner you might write something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
    &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Something like this works and is very understandable, it is not a scalable approach. What if you want to loop through 2 to 2 million.&lt;/p&gt;

&lt;p&gt;In situations like this, you can use the &lt;code&gt;range(stop)&lt;/code&gt; or &lt;code&gt;range(start, stop, [step,])&lt;/code&gt; built-in function.&lt;/p&gt;

&lt;p&gt;the &lt;em&gt;range&lt;/em&gt; function automatically generates the list for you. For example, you can rewrite the above code as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;11&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice how I wrote start from 2 and end at 11 and not 10. This is because the range function loops till &lt;code&gt;stop - 1&lt;/code&gt;. There is one more parameter in range function other than the start and stop, that is the step. Step determines how many numbers the range have to skip.&lt;/p&gt;

&lt;p&gt;Let's say you need to print all even numbers from 2 to 10, in that case, the skip parameter will be 2. By default, it is 1.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;11&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# OUTPUT: 2 4 6 8 10
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now let's say that you need to loop through a list. With the knowledge of range(), you might do this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;cloths&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'shirt'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'hat'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'socks'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'shorts'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cloths&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
  &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cloths&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But in python, there is a better way:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;cloths&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'shirt'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'hat'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'socks'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'shorts'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;cloth&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;cloths&lt;/span&gt;
  &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cloth&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. zip()
&lt;/h3&gt;

&lt;p&gt;Let's say you have two lists, colour and cloths, of different sizes and you want to pair them until the smaller list is over. In this case, you can write a code like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;colours&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'pink'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'red'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'green'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;cloths&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'shirt'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'hat'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'socks'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'shorts'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;colours&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cloths&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;colours&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;cloths&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

&lt;span class="c1"&gt;# OUTPUT
# pink shirt
# red hat
# green socks
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Which is good, but you can also use the in-built function &lt;code&gt;zip(*iterables)&lt;/code&gt; the best thing about this function is that you can pass any number of lists, not just two. Let me rewrite the above code and then explain to you how zip works.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;colours&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'pink'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'red'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'green'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;cloths&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'shirt'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'hat'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'socks'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'shorts'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;colour&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cloth&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;zip&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;colours&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cloths&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;colour&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cloth&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# OUTPUT
# pink shirt
# red hat
# green socks
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You might have guessed, zip takes any number of lists and returns another list that contains one element from each list. As you can see, both version produces the same output but the second one looks cleaner.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. reversed()
&lt;/h3&gt;

&lt;p&gt;If you want to loop over a list in reverse order, the traditional method was something like this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;cloths&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'shirt'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'hat'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'socks'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'shorts'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cloths&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
  &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cloths&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;


&lt;span class="c1"&gt;# Output
# -------
# shorts
# socks
# hat
# shirt
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But with Python, you can use the builtin function called reversed(). Take a look at this example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;cloths&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'shirt'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'hat'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'socks'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'shorts'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;cloth&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;reversed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cloths&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
  &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cloth&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="c1"&gt;# Output
# -------
# shorts
# socks
# hat
# shirt
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The second one is cleaner and faster than the first one.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. enumerate()
&lt;/h3&gt;

&lt;p&gt;You want to loop through a list along with the index. It's pretty straight forward in traditional programming:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;cloths&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'shirt'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'hat'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'socks'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'shorts'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cloths&lt;/span&gt;&lt;span class="p"&gt;)):&lt;/span&gt;
  &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cloths&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;


&lt;span class="c1"&gt;# Output
# -------
# 0 shorts
# 1 socks
# 2 hat
# 3 shirt
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But there is a cleaner and more efficient way in python:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;cloths&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'shirt'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'hat'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'socks'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'shorts'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cloth&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;enumerate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cloths&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
  &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cloth&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="c1"&gt;# OUTPUT
# -------
# 0 shorts
# 1 socks
# 2 hat
# 3 shirt
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  5. sorted()
&lt;/h3&gt;

&lt;p&gt;You need to loop over a list in sorted order, instead of running a sorting algorithm, you can use the sorted() built-in method.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;nums&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;sorted&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
  &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# OUTPUT
# ------
# 1
# 2
# 2
# 3
# 5
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The python sorted function uses Tim Sort with an average complexity of n*log(n)&lt;/p&gt;

&lt;p&gt;For reverse sorting, you can use the attribute&lt;br&gt;
&lt;br&gt;
 &lt;code&gt;sorted(nums, reverse=True)&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;What you want to sort a list of strings.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;cloths&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'shirt'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'hat'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'socks'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'shorts'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;cloth&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;sorted&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cloths&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
  &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cloth&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# OUTPUT
# ------
# hat
# shirt
# shorts
# socks
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It will sort based on letters, but what if you want to sort based on length of the string, you can do that with key attribute. For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;cloths&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'shirt'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'hat'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'socks'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'shorts'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;cloth&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;sorted&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cloths&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
  &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cloth&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# OUTPUT
# ------
# hat
# shirt
# socks
# shorts
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So that was 5 techniques using with you can make your python code more idiomatic.&lt;/p&gt;

</description>
      <category>python</category>
      <category>idiomatic</category>
      <category>loops</category>
    </item>
    <item>
      <title>Fixing Up Permissions After Data Migration in Django</title>
      <dc:creator>Udit Mittal</dc:creator>
      <pubDate>Tue, 11 Aug 2020 14:06:07 +0000</pubDate>
      <link>https://dev.to/idiomprog/fixing-up-permissions-after-data-migration-in-django-6k1</link>
      <guid>https://dev.to/idiomprog/fixing-up-permissions-after-data-migration-in-django-6k1</guid>
      <description>&lt;p&gt;Hello djangonauts, today I wanna talk about a problem that I faced while working with Django. So here's the thing I just recently performed a major release at work, the database had to be changed since we had newer migrations and database structure. Naturally I had to import some data from my older database to the new one, which for most of the part could safely be done using fixtures (or so I thought). So I would like to share some tips and things that I learned recently because of it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Tip #1
&lt;/h3&gt;

&lt;p&gt;Always exclude the &lt;a href="https://docs.djangoproject.com/en/3.0/ref/contrib/contenttypes/"&gt;Content Type&lt;/a&gt; table while exporting a fixture for data migration.&lt;/p&gt;

&lt;p&gt;It can be done as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python manage.py dumpdata &lt;span class="nt"&gt;--exclude&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;contenttypes
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Why? You may ask? It's because Django automatically creates these records when you perform the migrations for your apps. These records are basically used by django internally for schema management. So if you import them from the older database, Django would raise errors.&lt;/p&gt;

&lt;h3&gt;
  
  
  Tip #2
&lt;/h3&gt;

&lt;p&gt;Now if you were like me, you might have dumped your permissions records as well into the fixture, that's where the fun part comes in.&lt;/p&gt;

&lt;p&gt;Now since content type was created afresh for the newer database, so their ids were different from the one in my previous database. And the permissions records which had the foreign key field to the Content Type model, used the older ids, so this essentially messed up all my permissions.&lt;/p&gt;

&lt;p&gt;Usually if you're not making use of these, you can simply ignore them (which I wouldn't recommend personally). But since I was using these to provide staff accounts to people on the Django Admin with custom permissions, this meant that they might not have access to the right data or tables in the admin. So I thought, maybe I should manually fix these records and get done with it, but there were like 300 permissions in there, since there were many models, so I pondered whether there might be a better way to do it instead of doing it manually.&lt;/p&gt;

&lt;p&gt;After a little bit of research, I came across &lt;code&gt;update_permissions&lt;/code&gt;, a custom management command provided by &lt;a href="https://django-extensions.readthedocs.io/en/latest/command_extensions.html"&gt;django extensions&lt;/a&gt;, a very useful third party package I was already using in my project.&lt;/p&gt;

&lt;p&gt;So let me demonstrate how to use it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python manage.py update_permissions &lt;span class="nt"&gt;--apps&lt;/span&gt; news
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here we are passing the app name, for which we want to update permissions for, which being &lt;code&gt;news&lt;/code&gt; in my case.&lt;/p&gt;

&lt;p&gt;You can also update permissions for multiple apps at the same time, as shown below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python manage.py update_permissions &lt;span class="nt"&gt;--apps&lt;/span&gt; news, articles
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will create the permission records which are automatically created for you by Django when you create a new model, but got messed up in our case.&lt;/p&gt;

&lt;p&gt;In my case, I deleted all the records in the I had previously present in my Permissions table on the database and created them afresh using the command I just showed you above.&lt;/p&gt;

&lt;p&gt;So that's it for today's "Today I Learned", until next time.&lt;/p&gt;

</description>
      <category>django</category>
      <category>python</category>
      <category>migrations</category>
      <category>todayilearned</category>
    </item>
  </channel>
</rss>
