[PYTHON] Django's personal tips

This article is the last day of Django Advent Calendar 2019.

Introduction

Nice to meet you. Thank you.

I usually use Djnago to develop web applications.

-Siltrend

I enjoyed watching this year's Django Advent Calendar 2019 every day. All the articles were interesting and educational. So, in this article, the last day of this calendar, I'd like to organize some basic and personal tips for Django. I hope this article has contributed to the further spread of Django.

table of contents

-[Form Validation](#Form Validation) -[Send Http404](Send # http404) -[Execute instance acquisition and send Http404 if the object does not exist](# Perform instance acquisition and send -http404- if the object does not exist) -[Perform time-consuming processing in advance using Pickle](# Perform time-consuming processing in advance using pickle) -[Perform time-consuming processing in advance using Model](# Perform time-consuming processing in advance using model) -[Use login authentication function](#Use login authentication function) -[Get the data stored in Model for each logged-in user](Get the data stored in #model for each logged-in user) -[Extract object by OR condition](Extract object by #or condition) -[Get loop counter with Template](Get loop counter with #template) -[Specify list array number with Template](Specify list array number with #template) -[(Extra edition) Use Cloudinary as image storage](# Extra edition Use cloudinary as image storage)

Form validation

When you receive a value from the input screen of the Web and set it in Model, you can verify whether there is an invalid value. By using the Djnago standard is_valid function, for example, if an item other than a numerical value is entered in the IntegerField item, or if the required item is blank, an Error can be sent.

if form.is_valid():  #Form validation
    #processing
    # ...

Send Http404

If you want to branch the process by receiving an argument for each URL to access, it is better to set raise Http404 in else. You can avoid Server Error (500) when an argument is passed in an unexpected URL in this function by doing the following.

views.py


from django.http import Http404

def sample(request, mode):
    if mode == 'hoge':
        #Process 1
    elif mode == 'fuga':
        #Process 2
    else:
        raise Http404("No User matches the given query.")

Perform instance acquisition and send Http404 if object does not exist

You may want to use get_object_or_404 when issuing a query to get an instance from Model. In the example below, we are getting an object with a primary key of 1 from MyModel, but if that object does not exist, we will send an Http404. This should avoid inadvertently causing a Server Error (500).

views.py


from django.shortcuts import get_object_or_404

def my_view(request):
    my_object = get_object_or_404(MyModel, pk=1)

Pre-do time-consuming processing with Pickle

When you do a lot of processing in View, it may take a long time and increase the response time. In such cases, you may want to use pickle.dump and pickle.load. As a pre-process, process halfway, make the resulting Python object pickle, and load it for use in this process. Doing so will greatly improve response time.

python


#Pyhton object through such a function->Pickle
def pickle_dump(obj, path):
    with open(path, mode='wb') as f:
        pickle.dump(obj,f)

#When using from this process, pickle->Return to python object
def pickle_load(path):
   with open(path, mode='rb') as f:
       data = pickle.load(f)
       return data

After that, it is a good idea to call the preprocessing regularly with the job scheduler and automate it.

Perform time-consuming processing in advance using Model

If you're using Heroku to put your Djnago Project into production, trying the above methods may not work. It's due to the specification (https://devcenter.heroku.com/articles/active-storage-on-heroku) that Heroku's filesystem is temporary. Even if you pickle.dump the result of the process, the pickle will not be saved on your Djnago Project.

In such a case, you may want to store the Python object in Model.

To store a Python object in Model as it is, you need to prepare Custom Model Fields. However, if it is a list type Python object, you can use Django standard CharField by converting it to json format.

models.py


class Pickle(models.Model):
    sample = models.CharField(max_length=255, null=True)

    def set_sample(self, x):
        self.sample = json.dumps(x)

    def get_sample(self):
        return json.loads(self.sample)

Prepare the Model class method as described above and operate the Model through the setter or getter. You should be able to handle many cases by using json and CharField well like this. For example, pandas.DataFrame can also be stored in Model by type conversion with pandas.DataFrame-> numpy.ndarray-> list-> json.

Use login authentication function

You will often use the login authentication function when creating a web application.

Django provides login authentication as a standard feature. By using these, you can quickly implement login authentication. It is also explained in the Official Documents.

Implementing the authentication function is a three-step process.

  1. Create an app in Django Project with the following command to use the authentication function.
$ django-admin startapp accounts
  1. Add the app created in settings.py.
INSTALLED_APPS = [
    ...
    'accounts.apps.AccountsConfig', #add to
]
  1. The URL to be transitioned after successful login is also defined in settings.py.
#Redirect to top page after login
LOGIN_REDIRECT_URL = '/hoge/'

This completes the implementation of the login authentication function.

Then, by adding @ login_required to the View function, access can be restricted by login authentication.

@login_required
def sample(request):
    pass

By the way, the user registration function is not provided as a standard function of Djnago, but you can create it yourself. You can also customize the login screen and log-out screen.

For reference, the code for implementing the user registration function is shown below.

accounts/urls.py


urlpatterns = [
    path('signup/', views.SignUpView.as_view(), name='signup'),
]

accounts/views.py


from django.contrib.auth.forms import UserCreationForm
from django.urls import reverse_lazy
from django.views import generic


class SignUpView(generic.CreateView):
    form_class = UserCreationForm
    success_url = reverse_lazy('login')
    template_name = 'accounts/signup.html'

Get the data stored in Model for each logged-in user

If you implement login authentication, you will surely have a requirement to extract objects for each logged-in user from all the objects stored in Model. In such a case, you can extract only the logged-in user's object by setting the following conditions with the filter function.

views.py


from models import Content

@login_required
def sample(repuests):
    contents = Content.objects.all().filter(user_id=request.user.id)

Extract objects with OR conditions

When extracting an object from a Model with Django, the AND condition should be overlaid with the filter function, but the OR condition should use the Q library. For example, you can extract only objects with dates 2019-12-24, 2019-12-25, or 2019-12-26 by writing:

views.py


from django.db.models import Q
from models import Content

def sample(request):
    contents = Content.objects.filter(
                Q(date='2019-12-24') | Q(date='2019-12-25') | Q(date='2019-12-26')
                )

Get loop counter with Template

When turning the list passed from View with for in Template, You can get the loop counter in the for by implementing as follows.

{% for list in lists %}
    {{ forloop.counter }}
{% endfor %}

Furthermore, you can get various loop counters by replacing the counter part with counter0 (in order from 0) or revcounter (in reverse order).

Specify the array number of list in Template

For the list passed from View even in Template You can retrieve the element by specifying the array number as in Python.

{{ objects.0 }}

(Extra edition) Use Cloudinary as image storage

This isn't a tip, but I usually use Cloudinary as my image storage.

As mentioned in [Pre-do time-consuming processing using Model](# Pre-do time-consuming processing using model), you can't save files to Django Project running on Heroku. So if you want to upload images or manage the uploaded images with the Django application on Heroku, you need to have image storage.

You can use Cloudinary to work with image data in your Django application.

Cloudinary Official Documentation

There are three things you need to do to use Cloudinary:

--Model definition --settings.py settings --Adding Heroku Add-ons

models.py


from cloudinary.models import CloudinaryField

class Image(models.Model):
    picture = CloudinaryField('picture')

settings.py


# Add
CLOUDINARY_STORAGE = {
    'CLOUD_NAME': '*****',
    'API_KEY': '*****',
    'API_SECRET': '*****'
}

# ...

# Add
DEFAULT_FILE_STORAGE = 'cloudinary_storage.storage.MediaCloudinaryStorage'

If you set it as above, you can use it in the same way as ʻImageField`.

at the end

Thank you for reading to the end. How was that. If there are other ways like this, I would appreciate it if you could comment.

Have a good Django life!

Recommended Posts

Django's personal tips
Tensorflow personal tips
python tips
numpy tips
python tips
Jupyter Tips 5
Scapy Tips
Jupyter Tips 3
Personal tips about Python (strings, around logs)
Jupyter Tips 2
Django's ImageField
Python Tips
Python tips
Personal tips when doing various things with Python 3