ImportError: cannot import name 'python_2_unicode_compatible' from 'django.utils.encoding'

Hello guys,

I’m trying to build the example app from elasticsearch dsl drf tutorial ( [https://django-elasticsearch-dsl-drf.readthedocs.io/en/0.20.8/quick_start.html#example-app] ),

but I’m facing an error when I migrate my models,

from django.utils.encoding import python_2_unicode_compatible
ImportError: cannot import name 'python_2_unicode_compatible' from 'django.utils.encoding'

Here are the models:

admin.py

from __future__ import unicode_literals
from django.utils.encoding import python_2_unicode_compatible

from django.contrib import admin
from .models import *

@admin.register(Book)
class BookAdmin(admin.ModelAdmin):
"""Book admin."""

list_display = ('title', 'isbn', 'price', 'publication_date')
search_fields = ('title',)
filter_horizontal = ('authors', 'tags',)


@admin.register(Author)
class AuthorAdmin(admin.ModelAdmin):
"""Author admin."""

list_display = ('name', 'email',)
search_fields = ('name',)

@admin.register(Publisher)
class PublisherAdmin(admin.ModelAdmin):
"""Publisher admin."""

list_display = ('name',)
search_fields = ('name',)


@admin.register(Tag)
class TagAdmin(admin.ModelAdmin):
"""Tag admin."""

list_display = ('title',)
search_fields = ('title',)

book.py

from __future__ import unicode_literals
from django.utils.encoding import python_2_unicode_compatible

import json

from django.conf import settings
from django.db import models

from django.utils.translation import ugettext, ugettext_lazy as _



# States indicate the publishing status of the book. Publishing might
# be in-progress, not yet published, published, rejected, etc.
BOOK_PUBLISHING_STATUS_PUBLISHED = 'published'
BOOK_PUBLISHING_STATUS_NOT_PUBLISHED = 'not_published'
BOOK_PUBLISHING_STATUS_IN_PROGRESS = 'in_progress'
BOOK_PUBLISHING_STATUS_CANCELLED = 'cancelled'
BOOK_PUBLISHING_STATUS_REJECTED = 'rejected'
BOOK_PUBLISHING_STATUS_CHOICES = (
(BOOK_PUBLISHING_STATUS_PUBLISHED, "Published"),
(BOOK_PUBLISHING_STATUS_NOT_PUBLISHED, "Not published"),
(BOOK_PUBLISHING_STATUS_IN_PROGRESS, "In progress"),
(BOOK_PUBLISHING_STATUS_CANCELLED, "Cancelled"),
(BOOK_PUBLISHING_STATUS_REJECTED, "Rejected"),
)
BOOK_PUBLISHING_STATUS_DEFAULT = BOOK_PUBLISHING_STATUS_PUBLISHED

@python_2_unicode_compatible
class Publisher(models.Model):
"""Publisher."""

name = models.CharField(max_length=30)
address = models.CharField(max_length=50)
city = models.CharField(max_length=60)
state_province = models.CharField(max_length=30)
country = models.CharField(max_length=50)
website = models.URLField()
latitude = models.DecimalField(null=True,
                           blank=True,
                           decimal_places=15,
                           max_digits=19,
                           default=0)
longitude = models.DecimalField(null=True,
                                blank=True,
                                decimal_places=15,
                                max_digits=19,
                                default=0)

class Meta(object):
    """Meta options."""

    ordering = ["id"]

def __str__(self):
    return self.name

@property
def location_field_indexing(self):
    """Location for indexing.

    Used in Elasticsearch indexing/tests of `geo_distance` native filter.
    """
    return {
        'lat': self.latitude,
        'lon': self.longitude,
    }

@python_2_unicode_compatible
class Book(models.Model):

title = models.CharField(max_length=100)
description = models.TextField(null=True, blank=True)
summary = models.TextField(null=True, blank=True)
authors = models.ManyToManyField('books.Author', related_name='books')
publisher = models.ForeignKey(Publisher, related_name='books')
publication_date = models.DateField()
state = models.CharField(max_length=100,
                         choices=BOOK_PUBLISHING_STATUS_CHOICES,
                         default=BOOK_PUBLISHING_STATUS_DEFAULT)
isbn = models.CharField(max_length=100, unique=True)
price = models.DecimalField(max_digits=10, decimal_places=2)
pages = models.PositiveIntegerField(default=200)
stock_count = models.PositiveIntegerField(default=30)
tags = models.ManyToManyField('books.Tag',
                              related_name='books',
                              blank=True)

class Meta(object):
    """Meta options."""

    ordering = ["isbn"]

def __str__(self):
    return self.title

# The only publisher information we're going to need in our document
# is the publisher name. Since publisher isn't a required field,
# we define a properly on a model level to avoid indexing errors on
# non-existing relation.
@property
def publisher_indexing(self):
    """Publisher for indexing.

    Used in Elasticsearch indexing.
    """
    if self.publisher is not None:
        return self.publisher.name

# As of tags, again, we only need a flat list of tag names, on which
# we can filter. Therefore, we define a properly on a model level,
# which will return a JSON dumped list of tags relevant to the
# current book model object.
@property
def tags_indexing(self):
    """Tags for indexing.

    Used in Elasticsearch indexing.
    """
    return [tag.title for tag in self.tags.all()]

Thank you for your help :wink:

This was removed in Django 3.0: https://docs.djangoproject.com/en/3.0/releases/3.0/#removed-private-python-2-compatibility-apis

To complete the tutorial, try installing an older version of Django. Or you can probably proceed without it.

Report the problem with the tutorial to the project at https://github.com/barseghyanartur/django-elasticsearch-dsl-drf/issues - and perhaps even try fix it!

Thank you for your fast reply.

Yes, I’ll try to build without it, thank you :slight_smile:

Have a nice day!

Hi I Re-organized my code but still having errors at registering my models:

admin.site.register(Book, BookAdmin)
NameError: name 'Book' is not defined

Admin.py

from django.contrib import admin
from .models import *

class BookAdmin(admin.ModelAdmin):
    """Book admin."""

    list_display = ('title', 'isbn', 'price', 'publication_date')
    search_fields = ('title',)
    filter_horizontal = ('authors', 'tags',)

admin.site.register(Book, BookAdmin)

class AuthorAdmin(admin.ModelAdmin):
    """Author admin."""

    list_display = ('name', 'email',)
    search_fields = ('name',)
admin.site.register(Author, AuthorAdmin)


class PublisherAdmin(admin.ModelAdmin):
    """Publisher admin."""

    list_display = ('name',)
    search_fields = ('name',)
admin.site.register(Publisher, PublisherAdmin)


class TagAdmin(admin.ModelAdmin):
"""Tag admin."""

    list_display = ('title',)
    search_fields = ('title',)
admin.site.register(Tag, TagAdmin)

Book.py

import json

from django.conf import settings
from django.db import models

from django.utils.translation import ugettext, ugettext_lazy as _



# States indicate the publishing status of the book. Publishing might
# be in-progress, not yet published, published, rejected, etc.
BOOK_PUBLISHING_STATUS_PUBLISHED = 'published'
BOOK_PUBLISHING_STATUS_NOT_PUBLISHED = 'not_published'
BOOK_PUBLISHING_STATUS_IN_PROGRESS = 'in_progress'
BOOK_PUBLISHING_STATUS_CANCELLED = 'cancelled'
BOOK_PUBLISHING_STATUS_REJECTED = 'rejected'
BOOK_PUBLISHING_STATUS_CHOICES = (
(BOOK_PUBLISHING_STATUS_PUBLISHED, "Published"),
(BOOK_PUBLISHING_STATUS_NOT_PUBLISHED, "Not published"),
(BOOK_PUBLISHING_STATUS_IN_PROGRESS, "In progress"),
(BOOK_PUBLISHING_STATUS_CANCELLED, "Cancelled"),
(BOOK_PUBLISHING_STATUS_REJECTED, "Rejected"),
)
BOOK_PUBLISHING_STATUS_DEFAULT = BOOK_PUBLISHING_STATUS_PUBLISHED


class Publisher(models.Model):
"""Publisher."""

name = models.CharField(max_length=30)
address = models.CharField(max_length=50)
city = models.CharField(max_length=60)
state_province = models.CharField(max_length=30)
country = models.CharField(max_length=50)
website = models.URLField()
latitude = models.DecimalField(null=True,
                           blank=True,
                           decimal_places=15,
                           max_digits=19,
                           default=0)
longitude = models.DecimalField(null=True,
                                blank=True,
                                decimal_places=15,
                                max_digits=19,
                                default=0)

class Meta(object):
    """Meta options."""

    ordering = ["id"]

def __str__(self):
    return self.name


def location_field_indexing(self):
    """Location for indexing.

    Used in Elasticsearch indexing/tests of `geo_distance` native filter.
    """
    return {
        'lat': self.latitude,
        'lon': self.longitude,
    }


class Book(models.Model):

    title = models.CharField(max_length=100)
    description = models.TextField(null=True, blank=True)
    summary = models.TextField(null=True, blank=True)
    authors = models.ManyToManyField('books.Author', related_name='books')
    publisher = models.ForeignKey(Publisher, related_name='books')
    publication_date = models.DateField()
    state = models.CharField(max_length=100,
                             choices=BOOK_PUBLISHING_STATUS_CHOICES,
                             default=BOOK_PUBLISHING_STATUS_DEFAULT)
    isbn = models.CharField(max_length=100, unique=True)
    price = models.DecimalField(max_digits=10, decimal_places=2)
    pages = models.PositiveIntegerField(default=200)
    stock_count = models.PositiveIntegerField(default=30)
    tags = models.ManyToManyField('books.Tag',
                                  related_name='books',
                                  blank=True)

class Meta(object):
    """Meta options."""

    ordering = ["isbn"]

def __str__(self):
    return self.title

# The only publisher information we're going to need in our document
# is the publisher name. Since publisher isn't a required field,
# we define a properly on a model level to avoid indexing errors on
# non-existing relation.

def publisher_indexing(self):
    """Publisher for indexing.

    Used in Elasticsearch indexing.
    """
    if self.publisher is not None:
        return self.publisher.name

# As of tags, again, we only need a flat list of tag names, on which
# we can filter. Therefore, we define a properly on a model level,
# which will return a JSON dumped list of tags relevant to the
# current book model object.

def tags_indexing(self):
    """Tags for indexing.

    Used in Elasticsearch indexing.
    """
    return [tag.title for tag in self.tags.all()]

Thank you

It looks like it can’t find your Book model because you put the model in Book.py instead of models.py. Your admin file is importing everything in the models module via from .models import *, but your Book model isn’t there. Thus, Python can’t find Book because you’d need to import it from that other module.