Django community: RSS
This page, updated regularly, aggregates Community blog posts from the Django community.
-
Django to Ember #1
If you know Django and want to learn Ember (or vice-versa), this guide is for you. To get started, let's see what happens when a user opens the `/contact` page in both frameworks. -
Simple qgis plugin repo
At my company, we sometimes build QGIS plugins. You can install those by hand by unzipping a zipfile in the correct directory, but there's a nicer way. You can add custom plugin "registries" to QGIS and QGIS will then treat your plugins just like regular ones. Here's an example registry: https://plugins.lizard.net/ . Simple, right? Just a directory on our webserver. The URL you have to configure inside QGIS as registry is that of the plugins.xml file: https://plugins.lizard.net/plugins.xml . The plugins.xml has a specific format: <?xml version="1.0"?> <plugins> <pyqgis_plugin name="GGMN lizard integration" version="1.6"> <description>Download GGMN data from lizard, interpolate and add new points</description> <homepage>https://github.com/nens/ggmn-qgis</homepage> <qgis_minimum_version>2.8</qgis_minimum_version> <file_name>LizardDownloader.1.6.zip</file_name> <author_name>Reinout van Rees, Nelen &amp; Schuurmans</author_name> <download_url>https://plugins.lizard.net/LizardDownloader.1.6.zip</download_url> </pyqgis_plugin> .... more plugins ... </plugins> As you see, the format is reasonably simple. There's one directory on the webserver that I "scp" the zipfiles with the plugins to. I then run this script on the directory. That script extracts the (mandatory) metadata.txt from all zipfiles and creates a plugins.xml file out of it. A gotcha regarding the zipfiles: they should contain the version number, but, in contrast to python packages, the version should be prefixed by a dot instead of a dash. So no myplugin-1.0.zip but myplugin.1.0.zip. … -
How to Create a One Time Link
Django uses a very interesting approach to generate the Password reset tokens. I’m not really a security expert, neither I’m very familiar with cryptography algorithms, but it is very safe and reliable. Before I elaborate a little be more on the one-time-link generation, I wanted to discuss about the Django’s PasswordResetTokenGenerator implementation. Because what we will be doing is actually extending this particular class to fit our needs. Generally speaking, Django generate a token without persisting it in the database. Yet, it still have the capabilities of determining whether a given token is valid or not. Also the token is only valid for a defined number of days. The default value for the Password Reset Token is 7 days, and it can be changed in the settings.py by changing the value of PASSWORD_RESET_TIMEOUT_DAYS. The class have two public methods: make_token(user) check_token(user, token) The make_token method will generate a hash value with user related data that will change after the password reset. Meaning, after the user clicks on the link with the hash and proceed to the password reset, the link (or the hash) will no longer be valid: def _make_hash_value(self, user, timestamp): # Ensure results are consistent across DB backends … -
Django Tips #13 Using F() Expressions
In the Django QuerySet API, F() expressions are used to refer to model field values directly in the database. Let’s say you have a Product class with a price field, and you want to increase the price of all products in 20%. A possible solution would be: products = Product.objects.all() for product in products: product.price *= 1.2 product.save() Instead you could use an F() expression to update it in a single query: from django.db.models import F Product.objects.update(price=F('price') * 1.2) You can also do it for a single object: product = Product.objects.get(pk=5009) product.price = F('price') * 1.2 product.save() But take care with this kind of assignment. The F() object persist after saving the model. product.price # price = Decimal('10.00') product.price = F('price') + 1 product.save() # price = Decimal('11.00') product.name = 'What the F()' product.save() # price = Decimal('12.00') So, basically after updating a field like that, product.price will hold an instance of django.db.models.expressions.CombinedExpression, instead of the actual result. If you want to access the result immediately: product.price = F('price') + 1 product.save() print(product.price) # <CombinedExpression: F(price) + Value(1)> product.refresh_from_db() print(product.price) # Decimal('13.00') You can also use it to annotate data: from django.db.models import ExpressionWrapper, DecimalField Product.objects.all().annotate( value_in_stock=ExpressionWrapper( F('price') * F('stock'), … -
Dealing With QueryString Parameters
It is kinda tough to describe what the problem really is. But, do you know when you are creating an interface where you provide pagination, filters and ordering, and you are making it controlling it via URL Get parameters? For instance if you have different options for ordering, you might think of something like that: <div class="dropdown"> <button class="btn btn-default dropdown-toggle" type="button" data-toggle="dropdown"> Order by </button> <ul class="dropdown-menu"> <li><a href="?order=name">Name (a-z)</a></li> <li><a href="?order=-name">Name (z-a)</a></li> <li><a href="?order=price">Price</a></li> <li><a href="?order=date">Date</a></li> </ul> </div> Basically you would be sending the user to the very same page, but passing a GET parameter named order, where you could do something like that: def products_list(request): products = Product.objects.all() order = request.GET.get('order', 'name') # Set 'name' as a default value products = products.order_by(order) return render(request, 'products_list.html', { 'products': products }) PS: This is a minimalist example, if you pass an invalid parameter directly in the querystring you will make queryset break. I will avoid adding extra validations so we can focus on the objective of this article. So far so good. But the problem starts to appear when you add new control, also via GET parameter. Lets say a pagination: <ul class="pagination"> {% for i in page_obj.paginator.page_range %} … -
Better Python Object Serialization
Serialization is everywhere. Notably for me: JSON web APIs and structured logs. And yet, general approaches to serialize arbitrary objects to JSON are rather clunky. Fortunately there’s a gem in the Python standard library that makes it easy and elegant. -
Django Tips #12 Disabling Migrations to Speed Up Unit Tests
The model migrations are certainly a great feature of the Django framework. But, when it comes down to running tests, it really slows down the process. Especially if your migration history is big. This is a simple tip to speed up your tests. I like to create a separate settings file for this tweaks. tests_settings.py from settings import * # Custom settings goes here And then to run the tests: python manage.py test --settings=myproject.tests_settings --verbosity=1 Django >= 1.9 One option is using the MIGRATION_MODULES setting, which is intended to define a custom name for an app’s migration module. If you set None instead, Django will ignore the migration module. from settings import * MIGRATION_MODULES = { 'auth': None, 'contenttypes': None, 'default': None, 'sessions': None, 'core': None, 'profiles': None, 'snippets': None, 'scaffold_templates': None, } Django < 1.9 This is a possible solution if you are using a version prior to 1.9. Actually, I still prefer to use it nowadays. Because I don’t need to set each app. from settings import * class DisableMigrations(object): def __contains__(self, item): return True def __getitem__(self, item): return 'notmigrations' MIGRATION_MODULES = DisableMigrations() Older Django Versions (using South) Hold tight: SOUTH_TESTS_MIGRATE = False Damn! It could even live … -
Package of the Week: Pendulum
Pendulum is a Python library to make your life easier when it comes down to work with date/time. Installation pip install pendulum A few dependencies will be installed: pytz, tzlocal and python-dateutil. Just the python-dateutil itself is already great – but pendulum offers a few more tweaks. Usage import pendulum now = pendulum.now() # '2016-08-18 20:24:52' Let’s keep the now variable for the next examples. add now.add(days=1) # '2016-08-19 20:24:52' Accepts days, months, years, hours, minutes, seconds, microseconds, weeks. now.add(weeks=1, hours=2) # '2016-08-25 22:24:52' subtract now.subtract(weeks=1) # '2016-08-11 20:24:52' age birthday = pendulum.create(1988, 10, 22) birthday.age # 27 diff now = pendulum.now('Europe/Helsinki') future = now.add(hours=12) past = now.subtract(years=50, days=12) future.diff() # '<Period [11 hours 59 minutes 41 seconds]>' future.diff_for_humans() # '11 hours from now' past.diff_for_humans() # '50 years ago' delta delta = now - last_week delta.start # <Pendulum [2016-08-05T00:28:26.207225+03:00]> delta.end # <Pendulum [2016-08-12T00:28:26.207225+03:00]> delta.in_days() # 7 delta.in_hours() # 168 delta.in_weekdays() # 6 delta.in_words() # '1 week' interval it = pendulum.interval(days=15) it.weeks # 2 it.days # 15 it.in_hours() # 360 it.in_words() # '2 weeks 1 day' is_ now.is_birthday() now.is_future() now.is_past() now.is_monday() now.is_tuesday() now.is_wednesday() now.is_thursday() now.is_friday() now.is_saturday() now.is_sunday() now.is_today() now.is_yesterday() now.is_tomorrow() now.is_leap_year() now.is_long_year() now.is_same_day() now.is_weekday() now.is_weekend() now = pendulum.now() # 2016-08-18 20:24:52 … -
Exploring Django Utils #2
Last week I started a post series exploring the django.utils module. In this second part I will be focusing more on the html module. HTML Module: django.utils.html escape Returns the given text with ampersands, quotes and angle brackets encoded for use in HTML. from django.utils.html import escape escape("<strong style='font-size: 12px'>escaped html</strong>") '&lt;strong style=&#39;font-size: 12px&#39;&gt;escaped html&lt;/strong&gt;' It will cause already escaped strings to be escaped again: escaped_html = escape("<strong>escaped html</strong>") # '&lt;strong&gt;escaped html&lt;/strong&gt;' escape(escaped_html) # '&amp;lt;strong&amp;gt;escaped html&amp;lt;/strong&amp;gt;' If this is a concern, use conditional_escape() instead. conditional_escape escaped_html = conditional_escape("<strong>escaped html</strong>") # '&lt;strong&gt;escaped html&lt;/strong&gt;' conditional_escape(escaped_html) # '&lt;strong&gt;escaped html&lt;/strong&gt;' format_html This function is similar to str.format, but it will conditional escape all the arguments. Prefer to use it to build small HTML fragments instead of str.format or string interpolation, as it is safer. from django.utils.html import format_html format_html('<div class="alert {}">{}</>', 'warning', 'Watch out!') '<div class="alert warning">Watch out!</>' Safely format HTML fragments: format_html('<div class="alert {}">{}</>', '<script>alert(1);</script>', 'Watch out!') '<div class="alert &lt;script&gt;alert(1);&lt;/script&gt;">Watch out!</>' format_html_join A wrapper of format_html, for the common case of a group of arguments that need to be formatted using the same format string. format_html_join('\n', '<p>{}</p>', ['a', 'b', 'c']) <p>a</p>\n<p>b</p>\n<p>c</p> Another example: data = [ ['success', 'Success message'], ['warning', 'Watch out!'], ['danger', … -
Django Tips #11 Custom Manager With Chainable QuerySets
In a Django model, the Manager is the interface that interacts with the database. By default the manager is available through the Model.objects property. The default manager every Django model gets out of the box is the django.db.models.Manager. It is very straightforward to extend it and change the default manager. from django.db import models class DocumentManager(models.Manager): def pdfs(self): return self.filter(file_type='pdf') def smaller_than(self, size): return self.filter(size__lt=size) class Document(models.Model): name = models.CharField(max_length=30) size = models.PositiveIntegerField(default=0) file_type = models.CharField(max_length=10, blank=True) objects = DocumentManager() With that you will be able to retrieve all pdf files like this: Document.objects.pdfs() The thing is, this method is not chainable. I mean, you can still use order_by or filter in the result: Document.objects.pdfs().order_by('name') But if you try to chain the methods it will break: Document.objects.pdfs().smaller_than(1000) AttributeError: 'QuerySet' object has no attribute 'smaller_than' To make it work you must create custom QuerySet methods: class DocumentQuerySet(models.QuerySet): def pdfs(self): return self.filter(file_type='pdf') def smaller_than(self, size): return self.filter(size__lt=size) class DocumentManager(models.Manager): def get_queryset(self): return DocumentQuerySet(self.model, using=self._db) # Important! def pdfs(self): return self.get_queryset().pdfs() def smaller_than(self, size): return self.get_queryset().smaller_than(size) class Document(models.Model): name = models.CharField(max_length=30) size = models.PositiveIntegerField(default=0) file_type = models.CharField(max_length=10, blank=True) objects = DocumentManager() Now you can use it just like any other QuerySet method: Document.objects.pdfs().smaller_than(1000).exclude(name='Article').order_by('name') … -
How to Create a Password Confirmation View
It is a very common practice nowadays to keep alive signed in user sessions for a very long time. But some web pages usually deal with sensitive information (such as billing information or change email forms) and it is a good idea to ask the user to confirm his/her credentials. To achieve this task, we will be using the built-in check_password and the user’s last_login field. To illustrate a little bit more what we want to achieve, take the picture below as an example: No redirects, we want to keep the current URL. Make it lasts for a few hours. Building the Form I’m using a User ModelForm to hold an instance of the logged in user. Basically I’m overriding the clean() method so to validate the informed password using the built-in function check_password, where you can test a plain-text password against its hash. And in the same method, I’m updating the last_login with the current time. This field will be used to control when we should ask for the user’s password again. from django import forms from django.contrib.auth.models import User from django.contrib.auth.hashers import check_password from django.utils import timezone class ConfirmPasswordForm(forms.ModelForm): confirm_password = forms.CharField(widget=forms.PasswordInput()) class Meta: model = User fields … -
Django Tips #10 AuthenticationForm Custom Login Policy
Since I started working with Django, I never had to spend time implementing authentication related stuff. The built-in authentication system is great and it’s very easy to plug-in and get started. Now, even if need to customize, Django makes it easy. That’s what this tip is about. For the built-in login view, Django makes use of django.contrib.auth.forms.AuthenticationForm form to handle the authentication process. Basically it checks username, password and the is_active flag. Django makes it easy to add custom verifications, as the AuthenticationForm has a method named confirm_login_allowed(user). For example, if you are handling double opt-in email confirmation and don’t wanna let users without the email confirmed to log in to the application you can do something like that: forms.py: from django import forms from django.contrib.auth.forms import AuthenticationForm class CustomAuthenticationForm(AuthenticationForm): def confirm_login_allowed(self, user): if not user.is_active or not user.is_validated: raise forms.ValidationError('There was a problem with your login.', code='invalid_login') urls.py from django.conf.urls import url from django.contrib.auth import views as auth_views from .forms import CustomAuthenticationForm urlpatterns = [ url(r'^login/$', auth_views.login, {'template_name': 'core/login.html', 'authentication_form': CustomAuthenticationForm}, name='login'), url(r'^logout/$', auth_views.logout, name='logout'), ... ] Basically it is just a matter of overriding the confirm_login_allowed method and substituting the authentication_form parameter with the new form in the … -
django-html-validator - now locally, fast!
A couple of years ago I released a project called django-html-validator (GitHub link) and it's basically a Django library that takes the HTML generated inside Django and sends it in for HTML validation. The first option is to send the HTML payload, over HTTPS, to https://validator.nu/. Not only is this slow but it also means sending potentially revealing HTML. Ideally you don't have any passwords in your HTML and if you're doing HTML validation you're probably testing against some test data. But... it sucked. The other alternative was to download a vnu.jar file from the github.com/validator/validator project and executing it in a subprocess with java -jar vnu.jar /tmp/file.html. Problem with this is that it's really slow because java programs take such a long time to boot up. But then, at the beginning of the year some contributors breathed fresh life into the project. Python 3 support and best of all; the ability to start the vnu.jar as a local server on http://localhost:8888 and HTTP post HTML over to that. Now you don't have to pay the high cost of booting up a java program and you don't have to rely on a remote HTTP call. Now it becomes possible to … -
Package of the Week: django-import-export
As the name suggests, this is a library to handle importing and exporting data. The django-import-export library supports multiple formats, including xls, csv, json, yaml, and all other formats supported by tablib. It also have a Django admin integration, which is really convenient to use. Installation Pip is the way to go: pip install django-import-export Update your settings.py: INSTALLED_APPS = ( ... 'import_export', ) There is also an optional configuration that I usually add: IMPORT_EXPORT_USE_TRANSACTIONS = True The default value is False. It determines if the library will use database transactions on data import, just to be on the safe side. Resources The django-import-export library work with the concept of Resource, which is class definition very similar to how Django handle model forms and admin classes. In the documentation the authors suggest to put the code related to the resources inside the admin.py file. But if the implementation is not related to the Django admin, I usually prefer to create a new module named resources.py inside the app folder. models.py from django.db import models class Person(models.Model): name = models.CharField(max_length=30) email = models.EmailField(blank=True) birth_date = models.DateField() location = models.CharField(max_length=100, blank=True) resources.py from import_export import resources from .models import Person class PersonResource(resources.ModelResource): … -
Exploring Django Utils #1
Exploring the Django source code I ended up discovering some really nice utility functions that I wasn’t aware of. I thought about sharing with you guys in a form of reference-like article. There are great stuff there, so I decided to break this post into a few parts. Crypto Module: django.utils.crypto get_random_string Calling it without any parameters defaults the length to 12. from django.utils.crypto import get_random_string get_random_string() '5QxAxqyhsyJM' Your may pass the number of characteres you want: get_random_string(50) 'lrWYnyxhnXpwmjHDzmdgTFaIi1j73cKD5fPDOPwuVBmmKxITYF' And also the collection of characteres the random string will have: get_random_string(12, '0123456789') '805379737758' Date Module: django.utils.dates Basically it is a collection of commonly-used date structures. WEEKDAYS from django.utils.dates import WEEKDAYS WEEKDAYS = { 0: _('Monday'), 1: _('Tuesday'), 2: _('Wednesday'), 3: _('Thursday'), 4: _('Friday'), 5: _('Saturday'), 6: _('Sunday') } WEEKDAYS_ABBR from django.utils.dates import WEEKDAYS_ABBR WEEKDAYS_ABBR = { 0: _('Mon'), 1: _('Tue'), 2: _('Wed'), 3: _('Thu'), 4: _('Fri'), 5: _('Sat'), 6: _('Sun') } MONTHS from django.utils.dates import MONTHS MONTHS = { 1: _('January'), 2: _('February'), 3: _('March'), 4: _('April'), 5: _('May'), 6: _('June'), 7: _('July'), 8: _('August'), 9: _('September'), 10: _('October'), 11: _('November'), 12: _('December') } DateFormat Module: django.utils.dateformat The implementation of PHP date() style date formatting, which is used in the … -
Dritte Hamburger Python Unconference
Vom 09. bis 11. September 2016 findet die 3. Python Unconference Hamburg an der Technischen Universität Hamburg-Harburg (TUHH) statt. Erwartet werden über 100 Python-User bzw. Developer aus Hamburg und dem Rest der Welt. Von "Greenhorns" bis zu "proven Experts" aus den Bereichen Mathematik, Data Science, System-Administration und DevOps bis hin zu Web-Development und Python-Core-Entwicklung werden alle nur erdenklichen Facetten der Python-Welt vertreten sein. Wie in den letzten Jahren findet die Unconference am Samstag und Sonntag im Barcamp-Stil statt, mit Vorträgen und Diskussionen aus allen Bereichen der Python Welt. Am Freitag gibt es wieder Raum für Sprints, Tutorials und Workshops. Das aktuelle Freitags-Programm findet Ihr hier . Tickets gibt es hier. Mehr Informationen gibt es unter www.pyunconf.de. -
How to Deploy Django Applications on Heroku
Heroku is a cloud application platform, basically a Platform-as-a-Service (PaaS) platform. They support several programming languages, including Python. It is very easy to deploy Django applications on Heroku. They also offer a free plan, which is quite limited, but it is great to get started and to host demos of Django applications. Install Heroku Toolbelt Actually, first thing – sign up Heroku. Then install the Heroku Toolbelt. It is a command line tool to manage your Heroku apps. After installing the Heroku Toolbelt, open a terminal and login to your account: $ heroku login Enter your Heroku credentials. Email: vitor@simpleisbetterthancomplex.com Password (typing will be hidden): Authentication successful. Preparing the Application In this tutorial I will deploy an existing project, Bootcamp. It’s open-souce Django project I’ve developed a couple of years ago, and it’s also available on GitHub, so you actually can clone the repository and try it by yourself. Basically things will work better if you are already using Git. The Heroku deployment process is done through Git. Your application will be stored in a remote Git repository in the Heroku Cloud. Anyway, here is the list of things you will probably need to add to your project: Add a … -
How to Export to PDF
There are a few ways to export data to a PDF file using Django. All of them requires a third-party library so to generate the file itself. First I will show how to return a PDF response, which can also be used if you are just serving an existing PDF file. Then I will show how to use ReportLab and WeasyPrint. Writing a PDF to Response In the example below I’m using the Django’s FileSystemStorage class. It will also work if you simply use open() instead. The FileSystemStorage sets the base_url to the project’s MEDIA_ROOT. from django.core.files.storage import FileSystemStorage from django.http import HttpResponse, HttpResponseNotFound def pdf_view(request): fs = FileSystemStorage() filename = 'mypdf.pdf' if fs.exists(filename): with fs.open(filename) as pdf: response = HttpResponse(pdf, content_type='application/pdf') response['Content-Disposition'] = 'attachment; filename="mypdf.pdf"' return response else: return HttpResponseNotFound('The requested pdf was not found in our server.') This way the user will be prompted with the browser’s open/save file. If you want to display the PDF in the browser you can change the Content-Disposition to: response['Content-Disposition'] = 'inline; filename="mypdf.pdf"' Using ReportLab Installation pip install reportlab It relies on Pillow, which is a third-party Python Image Library. Sometimes it is a pain to get it installed. If you are … -
Setting up a Honey Pot with django-admin-honeypot
Security is something we often ignore until it is too late. However, there are some things you can do right now that are easy to increase your security. Using django-admin-honeypot is one of those things you can do. It is super easy and provides you with the means of tracking who is trying to access your site.Watch Now... -
Package of the Week: Flake8
Flake8 is a Python library that wraps PyFlakes, pycodestyle and Ned Batchelder’s McCabe script. It is a great toolkit for checking your code base against coding style (PEP8), programming errors (like “library imported but unused” and “Undefined name”) and to check cyclomatic complexity. If you are not familiar with the term cyclomatic complexity, it is a software metric created by Thomas J. McCabe to measure the number of independent paths through the source code. Generally speaking, the higher number of ifs inside a function, the higher number of paths it will have, thus a higher cyclomatic complexity. Of course there are other control flow operations that impact the calculus of the cyclomatic complexity. It is also referred as McCabe complexity. Speaking about coding style, I also like to follow the Django Coding Style on the Django projects I develop. This style standard is only enforced when writing code for inclusion in Django. Installation Easiest way to get started is installing it using pip: pip install flake8 Usage Inside the Django project dir, run the command: flake8 Or you can pass the path to a file/dir: flake8 bootcamp/feeds/ The output will be something like that: ./bootcamp/settings.py:96:80: E501 line too long (91 … -
Django Tips #9 How to Create a Change Password View
This is a very quick tip about how to create a change password view using the built-in PasswordChangeForm. For that matter, using a function-based view is easier, because the PasswordChangeForm is slightly different. It does not inherit from ModelForm and it takes an user argument in its constructor. The example below is a functional code to change the password for the authenticated user. views.py from django.contrib import messages from django.contrib.auth import update_session_auth_hash from django.contrib.auth.forms import PasswordChangeForm from django.shortcuts import render, redirect def change_password(request): if request.method == 'POST': form = PasswordChangeForm(request.user, request.POST) if form.is_valid(): user = form.save() update_session_auth_hash(request, user) # Important! messages.success(request, 'Your password was successfully updated!') return redirect('accounts:change_password') else: messages.error(request, 'Please correct the error below.') else: form = PasswordChangeForm(request.user) return render(request, 'accounts/change_password.html', { 'form': form }) The messages.success() and messages.error() are optional, but it is a good idea to keep your user aware about what is going on in the application. Now an important bit is to call update_session_auth_hash() after you save the form. Otherwise the user’s auth session will be invalidated and she/he will have to log in again. urls.py from django.conf.urls import url from myproject.accounts import views urlpatterns = [ url(r'^password/$', views.change_password, name='change_password'), ] change_password.html <form method="post"> {% … -
Serving a Customized Site with Moya
This SO post prompted me to think about how you would go about customizing a entire Django site (not just an app). Particularly if it is a third party project, still in development. Forking the site repository is a solution, but the more customizations you make, the more awkward it becomes to merge upstream fixes and features. The problem is compounded if you have multiple deploys, with custom templates, assets, and settings. I wanted to do a quick write-up of how this would be done in Moya, where customization is more of a first-class concept. I'll briefly go over how you would serve a Moya site with a custom template, without modifying any of the original files. The project I'll be customizing is Moya Techblog which power this blog. Install Moya If you want to follow along, then first install Moya + dependencies and Techblog with the following: pip install moya requests_oauthlib -U git clone https://github.com/moyaproject/moya-techblog.git Make a custom project Next we want to create a new directory along side the Techblog checkout, which will contain two files; moya and settings.ini. The former is an empty file that tells Moya this is a project directory and the latter contains the … -
How to Paginate with Django
As part of the Django’s common Web application tools, Django offers a few classes to manage paginated data. You can pass either a list/tuple of objects or an QuerySet. In this tutorial I will show how to paginate data using function based views and how to paginate using class-based views (ListView). The Paginator The paginator classes lives in django.core.paginator. We will be working mostly with the Paginator and Page classes. Consider the auth.User table has 53 user instances. from django.contrib.auth.models import User from django.core.paginator import Paginator user_list = User.objects.all() paginator = Paginator(user_list, 10) In the example above I’m telling Paginator to paginate the user_list QuerySet in pages of 10. This will create a 6 pages result. The first 5 pages with 10 users each and the last page with 3 users. Debugging the Paginator Object Input Output Type paginator.count 53 <type 'int'> paginator.num_pages 6 <type 'int'> paginator.page_range xrange(1, 7) <type 'xrange'> paginator.page(2) <Page 2 of 6> <class 'django.core.paginator.Page'> The Paginator.page() method will return a given page of the paginated results, which is an instance of Page. This is what we will return to the template. users = paginator.page(2) Debugging the Page Object Input Output Type users <Page 2 of 6> … -
How to Split Views Into Multiple Files
It is a good idea to keep your apps views module small. A common mistake is do much work inside the views functions. For the most part you can create separate modules to do the processing work outside the views and just import it and use the functions inside the views. Another common mistake is a single app implementing many different requirements or serving for many purposes. Sometimes you can split the work into different apps. When it makes sense of course. But sometimes, the views will get big anyway. In this case, you might want to split the views into different files. Sample Scenario Before I show you how, please consider the scenario below: App dir |∙∙core/ |∙∙__init__.py |∙∙admin.py |∙∙migrations/ |∙∙models.py |∙∙tests.py |∙∙urls.py |∙∙views.py views.py from django.shortcuts import render def view_a(request): return render(request, 'view_a.html') def view_b(request): return render(request, 'view_b.html') def view_c(request): return render(request, 'view_c.html') def view_d(request): return render(request, 'view_d.html') urls.py from django.conf.urls import url import .views urlpatterns = [ url(r'^aaa$', views.view_a, name='view_a'), url(r'^bbb$', views.view_b, name='view_b'), url(r'^ccc$', views.view_c, name='view_c'), url(r'^ddd$', views.view_d, name='view_d'), ] Splitting the Views This strategy is good if you are refactoring your code base. This way you won’t need to change the way you handle your urls.py. … -
Please Fix Your Decorators
If your Python decorator unintentionally changes the signatures of my callables or doesn’t work with class methods, it’s broken and should be fixed. Sadly most decorators are broken because the web is full of bad advice.