What are the differences between Ruby on Rails and Django?

Ruby on Rails is an open source web application framework which comes under MIT license. Django is an open-source MVT(Model View Template) framework which is used for building web applications.

The Ultimate VueJs and Django CRUD Tutorial

The Ultimate VueJs and Django CRUD Tutorial

The Ultimate VueJs and Django CRUD Tutorial - In this tutorial, We show you how to build an API with Django REST Framework and a SPA with Vue.js.

Originally published by  Junior Gantin at dunebook.com

As a developer, CRUD (Create-Read-Update-Delete) is one of the basic operations to know. In this tutorial, I’ll show you how to build an API with Django REST Framework and a SPA with Vue.js. I am going to show you step by step from scratch.

Take a look at the CRUD app we will build:


CRUD API with Django REST Framework

Django REST framework is a powerful and flexible toolkit for building Web APIs. Open your favorite command-line interface and make sure to install Pipenv. Pipenv is one of the best tools to manage Python project dependencies. alternatively, you can use CodeMix IDE for fast and smooth Vue and Python app development.

mkdir subscription-api
cd subscription-api
pipenv install --three
pipenv shell
pipenv install django
pipenv install django-rest-framework

BashCopy

Right now, we’ve installed Django and Django REST Framework. Let’s create a Django project and a Django app:

./manage.py startproject subscription-api .
./manage.py startapp subscriptions

So make sure to add subscriptions and restframework to our list of INSTALLEDAPPS in the settings.py file.

INSTALLED_APPS = [
  'django.contrib.admin',
  'django.contrib.auth',
  'django.contrib.contenttypes',
  'django.contrib.sessions',
  'django.contrib.messages',
  'django.contrib.staticfiles',
  'rest_framework',
  'subscriptions',
]

Our database model will contain Subscription model only. Let’s create 6 fields:

# subscriptions/models.py
from django.db import models

class Subscription(models.Model):
    name = models.CharField(max_length=255)
    description = models.TextField()
    currency = models.CharField(max_length=255)
    amount = models.IntegerField()
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    def str(self):
        return self.name

Now let’s update our database by first creating a new migration file and then applying it.

./manage.py makemigrations
./manage.py migrate

Create a serializer to convert our data into JSON format:

# subscriptions/serializers.py
from rest_framework import serializers
from .models import Subscription

class SubscriptionSerializer(serializers.ModelSerializer):
    class Meta:
        model = Subscription
        fields = ('name', 'description', 'currency',
            'amount', 'created_at', 'updated_at'
        )

Django REST Framework provides class-based generic API views. Update the views.py file:

# subscriptions/views.py
from .models import Subscription
from .serializers import SubscriptionSerializer
from rest_framework import generics

class SubscriptionList(generics.ListCreateAPIView):
    queryset = Subscription.objects.all()
    serializer_class = SubscriptionSerializer

class SubscriptionDetail(generics.RetrieveUpdateDestroyAPIView):
    queryset = Subscription.objects.all()
    serializer_class = SubscriptionSerializer

Let’s add our API endpoints.

# subscription_api/urls.py
from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('api', include('subscriptions.urls')),
    path('admin/', admin.site.urls),
]


# subscriptions/urls.py
from django.urls import path
from rest_framework.urlpatterns import format_suffix_patterns
from subscriptions import views

urlpatterns = [
    path('subscriptions/', views.SubscriptionList.as_view()),
    path('subscriptions/<int:pk>/', views.SubscriptionDetail.as_view()),
]

Start the server.

./manage.py runserver

Your browsable API is ready.

 

Let’s add Cross-Origin Resource Sharing (CORS) headers to responses with django-cors-headers:

pipenv install django-cors-headers

And then add it to your installed apps:

# subscription_api/settings.py
INSTALLED_APPS = [
    ...
    'corsheaders',
    ...
]

You will also need to add a middleware class to listen in on responses:

# subscription_api/settings.py
MIDDLEWARE = [
    ...
    'corsheaders.middleware.CorsMiddleware',
    'django.middleware.common.CommonMiddleware',
    ...
]

Just allow all origins to make cross-site HTTP requests:

# subscription_api/settings.py
CORS_ORIGIN_ALLOW_ALL = True
Vue.js CRUD REST API Consumption

Make sure you have the latest version of vue-cli installed.

vue create subscription-app
cd subscription-app
yarn add axios bootstrap bootstrap-vue vee-validate

We just create a new Vue.js project and installed:

  • axios: a great HTTP client library;
  • bootstrap and bootstrap-vue: a library to quickly integrate Bootstrap 4 components with Vue.js;
  • vue-validate: validate HTML inputs and Vue components the easy way.

Inside src/components folder, create the following Vue components:

  • Index.vue
  • Create.vue
  • Edit.vue

Make sure to import bootstrap and vee-validate in your main.js:

// src/main.js
...
import BootstrapVue from "bootstrap-vue";
import VeeValidate from "vee-validate";

import "bootstrap/dist/css/bootstrap.min.css";
import "bootstrap-vue/dist/bootstrap-vue.css";

Vue.use(BootstrapVue);
Vue.use(VeeValidate);
...

Now, we need to define our routes.

import Vue from "vue";
import Router from "vue-router";

Vue.use(Router);

export default new Router({
  routes: [
    {
      path: "/",
      redirect: '/index'
    },
    {
      path: "/create",
      name: "create",
      component: () => import("./components/Create.vue")
    },
    {
      path: "/edit/:id",
      name: "edit",
      component: () => import("./components/Edit.vue")
    },
    {
      path: "/index",
      name: "index",
      component: () => import("./components/Index.vue")
    },
  ]
});

Each route should map to a component we created. We created a redirection to redirect from /to /index.

The next step should be to define a router view in App.vue file.

Index.vue

So the first file called will be Index.vue. This component will display all subscriptions.

Let’s explain this deeper. We need to get all subscriptions from our API. Create a property called susbscriptions:

...
    data() {
        return {
            subscriptions: []
        }
    },
...

Create a method which gets all subscriptions from server with axios:

...
all: function () {
        axios.get('http://127.0.0.1:8000/api/subscriptions/')
            .then( response => {
                this.subscriptions = response.data
            });
    }
...

Call method when Index component is created:

...
created() {
    this.all();
},
...

The Index template part is just a Bootstrap card component with a for-loop.

We create a delete button into the template.

<button
    class="btn btn-danger btn-sm ml-1"
    v-on:click="deleteSubscription(subscription)">
    Delete
</button>

deleteSubscription is called when the button is clicked.

deleteSubscription: function(subscr) {
    if (confirm('Delete ' + subscr.name)) {
        axios.delete(http://127.0.0.1:8000/api/subscriptions/${subscr.id})
            .then( response => {
                this.all();
            });
    }
},

This method will call your API after you confirm the deletion.

Create.vue

This file will create and store a subscription. We’ll use vee-validate which is a template based validation library.

We create a property called subscription and a boolean called submitted:

...
subscription: {
    name: '',
    currency: '',
    amount: '',
    description: '',
},
submitted: false
...

All we need is to add the v-validate directive to the input we wish to validate. Like below:

<input
    type="text"
    class="form-control"
    id="name"
    v-model="subscription.name"
    v-validate="'required'"
    name="name"
    placeholder="Enter name">

The CSS class we bind is just a Bootstrap 4 HTML5 form validation hint wich display invalid-feedback block.

<input
...
    :class="{
        'is-invalid':
            errors.has('subscription.name')
        && submitted}">

So let’s store our subscription.

create: function (e) {
    this.$validator.validate().then(result => {
        this.submitted = true;
        if (!result) {
            return;
        }
        axios
            .post('http://127.0.0.1:8000/api/subscriptions/',
                this.subscription
            )
            .then(response => {
                this.$router.push('/');
            })
    });
}

We make a HTTP request and return to / path when everything works.

Edit.vue

When the Edit.vue component is loaded, then we fetch the subscription data from the database and then display it inside the same form we used in Create.vue.

I hope this is helpful to you. You can check out the subscription-app repo.

Originally published by  Junior Gantin at dunebook.com

==================================

Thanks for reading :heart: If you liked this post, share it with all of your programming buddies! Follow me on Facebook | Twitter

Learn More

☞ Nuxt.js - Vue.js on Steroids

☞ Vue JS 2 - The Complete Guide (incl. Vue Router & Vuex)

☞ Python and Django Full Stack Web Developer Bootcamp

☞ Django 2.1 & Python | The Ultimate Web Development Bootcamp

☞ Master Vuejs from scratch (incl Vuex, Vue Router)

☞ Vue JS 2.0 - Mastering Web Apps

☞ Vue.js Essentials - 3 Course Bundle

☞ MEVP Stack Vue JS 2 Course: MySQL + Express.js + Vue.js +PHP

☞ Python eCommerce | Build a Django eCommerce Web Application

☞ Python Django Dev To Deployment

☞ The Complete JavaScript Course 2019: Build Real Projects!

☞ JavaScript: Understanding the Weird Parts

☞ The Modern JavaScript Bootcamp (2019)

Creating a Weather App in Django Using Python Requests

Creating a Weather App in Django Using Python Requests

In this tutorial, I'll create a weather app in Django that gets the current weathers for multiple cities. To do this, I'll use Python Requests to call the Open Weather Map API.

In this tutorial, I'll create a weather app in Django that gets the current weathers for multiple cities. To do this, I'll use Python Requests to call the Open Weather Map API.

To get the current weather data, we'll use the Open Weather Map API.

Table of Contents

  • Installation
  • The Admin Dashboard
  • Creating the App
  • Adding the Template and View
  • Using the Weather API
  • Displaying the Data in the Template
  • Creating the Form
  • Conclusion

Even though the app is simple, we'll work with a database and create a form, so the concepts used here are applicable to more complicated projects.

The code in this article was written with Python 3 and Django 2.0, so to follow this tutorial, you should be somewhat familiar with both. If you'd like an introduction to both, check out our article called Build Your First Python and Django Application. That article uses Django 1.X, but you'll see the only difference is in how URLs are defined.

Here's what our app is going to look like when we're done.

Creating a Weather App in Django Using Python Requests

You can see a live demo of the app on Python Anywhere.

All the code for this article is on GitHub.

If you'd like to see a video of me building this app, check out this YouTube video:

Installation

Installing Django is like installing any other Python library: you can start a virtual environment and run pip to install Django, or you can do what I do and create a project directory, run pipenv and then activate the pipenv shell. Either method works, but for this article I'll be using pipenv.

pipenv install django

This will install the latest version of Django for you. At the time of writing this article, Django is on version 2.0.4.

Once you have Django installed, create and navigate to a directory for this project if you haven't already. Once there, you can run the startproject command that Django gives you to generate the project.

django-admin startproject the_weather

Django should have created a few new files in your directory.

Let's try starting up our development server. To do that, navigate to the new directory and use manage.py to run the runserver command in your terminal:

cd the_weather
python manage.py runserver

If you look at your terminal, you should see the URL for your app. By default it should be 127.0.0.1:8000.

Creating a Weather App in Django Using Python Requests

Open up your browser and go to that URL.

Creating a Weather App in Django

If you see that, you know you've set up Django correctly. You definitely should see it because we haven't even tried modifying the code yet.

The Admin Dashboard

Next we want to take a look at the admin dashboard Django gives us. To do that, first we have to migrate our database, which means Django will create the pre-defined tables that are needed for the default apps. To do this, you simply run the migrate command. Stop the server by using CTRL+C and then run:

python manage.py migrate

By running that command, Django has created a SQLite database for you, the default database in the settings, and it has added several tables to that database. You'll know if the database was created if you see a new db.sqlite3 file in your project directory.

One of the tables Django gives us is a user table, which will be used to store any users in our app. The app we're building doesn't need any users, but having an admin user will allow us to access the admin dashboard.

To create an admin user, we'll run the createsuperuser command.

python manage.py createsuperuser

Follow the instructions by giving a username, email address, and a password for your admin user. Once you've done that, you'll need to start the server again and navigate to the admin dashboard.

python manage.py runserver

Then go to 127.0.0.1:8000/admin.

The reason why we can go to this page is because because admin is set up in our urls.py (the reason why we can see the congratulations page is because Django gives you that until you add your own URLs).

If you login with the username and password you just created, you should see this page.

Creating a Weather App in Django Using Python Requests

Groups and users represent two models Django gives us access to. Models are just code representations of tables in a database. Even though Django created more tables, there's no need to access the rest of them directly, so no models were created.

If you click on 'user' you should see more detail about the user table, and you should see the user you created. I recommend clicking different links in the dashboard to see what's there. Just be careful not to delete your user, otherwise you'll have to run createsuperuser again.

Let's leave the admin dashboard for now and go to the code. We need to create an app inside of our project for our weather app.

Creating the App

In Django, you can separate functionality in your project by using apps. I think app is a confusing name because we usually refer to an app as being the entire project, but in the case of Django, app refers to a specific piece of functionality in your project. For example, if you look at the settings.py file, you'll see the INSTALLED_APPS list.

The first of the installed apps, django.contrib.admin is what we just used. It handles all the admin functionality and nothing else. Another app in our project by default are things like auth, which allowed us to log into our admin dashboard.

In our case, we need to create a new app to handle everything related to showing the weather. To create that app, stop the server with CTRL+C and run:

python manage.py startapp weather

By running startapp, Django has added a new directory and more files to our project.

With the latest files generated, let's create a new file called urls.py in our app directory.

#the_weather/weather/urls.py

from django.urls import path

urlpatterns = [
]

This file is similar to the urls.py in our the_weather directory. The difference is that this urls.py file contains all the URLs that are relevant to the app itself.

We're not specifying a URL yet, but we can set up the project to recognize our app and route any URLs specific to our app to the app urls.py file.

First, go to the INSTALLED_APPS list and add this app to the list.

#the_weather/the_weather/settings.py
...

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'weather',
]

...

This lets Django know we want to use the weather app in our project. By doing this, Django will know where to look for migrations and the URLs.

Next, we need to modify the original urls.py to point to our app urls.py file. To do that, we add a line under the existing path for the admin dashboard. We also need to import 'include' so we can point to our app urls.py file.

#the_weather/the_weather/urls.py

from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', include('weather.urls')),
]

The empty string means that we won't use an endpoint for the entry point to our app. Instead we'll let the app handle any specific endpoints. We could have easily put something like path('weather/', ...), which would have meant we would have to type 127.0.0.1:8000/weather/ to get anything associated with our weather app. But since our project is simple, we won't be doing that here.

Adding the Template and View

Now for the first interesting thing we're going to do. We need to add the template to our project.

A template in Django is just an HTML file that allows for extra syntax that makes the template dynamic. We'll be able to do things like add variables, if statements, and loops, among other things.

To start, I have an HTML file that's free any template syntax, but this will be enough for us to start.

We're going to create a template directory to put this file in.

cd weather
mkdir templates && cd templates
mkdir weather

We also created another directory with the same name as our app. We did this because Django combines all the templates directories from the various apps we have. To prevent filenames being duplicated, we can use the name of our app to prevent the duplicates.

Inside of the weather directory, create a new file called index.html. This will be our main template. Here's the HTML we'll use for the template.

<!-- the_weather/weather/templates/weather/index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>What's the weather like?</title>
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bulma/0.6.2/css/bulma.css" />
</head>
<body>
    <section class="hero is-primary">
        <div class="hero-body">
            <div class="container">
                <h1 class="title">
                    What's the weather like?
                </h1>
            </div>
        </div>
    </section>
    <section class="section">
        <div class="container">
            <div class="columns">
                <div class="column is-offset-4 is-4">
                    <form method="POST">
                        <div class="field has-addons">
                            <div class="control is-expanded">
                                <input class="input" type="text" placeholder="City Name">
                            </div>
                            <div class="control">
                                <button class="button is-info">
                                    Add City
                                </button>
                            </div>
                        </div>
                    </form>
                </div>
            </div>
        </div>
    </section>
    <section class="section">
        <div class="container">
            <div class="columns">
                <div class="column is-offset-4 is-4">
                    <div class="box">
                        <article class="media">
                            <div class="media-left">
                                <figure class="image is-50x50">
                                    <img src="http://openweathermap.org/img/w/10d.png" alt="Image">
                                </figure>
                            </div>
                            <div class="media-content">
                                <div class="content">
                                    <p>
                                        <span class="title">Las Vegas</span>
                                        <br>
                                        <span class="subtitle">29° F</span>
                                        <br> thunderstorm with heavy rain
                                    </p>
                                </div>
                            </div>
                        </article>
                    </div>
                </div>
            </div>
        </div>
    </section>
    <footer class="footer">
    </footer>
</body>
</html>

Now that we have our template created, let's create a view and URL combination so we can actually see this in our app.

Views in Django are either functions or classes. In our case since we're creating a simple view, we'll create a function. Add this function to your views.py:

#the_weather/weather/views.py

from django.shortcuts import render

def index(request):
    return render(request, 'weather/index.html') #returns the index.html template

We're naming our view 'index' because it will be at the index of our app, which is the root URL. To have the template render, we return request, which is necessary for the render function, and the name of the template file we want to render, in this case weather/index.html.

Let's add the URL that will send the request to this view. In the urls.py for the app, update the urlpatterns list.

#the_weather/weather/urls.py

from django.urls import path
from . import views

urlpatterns = [
    path('', views.index),  #the path for our index view
]

This allows us to reference the view we just created.

Django is going to match any URL without an endpoint and route it to the view function we created.

Go back to your project root, start the server, and go to 127.0.0.1:8000 again.

python manage.py runserver

Creating a Weather App in Django Using Python Requests

What we see now is just the result of the HTML you have in index.html file. You'll see an input to add a city and the weather for Las Vegas. However, the form doesn't work and the weather is just a placeholder, but don't worry, because we'll be creating those for this app.

Using the Weather API

What we want to do now is sign up for the Open Weather Map API. This will allow us to get the actual weather for any cities that we add in our app.

Go to the site, create an account and then go to the API keys on their dashboard. Enter a name and generate a new API key. This key will allow us to use the API to get the weather.

Creating a Weather App in Django Using Python Requests

The one endpoint we'll use is below, so you can see the actual data that gets returned by modifying the following URL with your API key and navigating to the URL in your browser. It may take a few minutes for your API key to become active, so if it doesn't work at first, try again in after a few minutes.

http://api.openweathermap.org/data/2.5/weather?q=las%20vegas&units=imperial&appid=YOUR_APP_KEY

With that, let's add in a request to get the data into our app.

First, we'll need to install requests so we can call the API from inside our app.

pipenv install requests

Let's update our index view to send a request to the URL we have.

#the_weather/weather/views.py

from django.shortcuts import render
import requests

def index(request):
    url = 'http://api.openweathermap.org/data/2.5/weather?q={}&units=imperial&appid=YOUR_APP_KEY'
    city = 'Las Vegas'
    city_weather = requests.get(url.format(city)).json() #request the API data and convert the JSON to Python data types

    return render(request, 'weather/index.html') #returns the index.html template

With those three lines, we're adding the URL that will send a request to. We'll make the part for the city a placeholder for when we allow users to add their own cities.

For now we'll set the city to be Las Vegas, but later this will be set to the cities from the database.

Finally, we'll send the request to the URL using the city and get the JSON representation of that city. If we print that to the console we can see the same data we saw when we put the URL in our address bar.

If you start your server again and reload the page, you'll see the data get printed to your console.

Creating a Weather App in Django Using Python Requests

Displaying the Data in the Template

Next, we need to pass the data to the template so it can be displayed to the user.

Let's create a dictionary to hold all of the data we need. Of the data returned to us, we need temp, description, and icon.

#the_weather/weather/views.py

def index(request):
    ...
    weather = {
        'city' : city,
        'temperature' : city_weather['main']['temp'],
        'description' : city_weather['weather'][0]['description'],
        'icon' : city_weather['weather'][0]['icon']
    }

    return render(request, 'weather/index.html') #returns the index.html template

Now that we all the information we want, we can pass that to the template. To pass it to the template, we'll create a variable called context. This will be a dictionary that allows us to use its values inside of the template.

#the_weather/weather/views.py

def index(request):
    ...
    context = {'weather' : weather}
    return render(request, 'weather/index.html', context) #returns the index.html template

And then in render, we'll add the context as the third argument.

With the weather data added inside of context, let's go to the template to add the data.

Inside of the template, all we need to do is modify the HTML to use variables instead of the values I typed in. Variables will use {{ }} tags, and they will reference anything inside of your context dictionary.

Note that Django converts dictionary keys so you can only access them using dot notation. For example, weather.city will give us the city name. We don't use weather['city'] like we would in Python.

Find the box div, and update it to this:

<!-- the_weather/weather/templates/weather/index.html -->
<div class="box">
    <article class="media">
        <div class="media-left">
            <figure class="image is-50x50">
                <img src="http://openweathermap.org/img/w/{{ weather.icon }}.png" alt="Image">
            </figure>
        </div>
        <div class="media-content">
            <div class="content">
                <p>
                    <span class="title">{{ weather.city }}</span>
                    <br>
                    <span class="subtitle">{{ weather.temperature }}° F</span>
                    <br> {{ weather.description }}
                </p>
            </div>
        </div>
    </article>
</div>

With all the variables replaced, we should now see the current weather for our city.

Creating a Weather App in Django Using Python Requests

Great! Now we can see the weather for one city, but we had to hard code the city. What we want to do now is pull from the database and show the cities that are in our database.

To do that, we'll create a table in our database to hold the cities that we want to know the weather for. We'll create a model for this.

Go to the models.py in your weather app, and add the following:

#the_weather/weather/models.py

from django.db import models

class City(models.Model):
    name = models.CharField(max_length=25)

    def _str_(self): #show the actual city name on the dashboard
        return self.name

    class Meta: #show the plural of city as cities instead of citys
        verbose_name_plural = 'cities'

This will create a table in our database that will have a column called name, which is the name of the city. This city will be a charfield, which is just a string.

To get these changes in the database, we have to run makemigrations to generate the code to update the database and migrate to apply those changes. So let's do that now.

python manage.py makemigrations
python manage.py migrate

We need to make it to where we can see this model on our admin dashboard. To do that, we need to register it in our admin.py file.

#the_weather/weather/admin.py

from django.contrib import admin
from .models import City

admin.site.register(City)

You'll see the city as an option on the admin dashboard.

Creating a Weather App in Django Using Python Requests

We can then go into the admin dashboard and add some cities. I'll start with three: London, Tokyo, and Las Vegas.

Creating a Weather App

With the entries in the database, we need to query these entries in our view. Start by importing the City model and then querying that model for all objects.

#the_weather/weather/views.py

from django.shortcuts import render
import requests
from .models import City
#the_weather/weather/views.py

def index(request):
    url = 'http://api.openweathermap.org/data/2.5/weather?q={}&units=imperial&appid=YOUR_APP_KEY'
    cities = City.objects.all() #return all the cities in the database
    ...

Since we have the list of cities, we want to loop over them and get the weather for each one and add it to a list that will eventually be passed to the template.

This will just a variation of what we did in the first case. The other difference is we are looping and appending each dictionary to a list. We'll remove the original city variable in favor a city variable in the loop.

#the_weather/weather/views.py

def index(request):
    ...
    weather_data = []

    for city in cities:

        city_weather = requests.get(url.format(city)).json() #request the API data and convert the JSON to Python data types

        weather = {
            'city' : city,
            'temperature' : city_weather['main']['temp'],
            'description' : city_weather['weather'][0]['description'],
            'icon' : city_weather['weather'][0]['icon']
        }

        weather_data.append(weather) #add the data for the current city into our list

    context = {'weather_data' : weather_data}
    ...

Cool, so we have the data. Now let's update the context to pass this list instead of a single dictionary.

#the_weather/weather/views.py

    ...
    context = {'weather_data' : weather_data}
    ...

Next, inside of the template, we need to loop over this list and generate the HTML for each city in the list. To do this, we can put a for loop around the HTML that generates a single box for the city.

<!-- the_weather/weather/index.html -->
<div class="column is-offset-4 is-4">
    {% for weather in weather_data %}
    <div class="box">
        <article class="media">
            <div class="media-left">
                <figure class="image is-50x50">
                    <img src="http://openweathermap.org/img/w/{{ weather.icon }}.png" alt="Image">
                </figure>
            </div>
            <div class="media-content">
                <div class="content">
                    <p>
                        <span class="title">{{ weather.city }}</span>
                        <br>
                        <span class="subtitle">{{ weather.temperature }}° F</span>
                        <br> {{ weather.description }}
                    </p>
                </div>
            </div>
        </article>
    </div>
    {% endfor %}
</div>

Awesome! Now we can see the data for all the cities we have in the database.

Creating the Form

The last thing we want to do is allow the user to add a city directly in the form.

To do that, we need to create a form. We could create the form directly, but since our form will have exactly the same field as our model, we can use a ModelForm.

Create a new file called forms.py.

#the_weather/weather/forms.py

from django.forms import ModelForm, TextInput
from .models import City

class CityForm(ModelForm):
    class Meta:
        model = City
        fields = ['name']
        widgets = {
            'name': TextInput(attrs={'class' : 'input', 'placeholder' : 'City Name'}),
        } #updates the input class to have the correct Bulma class and placeholder

To view the form, we need to create it in our view and pass it to the template.

To do that, let's update the index video to create the form. We'll replace the old city variable at the same time since we no longer need it. We also need to update the context so the form gets passed to the template.

#the_weather/weather/views.py

def index(request):
    ...
    form = CityForm()

    weather_data = []
    ...
    context = {'weather_data' : weather_data, 'form' : form}

Now in the template, let's update the form section to use the form from our view and a csrf_token, which is necessary for POST requests in Django.

<form method="POST">
    {% csrf_token %}
    <div class="field has-addons">
        <div class="control is-expanded">
            {{ form.name }}
        </div>
        <div class="control">
            <button class="button is-info">
                Add City
            </button>
        </div>
    </div>
</form>

With the form in our HTML working, we now need to handle the form data as it comes in. For that, we'll create an if block checking for a POST request. We need to add the check for the type of request before we start grabbing the weather data so we immediately get the data for the city we add.

#the_weather/weather/views.py

def index(request):
    cities = City.objects.all() #return all the cities in the database

    url = 'http://api.openweathermap.org/data/2.5/weather?q={}&units=imperial&appid=YOUR_APP_KEY'

    if request.method == 'POST': # only true if form is submitted
        form = CityForm(request.POST) # add actual request data to form for processing
        form.save() # will validate and save if validate

    form = CityForm()
    ...

By passing request.POST, we'll be able to validate the form data.

Now you should be able to type in the name of a city, click add, and see it show up. I'll add Miami as the next city.

Creating a Weather App in Django

When we drop out of the if block, the form will be recreated so we can add another city if we choose. The rest of the code will behave in the same way.

Conclusion

And that's it! We now have a way to keep track of the weather for multiple cities in our app.

In this article, we had to work with various parts of Django to get this working: views, models, forms, and templates. We also had to use the Python library requests to get the actual weather data. So even though the app is simple, you'll use many of the same concepts in apps with more complexity.

Serving React and Django together

Serving React and Django together

In this article, we’ll create an API using Django REST Framework and a React project (frontend) which will consume the API. The idea is very simple, React will fetch some book names from the backend (Django) and render them.

In this article, we’ll create an API using Django REST Framework and a React project (frontend) which will consume the API. The idea is very simple, React will fetch some book names from the backend (Django) and render them.

Reactjs is a nice framework for frontend and Django REST framework (DRF) is another great framework for API development. I wonder how to serve React and Django projects in the same server and same port! Finally, I’ve reached a solution and today I’ll discuss it.

Backend (Django) project

I’m using Django 2 for this project. At first, create a Django project named book.

Install django-rest-framework using pip install django-rest-framework and add rest_framework to INSTALLED_APPS list in settings.py .

Create two apps named api and core using python manage.py startapp apiand python manage.py startapp core , then add the app names to INSTALLED_APPS list in settings.py .

This is our INSTALLED_APPS list in settings.py :

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',

    "rest_framework",
    
    "api",
    "core",
]

Edit /api/views.py and add the following codes :

from rest_framework.response import Response
from rest_framework import status
from rest_framework.decorators import api_view


# This will return a list of books
@api_view(["GET"])
def book(request):
    books = ["Pro Python", "Fluent Python", "Speaking javascript", "The Go programming language"]
return Response(status=status.HTTP_200_OK, data={"data": books})

Configure the url in book/urls.py (url configuration can be done in more elegant approach but I’m skipping it for brevity) :

from django.urls import path

from api.views import book
from core.views import index

urlpatterns = [
    path("book/", book, name="book"),
]

Start the server using python manage.py runserver , (it will run the server at default port 8000).

Test our API

Postman is a great tool for testing APIs. Open Postman and navigate to “http://127.0.0.1:8000/book/” :

Our API is working fine! Now we’ll develop the frontend using React.

Frontend (React) Project

We’ll use create-react-app package to create React project. At first, install “create-react-app” package using npm install create-react-app .

Now create the react app named “book-frontend” create-react-app book-frontend inside the project directory (book).

Change the current directory to “book-frontend” and run npm start .

It will run our frontend server at default port 3000.

Navigate to localhost:3000 in your favorite browser (I’m using google chrome) :

We’ll use two more packages in the frontend. Let’s install them first:

axios : npm install axios

react-router-dom : npm install react-router-dom

Create a folder named Component inside src folder, then inside Component folder create a folder named Book. Inside book create a javascript file name index.js (That means: /src/Component/Book/index.js).

Put the following code into index.js (this code will fetch data from backend and render them to frontend).

Our index.js :

import React, { Component } from "react";

import axios from "axios";

export default class Book extends Component {
  constructor(props) {
    super(props);
    this.state = {
    books:[],
    };
    this.loadBooks = this.loadBooks.bind(this);
  }

  componentWillMount() {
    this.loadBooks();
  }

  async loadBooks()
  {
    const promise = await axios.get("http://localhost:3000/book");
    const status = promise.status;
    if(status===200)
    {
      const data = promise.data.data;
      this.setState({books:data});
    }
  }

  render() {
    return(
      <div>
        <h1>Books</h1>
            {this.state.books.map((value,index)=>{return <h4 key={index}>{value}</h4>})}
      </div>
    )
  }
}

And modify App.js like this :

import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';

import { BrowserRouter as Router, Route, Link } from "react-router-dom";

import Book from "./Component/Book/index";

class App extends Component {
  render() {
    return (
      <Router>
        <Route path="/" exact component={Book} />
    </Router>
    );
  }
}

export default App;

All the features of our million dollar book app are complete now!

Navigate to localhost:3000 to see the output :

OPS! Nothing is showing without the word “books”, right?

Open the console of your browser :

We have to solve the CORS issue.

We can solve this issue using django-cors-headers library.

My settings.py solving CORS issue :

"""
Django settings for book project.
Generated by 'django-admin startproject' using Django 2.2.
For more information on this file, see
https://docs.djangoproject.com/en/2.2/topics/settings/
For the full list of settings and their values, see
https://docs.djangoproject.com/en/2.2/ref/settings/
"""

import os

# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))

# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/2.2/howto/deployment/checklist/

# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = '[email protected]@1op&r-xle13)k2x0vv([email protected](ep&4'

# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True

ALLOWED_HOSTS = []

# Application definition

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    "corsheaders",  # added to solve CORS

    "rest_framework",

    "api",
    "core",
]

MIDDLEWARE = [
    'corsheaders.middleware.CorsMiddleware',  # added to solve CORS
    'django.middleware.common.CommonMiddleware',  # added to solve CORS
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',



]

ROOT_URLCONF = 'book.urls'

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [os.path.join(BASE_DIR, 'book-frontend')]
        ,
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

WSGI_APPLICATION = 'book.wsgi.application'

# Database
# https://docs.djangoproject.com/en/2.2/ref/settings/#databases

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
    }
}

# Password validation
# https://docs.djangoproject.com/en/2.2/ref/settings/#auth-password-validators

AUTH_PASSWORD_VALIDATORS = [
    {
        'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
    },
]

# Internationalization
# https://docs.djangoproject.com/en/2.2/topics/i18n/

LANGUAGE_CODE = 'en-us'

TIME_ZONE = 'UTC'

USE_I18N = True

USE_L10N = True

USE_TZ = True

# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/2.2/howto/static-files/

STATIC_URL = '/static/'


CORS_ORIGIN_ALLOW_ALL = True # added to solve CORS

Now, navigate to localhost:3000 and see our desired output!

Serving React and Django together

This is the key point of this article, we’ll serve these two apps together in the same server.

Create the “build” version of our frontend app

Navigate to the book-frontend directory and run npm run build . This will create a build directory.

Then go to setting.pyand add the following lines :

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [os.path.join(BASE_DIR, 'book-frontend')]  #Look, we have added the root folder of frontend here
        ,
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]
STATIC_URL = '/static/'
STATICFILES_DIRS = (
    os.path.join(BASE_DIR, 'book-frontend', "build", "static"),  # update the STATICFILES_DIRS
)

Goto cors/view.py now, we will serve our frontend view from here. Update it like :

from django.shortcuts import render


def index(request):
return render(request, "build/index.html")

Update /book/urls.py :

from django.urls import path

from api.views import book

from core.views import index

urlpatterns = [
    path("book/", book, name="book"),
    path("", index, name="index")
]

Now close all the previous servers (if they’re active until now). Run the Django server using python manage.py runserver. Go to your browser and navigate to http://127.0.0.1:8000/ and BOOM! We’re serving our Django and React app in the same server!

How to Build an E-commerce Website with Django and Python

How to Build an E-commerce Website with Django and Python

Learn how to build an E-commerce website with Django and Python.

How to Build an E-commerce Website with Django and Python

💻 Project code: https://github.com/justdjango/django-ecommerce

💻 Original code: https://mdbootstrap.com/freebies/jquery/e-commerce/


⭐️ Course Contents ⭐️

⌨️ (0:00:00) Setup and project configuration

⌨️ (0:16:55) Adding items to a cart

⌨️ (0:54:09) Improving the UI

⌨️ (1:10:34) Creating an order summary

⌨️ (1:38:03) The checkout process

⌨️ (2:10:46) Handling payments with Stripe

⌨️ (2:37:33) Discount codes

⌨️ (3:07:41) Managing refunds

⌨️ (3:31:31) Default addresses

⌨️ (4:12:30) Saving credit card information

Thanks for reading

If you liked this post, share it with all of your programming buddies!

Follow us on Facebook | Twitter

Further reading about Python

Complete Python Bootcamp: Go from zero to hero in Python 3

Machine Learning A-Z™: Hands-On Python & R In Data Science

Python and Django Full Stack Web Developer Bootcamp

Complete Python Masterclass

Python Tutorial - Python GUI Programming - Python GUI Examples (Tkinter Tutorial)

Computer Vision Using OpenCV

OpenCV Python Tutorial - Computer Vision With OpenCV In Python

Python Tutorial: Image processing with Python (Using OpenCV)

A guide to Golang e-commerce

Building an e-commerce site with Gatsby, Netlify, and Stripe

Building a BigCommerce App Using Laravel and React


Python Django with Docker and Gitlab CI

Python Django with Docker and Gitlab CI

Python Django with Docker and Gitlab CI - In this article i will describe how we set up Gitlab CI to run tests for Django project. But first couple of words about what tools we were using...✈️✈️✈️✈️✈️

Python Django with Docker and Gitlab CI - In this article i will describe how we set up Gitlab CI to run tests for Django project. But first couple of words about what tools we were using..

For a project I was specifically asked to build an API using Python Django. So, my first starting point was to google “django cookiecutter” which immediately brought me to this amazing cookiecutter project. What I am going to demonstrate here is how to quickly setup the project (for the sake of completeness) and use Gitlab Continuous Integration to automatically unit test, run linters, generate documentation, build a container and release it.

Setup the project

We start with initiating the project using the mentioned cookiecutter project,although you can also use another cookiecutter or build on your existing project; you probably need to make some alterations here and there. Here is a small list of prerequisites:

  • you have docker installed locally
  • you have Python installed locally
  • you have a Gitlab account and you can push using ssh keys

Now, install cookiecutter and generate the project:

pip install "cookiecutter>=1.4.0"
cookiecutter https://github.com/pydanny/cookiecutter-django

Provide the options in any way you like, so the Django project will be created. Type y when asked to include Docker (because that is why we are here!!!).

Walk trough the options for the Django Cookiecutter

Enter the project, create a git repo and push it there:

cd my_django_api
git init
git add .
git commit -m "first awesome commit"
git remote add origin [email protected]:jwdobken/my-django-api.git
git push -u origin master

Obviously replace my-django-api with your project name and jwdobken with your own Gitlab account name.

You can read here how to develop running docker locally. It is something I do with all my projects of any type; the dev and production environments are more alike and it has been years since I worked with something like virtual environments and I am not missing it!

Add a test environment

Make a test environment by copying the local environment:

cp local.yml test.yml
cp requirements/local.txt requirements/test.txt
cp -r compose/local compose/test

In compose/test/django/Dockerfile change requirements/local.txt to requirements/test.txt . You can make more alterations to the test environment later.

The Gitlab-CI file

Finally we get to the meat. Here is the .gitlab-ci.yml file:

image: docker:latest
	services:
	  - docker:dind
	

	variables:
	  DOCKER_HOST: tcp://docker:2375
	  DOCKER_DRIVER: overlay2
	  CONTAINER_TEST_IMAGE: $CI_REGISTRY_IMAGE:$CI_BUILD_REF_SLUG
	  CONTAINER_RELEASE_IMAGE: $CI_REGISTRY_IMAGE:latest
	

	stages:
	  - test
	  - build
	  - release
	

	test:
	  stage: test
	  image: tiangolo/docker-with-compose
	  script:
	    - docker-compose -f test.yml build
	    # - docker-compose -f test.yml run --rm django pydocstyle
	    - docker-compose -f test.yml run --rm django flake8
	    - docker-compose -f test.yml run django coverage run -m pytest
	    - docker-compose -f local.yml run --rm django coverage html
	    - docker-compose -f local.yml run --rm django /bin/sh -c "cd docs && apk add make && make html"
	    - docker-compose -f local.yml run django coverage report
	  coverage: "/TOTAL.+ ([0-9]{1,3}%)/"
	  artifacts:
	    paths:
	      - htmlcov
	      - docs/_build
	    expire_in: 5 days
	

	build:
	  stage: build
	  script:
	    - docker login -u gitlab-ci-token -p $CI_BUILD_TOKEN $CI_REGISTRY
	    - docker build -t $CONTAINER_TEST_IMAGE -f compose/production/django/Dockerfile .
	    - docker push $CONTAINER_TEST_IMAGE
	

	release:
	  stage: release
	  script:
	    - docker login -u gitlab-ci-token -p $CI_BUILD_TOKEN $CI_REGISTRY
	    - docker pull $CONTAINER_TEST_IMAGE
	    - docker tag $CONTAINER_TEST_IMAGE $CONTAINER_RELEASE_IMAGE
	    - docker push $CONTAINER_RELEASE_IMAGE
	  only:
	    - master
	

	pages:
	  stage: release
	  script:
	    - mkdir -p public/coverage
	    - mv htmlcov/* public/coverage
	    - mkdir -p public/docs
	    - mv -v docs/_build/html/* public/docs
	  artifacts:
	    paths:
	      - public
	    expire_in: 30 days
	  only:
	    - master

The test stage builds the container stack in the test environment, runs the unit tests with flake8, copies the html coverage report and catches the total coverage. Also, we misuse the test build to generate the sphinxdocumentation for which we need to install Make.

The build stage builds the production container and pushes it to the Gitlab container registry.

The release stage pulls the build container and tags it as the latest release before pushing it to the container registry.

The page part publishes the test and documentation artifacts with Gitlab Pages.

Push your code to Gitlab where you should find a running pipeline.

the pipeline is running

the pipeline has succesfully finished

In the container registry of the project you can find two images: the latest master image and the latest release image. The page itself explains how to pull images from here to anywhere.

Badges

Gitlab enables badges on the repo page to give any specific information. On the Gitlab project page, go to Settings, go to Badges. Here you can add the following badges:

Pipeline status of the master branch:

  • Link: https://gitlab.com/%{project_path}/pipelines

  • Badge image URL: https://gitlab.com/%{project_path}/badges/%{default_branch}/pipeline.svg

Test coverage and report:

  • Link: https://.gitlab.io/my-django-api/coverage/

  • Badge image URL: https://gitlab.com/%{project_path}/badges/%{default_branch}/coverage.svg?job=test

Documentation:

  • Link:https://.gitlab.io/my-django-api/docs/

  • Badge image URL: https://img.shields.io/static/v1.svg?label=sphinx&message=documentation&color=blue

Note that the URL link of Gitlab Pages, for the test coverage report and documentation, is not straightforward. Replace your username with a groupname if you work in a group. In the case of a subgroup, provide the full path. Usually I end up with a bit of trial-and-error; this article explains most of it.

status badges shown on the repo page

Pydocstyle

Finally, I highly recommend to check the existence and quality of your docstrings using pydocstyle. Add the following line to requirements/test.txtand requirements/local.txt in the Code quality section:

pydocstyle==3.0.0  # https://github.com/PyCQA/pydocstyle

Add the following lines to setup.cfg to configure pydocstyle:

[pydocstyle]
match = (?!\d{4}_).*\.py

And finally add the following line to .gitlab-ci.yml in the script section of the test stage (just after the build):

- docker-compose -f test.yml run — rm django pydocstyle

Be warned that the project does not comply with pydocstyle by default, so you will have to complete the code with docstrings to pass the test again.

Finally

We now have a fresh Django project with a neat CI pipeline on Gitlab for automated unit tests, documentation and container image release. You can later include Continuous Deployment to the pipeline; I left it out of the scope, because it depends too much on your production environment. You can read more about Gitlab CI here.

Currently the pipeline is quite slow mainy caused by the build of the images. The running time can be accelerated by caching dependencies.

There is a soft (10GB) size restriction for registry on GitLab.com, as part of the repository size limit. Therefore, when the number of images increases, you probably need to archive old images manually.

===================================================================

Thanks for reading :heart: If you liked this post, share it with all of your programming buddies! Follow me on Facebook | Twitter